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 { + u64 offs; + u64 size; + u32 parcel_id; + u32 nonce; +}; + /** * 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; + +/* + * Return the trusted OS revision, not the service API revision. + * + * Request: struct optee_rpmi_probe_req + * Response: struct optee_rpmi_os_resp + */ +#define OPTEE_RPMI_GET_OS_VERSION 1 + +/** + * struct optee_rpmi_os_resp - GET_OS_VERSION response + * @status: signed RPMI error code + * @major: trusted OS major revision + * @minor: trusted OS minor revision + * @reserved: must be zero + * @build_id: trusted OS build identifier, zero if unspecified + */ +struct optee_rpmi_os_resp { + __le32 status; + __le32 major; + __le32 minor; + __le32 reserved; + __le64 build_id; +} __packed; + +/* + * Query secure-world capabilities and limits. + * + * Request: struct optee_rpmi_probe_req + * Response: struct optee_rpmi_caps_resp + */ +#define OPTEE_RPMI_EXCHANGE_CAPABILITIES 2 + +/** + * struct optee_rpmi_caps_resp - EXCHANGE_CAPABILITIES response + * @status: signed RPMI error code + * @secure_caps: reserved for future optional features; zero in version 1 + * @rpc_param_count: nonzero parameter capacity of each RPC argument buffer + * @notification_count: nonzero logical key count, including synchronous keys + * Keys range from zero through notification_count - 1. + * + * Version 1 defines no capability bits. Unknown bits are ignored by Linux + * for compatibility with future extensions. + */ +struct optee_rpmi_caps_resp { + __le32 status; + __le32 secure_caps; + __le32 rpc_param_count; + __le32 notification_count; +} __packed; + +/* + * Unregister a shared parcel from OP-TEE. + * + * Request: struct optee_rpmi_unregister_req + * Response: struct optee_rpmi_status_resp + */ +#define OPTEE_RPMI_UNREGISTER_SHM 3 + +/** + * struct optee_rpmi_unregister_req - retire a shared parcel in OP-TEE + * @op: OPTEE_RPMI_UNREGISTER_SHM + * @parcel_id: parcel to retire; zero is valid with a nonzero nonce + * @nonce: nonzero nonce associated with the parcel + * + * Success means OP-TEE stopped using the mapping and released its receiver + * interest. + */ +struct optee_rpmi_unregister_req { + __le32 op; + __le32 parcel_id; + __le32 nonce; +} __packed; + +/* + * Enable asynchronous notification delivery. + * + * Request: struct optee_rpmi_enable_notif_req + * Response: struct optee_rpmi_status_resp + */ +#define OPTEE_RPMI_ENABLE_ASYNC_NOTIF 4 + +/** + * struct optee_rpmi_enable_notif_req - bind an incoming RPMI doorbell + * @op: OPTEE_RPMI_ENABLE_ASYNC_NOTIF + * @signal_id: allocated TEE-to-REE signal, not a logical notification key + * + * Success activates delivery and raises the doorbell for pending work. + * Raising the signal requests OPTEE_MSG_CMD_DO_BOTTOM_HALF. + * OPTEE_MSG_CMD_STOP_ASYNC_NOTIF stops future doorbell generation, but does + * not drain already-raised signals or release the signal ID. + */ +struct optee_rpmi_enable_notif_req { + __le32 op; + __le32 signal_id; +} __packed; + +/* + * Start a yielding command using shared command and RPC arguments. + * + * Request: struct optee_rpmi_call_req + * Response: struct optee_rpmi_call_resp + */ +#define OPTEE_RPMI_YIELDING_CALL_WITH_ARG 5 + +#define OPTEE_RPMI_YIELDING_CALL_RETURN_DONE 0 +#define OPTEE_RPMI_YIELDING_CALL_RETURN_RPC_CMD 1 +#define OPTEE_RPMI_YIELDING_CALL_RETURN_INTERRUPT 2 + +/** + * struct optee_rpmi_call_req - start a yielding command + * @op: OPTEE_RPMI_YIELDING_CALL_WITH_ARG + * @parcel_id: argument parcel identity + * @nonce: nonce associated with the parcel + * @flags: zero in version 1 + * @arg_offset: command argument byte offset from the parcel's first byte + * @rpc_offset: RPC argument byte offset from the parcel's first byte + * @arg_size: command argument extent in bytes + * @rpc_size: RPC argument capacity in bytes + * + * Firmware validates ownership, RW access, alignment and disjoint ranges. + * RPMI_ERR_BUSY rejects an initial request without acquiring call ownership. + */ +struct optee_rpmi_call_req { + __le32 op; + __le32 parcel_id; + __le32 nonce; + __le32 flags; + __le64 arg_offset; + __le64 rpc_offset; + __le32 arg_size; + __le32 rpc_size; +} __packed; + +/** + * struct optee_rpmi_call_resp - yielding command response + * @status: signed RPMI error code, distinct from the command's GP result + * @result: OPTEE_RPMI_YIELDING_CALL_RETURN_* value when status is success + * @resume_token: zero for DONE, nonzero opaque token for a suspended command + * + * DONE releases all access to the call's argument and RPC ranges. RPC_CMD + * requests RPC command handling; INTERRUPT requests resumption without an + * RPC command. Tokens belong to one accepted call, service and caller. + */ +struct optee_rpmi_call_resp { + __le32 status; + __le32 result; + __le64 resume_token; +} __packed; + +/* + * Resume a suspended yielding command. + * + * Request: struct optee_rpmi_resume_req + * Response: struct optee_rpmi_call_resp + */ +#define OPTEE_RPMI_YIELDING_CALL_RESUME 6 + +/** + * struct optee_rpmi_resume_req - resume a suspended command + * @op: OPTEE_RPMI_YIELDING_CALL_RESUME + * @reserved: must be zero + * @resume_token: token from the preceding response for this call + * + * Resume must not return RPMI_ERR_BUSY. + */ +struct optee_rpmi_resume_req { + __le32 op; + __le32 reserved; + __le64 resume_token; +} __packed; + +#endif /* OPTEE_RPMI_H */