Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions Documentation/devicetree/bindings/firmware/linaro,optee-rpmi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/firmware/linaro,optee-rpmi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: OP-TEE accessed through the RISC-V RPMI TEE service group

maintainers:
- Marouene Boubakri <marouene.boubakri@oss.nxp.com>

description: |
OP-TEE is a piece of software using hardware features to provide a Trusted
Execution Environment. On RISC-V, OP-TEE runs as a supervisor domain
isolated from the Rich Execution Environment (REE) by the M-mode firmware.

The REE reaches OP-TEE through the TEE service group of the RISC-V Platform
Management Interface (RPMI) [1], carried on a channel of the SBI Message
Proxy (MPXY) extension [2]. Each call into OP-TEE is a TEE_CALL service
request whose service data carries the register arguments of the OP-TEE
SMC ABI (drivers/tee/optee/optee_smc.h), as described in
drivers/tee/optee/optee_rpmi.h.

The RPMI TEE framework (the M-mode firmware) assigns an identifier to each
endpoint. The identifiers of the REE and of OP-TEE are required to
address TEE_CALL requests and are described here.

The compatible string uses the same "linaro" vendor prefix as
"linaro,optee-tz", which identifies the OP-TEE reference implementation.

[1] RISC-V Platform Management Interface (RPMI) v2.0 (or higher)
https://github.com/riscv-non-isa/riscv-rpmi/releases

[2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher)
https://github.com/riscv-non-isa/riscv-sbi-doc/releases

properties:
$nodename:
const: optee

compatible:
const: linaro,optee-rpmi

mboxes:
maxItems: 1
description:
SBI MPXY channel implementing the RPMI TEE service group.

riscv,rpmi-tee-sender-id:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Endpoint identifier of the REE, used as SENDER_ID of the TEE_CALL
requests.

riscv,rpmi-tee-target-id:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Endpoint identifier of OP-TEE, used as TARGET_ID of the TEE_CALL
requests.

required:
- compatible
- mboxes
- riscv,rpmi-tee-sender-id
- riscv,rpmi-tee-target-id

additionalProperties: false

examples:
- |
firmware {
optee {
compatible = "linaro,optee-rpmi";
mboxes = <&mpxy_mbox 0x10 0x0>;
riscv,rpmi-tee-sender-id = <0>;
riscv,rpmi-tee-target-id = <1>;
};
};
...
18 changes: 16 additions & 2 deletions Documentation/tee/op-tee.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@
OP-TEE (Open Portable Trusted Execution Environment)
====================================================

The OP-TEE driver handles OP-TEE [1] based TEEs. Currently it is only the ARM
TrustZone based OP-TEE solution that is supported.
The OP-TEE driver handles OP-TEE [1] based TEEs. The ARM TrustZone based
OP-TEE solution and OP-TEE running as an isolated supervisor domain on
RISC-V are supported.

Lowest level of communication with OP-TEE builds on ARM SMC Calling
Convention (SMCCC) [2], which is the foundation for OP-TEE's SMC interface
[3] used internally by the driver. Stacked on top of that is OP-TEE Message
Protocol [4].

On RISC-V the SMC interface is unchanged but its register arguments and
return values are carried by the TEE_CALL service of the TEE service group
of the RISC-V Platform Management Interface (RPMI) [7], sent to the M-mode
firmware on an SBI Message Proxy (MPXY) channel [8]. The M-mode firmware
switches the calling hart to the OP-TEE domain until OP-TEE responds, so a
call behaves like an SMC: it runs on the calling hart and returns when
OP-TEE completes, requests an RPC or yields on a foreign interrupt. The
message layout is described in drivers/tee/optee/optee_rpmi.h.

OP-TEE SMC interface provides the basic functions required by SMCCC and some
additional functions specific for OP-TEE. The most interesting functions are:

Expand Down Expand Up @@ -164,3 +174,7 @@ References
"TEE Client API Specification v1.0" and click download.

[6] https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html

[7] https://github.com/riscv-non-isa/riscv-rpmi/releases

[8] https://github.com/riscv-non-isa/riscv-sbi-doc/releases
2 changes: 2 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -20420,6 +20420,7 @@ M: Jens Wiklander <jenswi@kernel.org>
L: op-tee@lists.trustedfirmware.org (moderated for non-subscribers)
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-optee-devices
F: Documentation/devicetree/bindings/firmware/linaro,optee-rpmi.yaml
F: drivers/tee/optee/

OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
Expand Down Expand Up @@ -23586,6 +23587,7 @@ F: drivers/clk/clk-rpmi.c
F: drivers/irqchip/irq-riscv-rpmi-sysmsi.c
F: drivers/mailbox/riscv-sbi-mpxy-mbox.c
F: include/linux/mailbox/riscv-rpmi-message.h
F: include/linux/mailbox/riscv-sbi-mpxy-mbox.h

