Hi Amir,
On Fri, Oct 9, 2026 at 12:03 AM Amirreza Zarrabi amirreza.zarrabi@oss.qualcomm.com wrote:
Hi Jens,
On 10/8/2026 5:51 PM, Jens Wiklander wrote:
Hi Amir,
On Tue, Oct 6, 2026 at 2:40 AM Amirreza Zarrabi amirreza.zarrabi@oss.qualcomm.com wrote:
Define the OP-TEE service protocol carried by RPMI TEE_CALL payloads. Add operations for version and capability queries, shared-memory unregistration, asynchronous notification enablement, and yielding-call start and resume. Use fixed-width little-endian control fields and RPMI error codes for control responses.
Add a parcel memory-reference layout to the common message parameter union. Identify shared memory by its parcel ID and nonce, with a 64-bit byte offset and size, without changing the message parameter size. Encode NULL references with a zero parcel ID and nonce, leaving parcel ID zero usable with a nonzero nonce.
Document the wire layouts and ownership rules for matching Linux and OP-TEE implementations.
Signed-off-by: Amirreza Zarrabi amirreza.zarrabi@oss.qualcomm.com
drivers/tee/optee/optee_msg.h | 38 +++++-- drivers/tee/optee/optee_rpmi.h | 234 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+), 8 deletions(-)
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h index 6c3043f8da33..028f8cd95fdd 100644 --- a/drivers/tee/optee/optee_msg.h +++ b/drivers/tee/optee/optee_msg.h @@ -31,6 +31,9 @@ #define OPTEE_MSG_ATTR_TYPE_FMEM_INPUT OPTEE_MSG_ATTR_TYPE_RMEM_INPUT #define OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT #define OPTEE_MSG_ATTR_TYPE_FMEM_INOUT OPTEE_MSG_ATTR_TYPE_RMEM_INOUT +#define OPTEE_MSG_ATTR_TYPE_PMEM_INPUT OPTEE_MSG_ATTR_TYPE_RMEM_INPUT +#define OPTEE_MSG_ATTR_TYPE_PMEM_OUTPUT OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT +#define OPTEE_MSG_ATTR_TYPE_PMEM_INOUT OPTEE_MSG_ATTR_TYPE_RMEM_INOUT #define OPTEE_MSG_ATTR_TYPE_TMEM_INPUT 0x9 #define OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT 0xa #define OPTEE_MSG_ATTR_TYPE_TMEM_INOUT 0xb @@ -149,6 +152,23 @@ struct optee_msg_param_fmem { u64 global_id; };
+/**
- struct optee_msg_param_pmem - RPMI parcel memory reference
- @offs: full-width byte offset from the parcel's first byte
- @size: logical reference size, or required size for a short-buffer response
- @parcel_id: firmware-assigned parcel identifier
- @nonce: nonzero REE nonce supplied when sharing the parcel
- A zero parcel ID and nonce encode a NULL reference. Its offset must be zero;
- its size is preserved. Parcel ID zero remains valid with a nonzero nonce.
- */
+struct optee_msg_param_pmem {
Without an internal offset like in struct optee_msg_param_fmem, an explicit register SHM call into OP-TEE is needed before it can be used. You'd still need the TEE_MEMORY_PARCEL_CREATE, but we can save one round-trip into the secure world.
The original intenation was to use parcel-relative offsets, with the secure-side memory object covers the entire parcel. OP-TEE can retrieve it lazily and apply the supplied offset directly, so this design does not require an explicit SHM registration call or an additional round trip.
Since we are implementing the RPMI parcel memory-object cache independently of FF-A's cache in OP-TEE, this seems simpler: it avoids a separate initial-offset property, preserves a full-width offset reference, while keeping OP-TEE ignorant from the SHM concept which is a Linux side concept.
That said, I can separate the offsets to matching FF-A's memory-object model. But I am not sure what we achive?
I think it's needed, but I don't mind being proven wrong. :-)
IIRC, this stems from TEE_IOC_SHM_REGISTER. In hindsight, I regret that offset. We should have kept it in userspace, but that's too late now.
u64 offs;u64 size;u32 parcel_id;u32 nonce;I wonder if parcel_id and nonce wouldn't be better combined into a single field. They need to be separate when preparing arguments for the TEE_MEMORY_* calls. Everywhere else, it's only an opaque memory handle, and one handle is easier to keep track of than two.
I thought about that before. This would push the conversion to the firmware boundary. I was not sure if it is acceptable. I'll do that :).
Sounds good to me.
+};
/**
- struct optee_msg_param_value - opaque value parameter
- @a: first opaque value
@@ -166,18 +186,19 @@ struct optee_msg_param_value { /**
- struct optee_msg_param - parameter used together with struct optee_msg_arg
- @attr: attributes
- @tmem: parameter by temporary memory reference
- @rmem: parameter by registered memory reference
- @fmem: parameter by FF-A registered memory reference
- @value: parameter by opaque value
- @octets: parameter by octet string
- @u.tmem: parameter by temporary memory reference
- @u.rmem: parameter by registered memory reference
- @u.fmem: parameter by FF-A registered memory reference
- @u.pmem: parameter by RPMI parcel memory reference
- @u.value: parameter by opaque value
- @u.octets: parameter by octet string
- @u: union holding OP-TEE msg parameter
- @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in
- the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value or octets,
- OPTEE_MSG_ATTR_TYPE_TMEM_* indicates @tmem and
- OPTEE_MSG_ATTR_TYPE_RMEM_* or the alias PTEE_MSG_ATTR_TYPE_FMEM_* indicates
- @rmem or @fmem depending on the conduit.
- OPTEE_MSG_ATTR_TYPE_TMEM_* indicates @u.tmem. OPTEE_MSG_ATTR_TYPE_RMEM_*
- and its FMEM/PMEM aliases indicate @u.rmem, @u.fmem or @u.pmem depending
*/
- on the conduit.
- OPTEE_MSG_ATTR_TYPE_NONE indicates that none of the members are used.
struct optee_msg_param { @@ -186,6 +207,7 @@ struct optee_msg_param { struct optee_msg_param_tmem tmem; struct optee_msg_param_rmem rmem; struct optee_msg_param_fmem fmem;
struct optee_msg_param_pmem pmem; struct optee_msg_param_value value; u8 octets[24]; } u;diff --git a/drivers/tee/optee/optee_rpmi.h b/drivers/tee/optee/optee_rpmi.h new file mode 100644 index 000000000000..252216aad09b --- /dev/null +++ b/drivers/tee/optee/optee_rpmi.h @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#ifndef OPTEE_RPMI_H +#define OPTEE_RPMI_H
+#include <linux/bitops.h> +#include <linux/types.h> +#include <linux/uuid.h>
+/*
- OP-TEE service ABI over RPMI TEE_CALL.
- Requests and responses are carried in the TEE_CALL service payload.
- Control fields are little-endian. Response status fields contain signed
- RPMI error codes, distinct from the outer TEE_CALL status and the GP
- command result in optee_msg_arg.ret.
- */
+#define OPTEE_RPMI_SERVICE_UUID \
UUID_INIT(0x486178e0, 0xe7f8, 0x11e3, \0xbc, 0x5e, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b)+#define OPTEE_RPMI_VERSION_MAJOR 1 +#define OPTEE_RPMI_VERSION_MINOR 0
+/**
- struct optee_rpmi_probe_req - request without operation-specific arguments
- @op: GET_API_VERSION, GET_OS_VERSION or EXCHANGE_CAPABILITIES
- */
+struct optee_rpmi_probe_req {
__le32 op;+} __packed;
+/**
- struct optee_rpmi_status_resp - response carrying only an RPMI status
- @status: signed RPMI error code
- */
+struct optee_rpmi_status_resp {
__le32 status;+} __packed;
+/*
- Return the service API version.
- Request: struct optee_rpmi_probe_req
- Response: struct optee_rpmi_api_resp
- */
+#define OPTEE_RPMI_GET_API_VERSION 0
+/**
- struct optee_rpmi_api_resp - GET_API_VERSION response
- @status: signed RPMI error code
- @major: incompatible protocol revision
- @minor: compatible protocol revision
- */
+struct optee_rpmi_api_resp {
__le32 status;__le32 major;__le32 minor;+} __packed;
Why do these communication structs have to be packed? With careful design of the layout, padding, alignment, etc, it shouldn't be an issue.
Agreed. The structures already have naturally aligned fields and explicit reserved fields where needed, so `__packed` is unnecessary for their current layouts. I'll remove it and keep the wire layout explicitly defined, retaining unaligned access helpers where transport-buffer alignment is not guaranteed.
Good.
Cheers, Jens