[PATCH 1/2] tee: system invocation

From: Etienne Carriere
Date: Mon Jan 30 2023 - 04:42:20 EST


Adds TEE context flag sys_service to be enabled for invocation contexts
that should used TEE provisioned system resources. OP-TEE SMC ABI entry
rely this information to use a dedicated entry function to request
allocation of a system thread from a dedicated system context pool.

This feature is needed when a TEE invocation cannot afford to wait for
a free TEE thread when all TEE threads context are used and suspended
as these may be suspended waiting for a system service, as an SCMI clock
or voltage regulator, to be enabled. An example is when OP-TEE invokes
a Linux OS remove service (RPC) to access an eMMC RPMB partition and
the eMMC device is supplied by an OP-TEE SCMI regulator.

Signed-off-by: Etienne Carriere <etienne.carriere@xxxxxxxxxx>
---
drivers/tee/optee/optee_smc.h | 14 +++++++++++---
drivers/tee/optee/smc_abi.c | 6 +++++-
include/linux/tee_drv.h | 4 ++++
3 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h
index 73b5e7760d10..7c7eedf183c5 100644
--- a/drivers/tee/optee/optee_smc.h
+++ b/drivers/tee/optee/optee_smc.h
@@ -108,7 +108,8 @@ struct optee_smc_call_get_os_revision_result {
* Call with struct optee_msg_arg as argument
*
* When called with OPTEE_SMC_CALL_WITH_RPC_ARG or
- * OPTEE_SMC_CALL_WITH_REGD_ARG in a0 there is one RPC struct optee_msg_arg
+ * OPTEE_SMC_CALL_WITH_REGD_ARG or OPTEE_SMC_FUNCID_CALL_SYSTEM_WITH_REGD_ARG
+ * in a0 there is one RPC struct optee_msg_arg
* following after the first struct optee_msg_arg. The RPC struct
* optee_msg_arg has reserved space for the number of RPC parameters as
* returned by OPTEE_SMC_EXCHANGE_CAPABILITIES.
@@ -130,8 +131,8 @@ struct optee_smc_call_get_os_revision_result {
* a4-6 Not used
* a7 Hypervisor Client ID register
*
- * Call register usage, OPTEE_SMC_CALL_WITH_REGD_ARG:
- * a0 SMC Function ID, OPTEE_SMC_CALL_WITH_REGD_ARG
+ * Call register usage, OPTEE_SMC_CALL_WITH_REGD_ARG and OPTEE_SMC_FUNCID_CALL_SYSTEM_WITH_REGD_ARG:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_WITH_REGD_ARG or OPTEE_SMC_FUNCID_CALL_SYSTEM_WITH_REGD_ARG
* a1 Upper 32 bits of a 64-bit shared memory cookie
* a2 Lower 32 bits of a 64-bit shared memory cookie
* a3 Offset of the struct optee_msg_arg in the shared memory with the
@@ -175,6 +176,8 @@ struct optee_smc_call_get_os_revision_result {
OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_RPC_ARG)
#define OPTEE_SMC_CALL_WITH_REGD_ARG \
OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_REGD_ARG)
+#define OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG \
+ OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_SYSTEM_WITH_REGD_ARG)

/*
* Get Shared Memory Config
@@ -254,6 +257,8 @@ struct optee_smc_get_shm_config_result {
#define OPTEE_SMC_SEC_CAP_ASYNC_NOTIF BIT(5)
/* Secure world supports pre-allocating RPC arg struct */
#define OPTEE_SMC_SEC_CAP_RPC_ARG BIT(6)
+/* Secure world provisions thread for system service invocation */
+#define OPTEE_SMC_SEC_CAP_SYSTEM_THREAD BIT(7)

#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
@@ -426,6 +431,9 @@ struct optee_smc_disable_shm_cache_result {
/* See OPTEE_SMC_CALL_WITH_REGD_ARG above */
#define OPTEE_SMC_FUNCID_CALL_WITH_REGD_ARG 19

+/* See OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG above */
+#define OPTEE_SMC_FUNCID_CALL_SYSTEM_WITH_REGD_ARG 20
+
/*
* Resume from RPC (for example after processing a foreign interrupt)
*
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index a1c1fa1a9c28..513038a138f6 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -889,7 +889,11 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx,
}

if (rpc_arg && tee_shm_is_dynamic(shm)) {
- param.a0 = OPTEE_SMC_CALL_WITH_REGD_ARG;
+ if (ctx->sys_service &&
+ (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_SYSTEM_THREAD))
+ param.a0 = OPTEE_SMC_CALL_SYSTEM_WITH_REGD_ARG;
+ else
+ param.a0 = OPTEE_SMC_CALL_WITH_REGD_ARG;
reg_pair_from_64(&param.a1, &param.a2, (u_long)shm);
param.a3 = offs;
} else {
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 17eb1c5205d3..1ff292ba7679 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -47,6 +47,9 @@ struct tee_shm_pool;
* non-blocking in nature.
* @cap_memref_null: flag indicating if the TEE Client support shared
* memory buffer with a NULL pointer.
+ * @sys_service: flag set by the TEE Client to indicate that it is part of
+ * a system service and that the TEE may use resources reserved
+ * for this.
*/
struct tee_context {
struct tee_device *teedev;
@@ -55,6 +58,7 @@ struct tee_context {
bool releasing;
bool supp_nowait;
bool cap_memref_null;
+ bool sys_service;
};

struct tee_param_memref {
--
2.25.1