RISC-V SPACEMIT SoC Support
M: Yixun Lan <dlan@kernel.org>
Expand Down
60 changes: 60 additions & 0 deletions drivers/mailbox/riscv-sbi-mpxy-mbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/irqchip/riscv-imsic.h>
#include <linux/mailbox_controller.h>
#include <linux/mailbox/riscv-rpmi-message.h>
#include <linux/mailbox/riscv-sbi-mpxy-mbox.h>
#include <linux/minmax.h>
#include <linux/mm.h>
#include <linux/module.h>
Expand Down Expand Up @@ -719,6 +720,65 @@ static const struct mbox_chan_ops mpxy_mbox_ops = {
.shutdown = mpxy_mbox_shutdown,
};

/**
* riscv_sbi_mpxy_mbox_call() - Send an RPMI message directly on an MPXY channel
* @chan: SBI MPXY mailbox channel owned by the caller
* @msg: RPMI message of type RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE or
* RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE
*
* An SBI MPXY message send is not queued anywhere: it is an ecall executed
* on the calling hart, using the calling hart's shared memory, which only
* returns once the SBI implementation has processed the message. For some
* message protocols that processing is unbounded because it runs on the
* calling hart itself, for example when the SBI implementation forwards
* the message to another supervisor domain and switches the hart to it
* until it responds (the RPMI TEE service group's TEE_CALL does this).
*
* Such messages must not go through mbox_send_message(): the mailbox core
* invokes the controller send_data() callback with the channel spinlock
* held and interrupts disabled, which would serialize all harts on a single
* lock and keep interrupts disabled on the calling hart for the whole
* duration of the call.
*
* This helper bypasses the mailbox core queue and channel lock and performs
* the transfer directly in the calling context. Only local interrupts are
* disabled around the ecall, because the per-hart shared memory can be used
* from hard interrupt context through mbox_send_message() by other clients.
* Calls from different harts run concurrently since each hart has its own
* shared memory.
*
* The caller must own @chan through mbox_request_channel() (or a variant of
* it) so that no other client can use the channel, and must not use
* mbox_send_message() on it concurrently.
*
* Return: 0 on success or a negative error code.
*/
int riscv_sbi_mpxy_mbox_call(struct mbox_chan *chan,
struct rpmi_mbox_message *msg)
{
struct mpxy_mbox_channel *mchan;
unsigned long flags;

if (!chan || !chan->cl || !chan->mbox || !msg)
return -EINVAL;
if (chan->mbox->ops != &mpxy_mbox_ops)
return -EINVAL;
if (msg->type != RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE &&
msg->type != RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE)
return -EINVAL;

mchan = chan->con_priv;
if (mchan->attrs.msg_proto_id != SBI_MPXY_MSGPROTO_RPMI_ID)
return -EOPNOTSUPP;

local_irq_save(flags);
mpxy_mbox_send_rpmi_data(mchan, msg);
local_irq_restore(flags);

return msg->error;
}
EXPORT_SYMBOL_GPL(riscv_sbi_mpxy_mbox_call);

/* ====== MPXY platform driver ===== */

static void mpxy_mbox_msi_write(struct msi_desc *desc, struct msi_msg *msg)
Expand Down
2 changes: 1 addition & 1 deletion drivers/tee/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Generic Trusted Execution Environment Configuration
menuconfig TEE
tristate "Trusted Execution Environment support"
depends on HAVE_ARM_SMCCC || COMPILE_TEST || CPU_SUP_AMD
depends on HAVE_ARM_SMCCC || COMPILE_TEST || CPU_SUP_AMD || RISCV_SBI_MPXY_MBOX
select CRYPTO_LIB_SHA1
select DMA_SHARED_BUFFER
select GENERIC_ALLOCATOR
Expand Down
11 changes: 10 additions & 1 deletion drivers/tee/optee/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@
# OP-TEE Trusted Execution Environment Configuration
config OPTEE
tristate "OP-TEE"
depends on HAVE_ARM_SMCCC
depends on HAVE_ARM_SMCCC || RISCV_SBI_MPXY_MBOX
depends on RISCV_SBI_MPXY_MBOX || !RISCV_SBI_MPXY_MBOX
depends on MMU
depends on RPMB || !RPMB
help
This implements the OP-TEE Trusted Execution Environment (TEE)
driver.

config OPTEE_RPMI_CONDUIT
bool
depends on OPTEE && RISCV_SBI_MPXY_MBOX
default y
help
Reach OP-TEE through the TEE service group of the RISC-V Platform
Management Interface (RPMI) on an SBI Message Proxy (MPXY) channel.

