diff --git a/Documentation/devicetree/bindings/firmware/linaro,optee-rpmi.yaml b/Documentation/devicetree/bindings/firmware/linaro,optee-rpmi.yaml new file mode 100644 index 00000000000000..1c3dffc331ff9f --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/linaro,optee-rpmi.yaml @@ -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 + +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>; + }; + }; +... diff --git a/Documentation/tee/op-tee.rst b/Documentation/tee/op-tee.rst index b0ac097d55476a..b56c32bf255bfe 100644 --- a/Documentation/tee/op-tee.rst +++ b/Documentation/tee/op-tee.rst @@ -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: @@ -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 diff --git a/MAINTAINERS b/MAINTAINERS index 3a19da74d00c9d..fa6ec35555a94b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20420,6 +20420,7 @@ M: Jens Wiklander 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 @@ -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 diff --git a/drivers/mailbox/riscv-sbi-mpxy-mbox.c b/drivers/mailbox/riscv-sbi-mpxy-mbox.c index 714f7fb97a2fd6..83a89e285bb1a6 100644 --- a/drivers/mailbox/riscv-sbi-mpxy-mbox.c +++ b/drivers/mailbox/riscv-sbi-mpxy-mbox.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -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) diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig index 98c3ad0839409b..6434204d899e38 100644 --- a/drivers/tee/Kconfig +++ b/drivers/tee/Kconfig @@ -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 diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index 50d2051f7f20b7..0b6cd91a8ee885 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -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 diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile index ad7049c1c10721..4b5a868a939846 100644 --- a/drivers/tee/optee/Makefile +++ b/drivers/tee/optee/Makefile @@ -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) diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index e046aff6182866..c29bff2248485b 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -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 diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index aefe1e6f568915..b90359988a3c1e 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -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); diff --git a/drivers/tee/optee/optee_rpmi.h b/drivers/tee/optee/optee_rpmi.h new file mode 100644 index 00000000000000..89821255bcc039 --- /dev/null +++ b/drivers/tee/optee/optee_rpmi.h @@ -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 +#include + +/* + * 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*/ diff --git a/drivers/tee/optee/rpmi_conduit.c b/drivers/tee/optee/rpmi_conduit.c new file mode 100644 index 00000000000000..bc4ff975caaf53 --- /dev/null +++ b/drivers/tee/optee/rpmi_conduit.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2026 NXP + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "optee_private.h" +#include "optee_rpmi.h" +#include "optee_smc.h" + +/* + * This file implements the conduit carrying the SMC ABI over the TEE + * service group of the RISC-V Platform Management Interface (RPMI). Each + * invocation of the ABI is a TEE_CALL request sent on an SBI MPXY channel + * with the message layout described in optee_rpmi.h. + * + * The TEE_CALL request is not sent with mbox_send_message(): the target + * TEE executes on the calling hart until it responds, so the transfer is + * done with riscv_sbi_mpxy_mbox_call() which bypasses the mailbox core + * queue and channel lock. Calls from different harts run concurrently, + * exactly like SMCs do. + */ + +static_assert(sizeof(struct optee_rpmi_call_req) == 92); +static_assert(sizeof(struct optee_rpmi_call_rsp) == 40); + +/** + * struct optee_rpmi_conduit - RPMI TEE service group conduit + * @cl: mailbox client owning @chan + * @chan: SBI MPXY channel implementing the RPMI TEE service group + * @sender_id: endpoint identifier of the REE + * @target_id: endpoint identifier of OP-TEE + */ +struct optee_rpmi_conduit { + struct mbox_client cl; + struct mbox_chan *chan; + u32 sender_id; + u32 target_id; +}; + +/* Like the rest of the SMC ABI, at most a single OP-TEE instance is supported */ +static struct optee_rpmi_conduit optee_rpmi; + +static const uuid_t optee_rpmi_service_uuid = OPTEE_RPMI_SERVICE_UUID; + +static void optee_rpmi_invoke_fn(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + unsigned long a6, unsigned long a7, + struct arm_smccc_res *res) +{ + struct optee_rpmi_call_req req = { + .sender_id = cpu_to_le32(optee_rpmi.sender_id), + .target_id = cpu_to_le32(optee_rpmi.target_id), + .data_len = cpu_to_le32(sizeof(req.args)), + .args = { + cpu_to_le64(a0), cpu_to_le64(a1), cpu_to_le64(a2), + cpu_to_le64(a3), cpu_to_le64(a4), cpu_to_le64(a5), + cpu_to_le64(a6), cpu_to_le64(a7), + }, + }; + struct optee_rpmi_call_rsp rsp = {}; + struct rpmi_mbox_message msg; + int rc; + + export_uuid(req.service, &optee_rpmi_service_uuid); + + rpmi_mbox_init_send_with_response(&msg, RPMI_TEE_SRV_CALL, + &req, sizeof(req), &rsp, sizeof(rsp)); + rc = riscv_sbi_mpxy_mbox_call(optee_rpmi.chan, &msg); + if (!rc) { + if (msg.data.out_response_len < sizeof(rsp.status)) + rc = -EIO; + else + rc = rpmi_to_linux_error((s32)le32_to_cpu(rsp.status)); + } + if (!rc && (msg.data.out_response_len < sizeof(rsp) || + le32_to_cpu(rsp.rsp_len) != sizeof(rsp.rets))) + rc = -EIO; + + if (rc) { + /* + * The SBI implementation or the RPMI TEE framework failed to + * deliver the call, OP-TEE was not reached. Report it in a0 + * as the SMC ABI does for a call that could not be handled. + */ + if (rc != -EBUSY) + pr_warn_ratelimited("TEE_CALL of 0x%lx failed: %d\n", + a0, rc); + res->a0 = rc == -EBUSY ? OPTEE_SMC_RETURN_EBUSY : + OPTEE_SMC_RETURN_ENOTAVAIL; + res->a1 = 0; + res->a2 = 0; + res->a3 = 0; + return; + } + + res->a0 = le64_to_cpu(rsp.rets[0]); + res->a1 = le64_to_cpu(rsp.rets[1]); + res->a2 = le64_to_cpu(rsp.rets[2]); + res->a3 = le64_to_cpu(rsp.rets[3]); +} + +static void optee_rpmi_conduit_release(void *data) +{ + struct optee_rpmi_conduit *conduit = data; + + mbox_free_channel(conduit->chan); + conduit->chan = NULL; +} + +static int optee_rpmi_get_attr(struct optee_rpmi_conduit *conduit, + enum rpmi_mbox_attribute_id id, u32 *value) +{ + struct rpmi_mbox_message msg; + int rc; + + rpmi_mbox_init_get_attribute(&msg, id); + rc = rpmi_mbox_send_message(conduit->chan, &msg); + if (rc) + return rc; + + *value = msg.attr.value; + return 0; +} + +optee_invoke_fn *optee_rpmi_conduit_init(struct device *dev) +{ + struct optee_rpmi_conduit *conduit = &optee_rpmi; + u32 value; + int rc; + + if (conduit->chan) + return ERR_PTR(-EBUSY); + + rc = device_property_read_u32(dev, "riscv,rpmi-tee-sender-id", + &conduit->sender_id); + if (rc) + return ERR_PTR(dev_err_probe(dev, rc, + "missing \"riscv,rpmi-tee-sender-id\" property\n")); + + rc = device_property_read_u32(dev, "riscv,rpmi-tee-target-id", + &conduit->target_id); + if (rc) + return ERR_PTR(dev_err_probe(dev, rc, + "missing \"riscv,rpmi-tee-target-id\" property\n")); + + conduit->cl.dev = dev; + conduit->cl.tx_block = false; + conduit->cl.knows_txdone = true; + conduit->chan = mbox_request_channel(&conduit->cl, 0); + if (IS_ERR(conduit->chan)) { + rc = PTR_ERR(conduit->chan); + conduit->chan = NULL; + return ERR_PTR(dev_err_probe(dev, rc, + "failed to request MPXY channel\n")); + } + + rc = devm_add_action_or_reset(dev, optee_rpmi_conduit_release, conduit); + if (rc) + return ERR_PTR(rc); + + rc = optee_rpmi_get_attr(conduit, RPMI_MBOX_ATTR_SERVICEGROUP_ID, + &value); + if (rc) + return ERR_PTR(dev_err_probe(dev, rc, + "failed to read RPMI service group ID\n")); + if (value != RPMI_SRVGRP_TEE) { + dev_err(dev, "MPXY channel implements RPMI service group 0x%x, not TEE\n", + value); + return ERR_PTR(-ENODEV); + } + + rc = optee_rpmi_get_attr(conduit, RPMI_MBOX_ATTR_MAX_MSG_DATA_SIZE, + &value); + if (rc) + return ERR_PTR(dev_err_probe(dev, rc, + "failed to read RPMI max message size\n")); + if (value < sizeof(struct optee_rpmi_call_req) || + value < sizeof(struct optee_rpmi_call_rsp)) { + dev_err(dev, "MPXY channel message size %u is too small\n", + value); + return ERR_PTR(-EINVAL); + } + + pr_info("using RPMI TEE service group, endpoints %u -> %u\n", + conduit->sender_id, conduit->target_id); + + return optee_rpmi_invoke_fn; +} diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index b8a2bdac3208f9..3d5d545269b538 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -1464,6 +1464,20 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm) return rc; } +/* + * struct optee_smc_conduit - conduit used to invoke the SMC ABI + * @init: probes the conduit and returns the function invoking the + * SMC ABI through it, or an ERR_PTR() on failure + * + * The SMC ABI is defined in terms of register arguments and return values + * (see optee_smc.h) but does not depend on how they reach secure world. A + * conduit is selected by the compatible string of the OP-TEE firmware node. + */ +struct optee_smc_conduit { + optee_invoke_fn *(*init)(struct device *dev); +}; + +#ifdef CONFIG_HAVE_ARM_SMCCC /* Simple wrapper functions to be able to use a function pointer */ static void optee_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, @@ -1483,7 +1497,7 @@ static void optee_smccc_hvc(unsigned long a0, unsigned long a1, arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res); } -static optee_invoke_fn *get_invoke_func(struct device *dev) +static optee_invoke_fn *optee_smccc_conduit_init(struct device *dev) { const char *method; @@ -1503,6 +1517,17 @@ static optee_invoke_fn *get_invoke_func(struct device *dev) return ERR_PTR(-EINVAL); } +static const struct optee_smc_conduit optee_smccc_conduit = { + .init = optee_smccc_conduit_init, +}; +#endif + +#if IS_ENABLED(CONFIG_OPTEE_RPMI_CONDUIT) +static const struct optee_smc_conduit optee_rpmi_conduit = { + .init = optee_rpmi_conduit_init, +}; +#endif + /* optee_remove - Device Removal Routine * @pdev: platform device information struct * @@ -1728,6 +1753,7 @@ static int optee_protmem_pool_init(struct optee *optee) static int optee_probe(struct platform_device *pdev) { + const struct optee_smc_conduit *conduit; optee_invoke_fn *invoke_fn; struct tee_shm_pool *pool = ERR_PTR(-EINVAL); struct optee *optee = NULL; @@ -1741,7 +1767,11 @@ static int optee_probe(struct platform_device *pdev) u32 sec_caps; int rc; - invoke_fn = get_invoke_func(&pdev->dev); + conduit = device_get_match_data(&pdev->dev); + if (!conduit) + return -ENODEV; + + invoke_fn = conduit->init(&pdev->dev); if (IS_ERR(invoke_fn)) return PTR_ERR(invoke_fn); @@ -1956,7 +1986,12 @@ static int optee_probe(struct platform_device *pdev) } static const struct of_device_id optee_dt_match[] = { - { .compatible = "linaro,optee-tz" }, +#ifdef CONFIG_HAVE_ARM_SMCCC + { .compatible = "linaro,optee-tz", .data = &optee_smccc_conduit }, +#endif +#if IS_ENABLED(CONFIG_OPTEE_RPMI_CONDUIT) + { .compatible = "linaro,optee-rpmi", .data = &optee_rpmi_conduit }, +#endif {}, }; MODULE_DEVICE_TABLE(of, optee_dt_match); diff --git a/include/linux/mailbox/riscv-rpmi-message.h b/include/linux/mailbox/riscv-rpmi-message.h index e135c6564d0c80..0530e1dddf3c5d 100644 --- a/include/linux/mailbox/riscv-rpmi-message.h +++ b/include/linux/mailbox/riscv-rpmi-message.h @@ -93,6 +93,7 @@ static inline int rpmi_to_linux_error(int rpmi_error) /* RPMI service group IDs */ #define RPMI_SRVGRP_SYSTEM_MSI 0x00002 #define RPMI_SRVGRP_CLOCK 0x00008 +#define RPMI_SRVGRP_TEE 0x00010 /* RPMI clock service IDs */ enum rpmi_clock_service_id { @@ -119,6 +120,30 @@ enum rpmi_sysmsi_service_id { RPMI_SYSMSI_SRV_ID_MAX_COUNT }; +/* RPMI TEE service IDs */ +enum rpmi_tee_service_id { + RPMI_TEE_SRV_ENABLE_NOTIFICATION = 0x01, + RPMI_TEE_SRV_PROBE_FEATURES = 0x02, + RPMI_TEE_SRV_PROBE_SYSTEM = 0x03, + RPMI_TEE_SRV_EXIT = 0x04, + RPMI_TEE_SRV_SIGNAL_BUS_SETUP = 0x05, + RPMI_TEE_SRV_SIGNAL_BUS_TEARDOWN = 0x06, + RPMI_TEE_SRV_SIGNAL_RAISE = 0x07, + RPMI_TEE_SRV_SIGNAL_RETRIEVE = 0x08, + RPMI_TEE_SRV_MEMORY_PARCEL_CREATE = 0x09, + RPMI_TEE_SRV_MEMORY_PARCEL_ACCEPT = 0x0a, + RPMI_TEE_SRV_MEMORY_PARCEL_RELEASE = 0x0b, + RPMI_TEE_SRV_MEMORY_PARCEL_RECLAIM = 0x0c, + RPMI_TEE_SRV_MEMORY_SEGMENT_SEND = 0x0d, + RPMI_TEE_SRV_MEMORY_SEGMENT_RECEIVE = 0x0e, + RPMI_TEE_SRV_REGISTER_FOR_LIFECYCLE_INFO = 0x0f, + RPMI_TEE_SRV_ON_START_INFO = 0x10, + RPMI_TEE_SRV_ON_SHUTDOWN_INFO = 0x11, + RPMI_TEE_SRV_ON_CHANGED_INFO = 0x12, + RPMI_TEE_SRV_CALL = 0x13, + RPMI_TEE_SRV_ID_MAX_COUNT +}; + /* RPMI Linux mailbox attribute IDs */ enum rpmi_mbox_attribute_id { RPMI_MBOX_ATTR_SPEC_VERSION, diff --git a/include/linux/mailbox/riscv-sbi-mpxy-mbox.h b/include/linux/mailbox/riscv-sbi-mpxy-mbox.h new file mode 100644 index 00000000000000..4fb7b04cddc724 --- /dev/null +++ b/include/linux/mailbox/riscv-sbi-mpxy-mbox.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2026 NXP */ + +#ifndef _LINUX_RISCV_SBI_MPXY_MBOX_H_ +#define _LINUX_RISCV_SBI_MPXY_MBOX_H_ + +#include + +struct mbox_chan; +struct rpmi_mbox_message; + +#if IS_ENABLED(CONFIG_RISCV_SBI_MPXY_MBOX) +int riscv_sbi_mpxy_mbox_call(struct mbox_chan *chan, + struct rpmi_mbox_message *msg); +#else +static inline int riscv_sbi_mpxy_mbox_call(struct mbox_chan *chan, + struct rpmi_mbox_message *msg) +{ + return -ENODEV; +} +#endif + +#endif /* _LINUX_RISCV_SBI_MPXY_MBOX_H_ */