config OPTEE_INSECURE_LOAD_IMAGE
bool "Load OP-TEE image as firmware"
default n
Expand Down
1 change: 1 addition & 0 deletions drivers/tee/optee/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ optee-objs += supp.o
optee-objs += device.o
optee-objs += smc_abi.o
optee-objs += ffa_abi.o
optee-$(CONFIG_OPTEE_RPMI_CONDUIT) += rpmi_conduit.o

# for tracing framework to find optee_trace.h
CFLAGS_smc_abi.o := -I$(src)
8 changes: 8 additions & 0 deletions drivers/tee/optee/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,14 @@ static bool is_normal_memory(pgprot_t p)
#elif defined(CONFIG_ARM64)
return ((pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL)) ||
((pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL_TAGGED));
#elif defined(CONFIG_RISCV)
/*
* Svpbmt, or the T-Head equivalent, encodes non-cacheable and I/O
* memory in the memory type bits of the PTE, normal cacheable memory
* (PMA) has them cleared. Without Svpbmt the memory type only comes
* from the PMAs, the mask is empty and all mappings pass the check.
*/
return !(pgprot_val(p) & _PAGE_MTMASK);
#else
#error "Unsupported architecture"
#endif
Expand Down
3 changes: 3 additions & 0 deletions drivers/tee/optee/optee_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,9 @@ static inline void reg_pair_from_64(u32 *reg0, u32 *reg1, u64 val)
/* Registration of the ABIs */
int optee_smc_abi_register(void);
void optee_smc_abi_unregister(void);
#if IS_ENABLED(CONFIG_OPTEE_RPMI_CONDUIT)
optee_invoke_fn *optee_rpmi_conduit_init(struct device *dev);
#endif
int optee_ffa_abi_register(void);
void optee_ffa_abi_unregister(void);

Expand Down
69 changes: 69 additions & 0 deletions drivers/tee/optee/optee_rpmi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
/*
* Copyright 2026 NXP
*/
#ifndef OPTEE_RPMI_H
#define OPTEE_RPMI_H

#include <linux/types.h>
#include <linux/uuid.h>

/*
* This file defines how the OP-TEE SMC ABI (optee_smc.h) is carried by the
* TEE service group of the RISC-V Platform Management Interface (RPMI). It
* is kept in sync between secure world and the normal world driver.
*
* An invocation of the SMC ABI is a TEE_CALL service request sent to the
* RPMI TEE framework on an SBI MPXY channel where:
* - SENDER_ID identifies the REE endpoint and TARGET_ID the OP-TEE
* endpoint, both assigned by the framework,
* - SERVICE is OPTEE_RPMI_SERVICE_UUID in RFC 4122 byte order,
* - SERVICE_DATA carries the register arguments a0-a7 of the SMC ABI as
* little-endian 64-bit words.
*
* The SERVICE_RSP of the TEE_CALL response carries the return values a0-a3
* of the SMC ABI as little-endian 64-bit words. The STATUS of the response
* is set by the framework and is RPMI_SUCCESS whenever OP-TEE was reached,
* errors reported by OP-TEE itself are returned in a0 as usual.
*/

/*
* UUID identifying the OP-TEE API as a TEE_CALL service, the same value
* as returned by OPTEE_SMC_CALLS_UID (OPTEE_MSG_UID_0..3).
*/
#define OPTEE_RPMI_SERVICE_UUID \
UUID_INIT(0x384fb3e0, 0xe7f8, 0x11e3, \
0xaf, 0x63, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b)

#define OPTEE_RPMI_CALL_NUM_ARGS 8
#define OPTEE_RPMI_CALL_NUM_RETS 4

/**
* struct optee_rpmi_call_req - TEE_CALL request data invoking the SMC ABI
* @sender_id: SENDER_ID, endpoint identifier of the REE
* @target_id: TARGET_ID, endpoint identifier of OP-TEE
* @service: SERVICE, bytes of OPTEE_RPMI_SERVICE_UUID
* @data_len: SERVICE_DATA_LEN, sizeof(@args)
* @args: SERVICE_DATA, register arguments a0-a7 of the SMC ABI
*/
struct optee_rpmi_call_req {
__le32 sender_id;
__le32 target_id;
u8 service[UUID_SIZE];
__le32 data_len;
__le64 args[OPTEE_RPMI_CALL_NUM_ARGS];
} __packed;

/**
* struct optee_rpmi_call_rsp - TEE_CALL response data of the SMC ABI
* @status: STATUS, RPMI error code set by the framework
* @rsp_len: SERVICE_RSP_LEN, sizeof(@rets)
* @rets: SERVICE_RSP, return values a0-a3 of the SMC ABI
*/
struct optee_rpmi_call_rsp {
__le32 status;
__le32 rsp_len;
__le64 rets[OPTEE_RPMI_CALL_NUM_RETS];
} __packed;

#endif /*OPTEE_RPMI_H*/
Loading
Loading