diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c index 2a7aeab40e5435..96f1ae8f2c4393 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/optee.c @@ -266,7 +266,7 @@ static int invoke_process_smt_channel(struct scmi_optee_channel *channel) param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = channel->channel_id; - ret = tee_client_invoke_func(scmi_optee_private->tee_ctx, &arg, param); + ret = tee_client_system_invoke_func(scmi_optee_private->tee_ctx, &arg, param); if (ret < 0 || arg.ret) { dev_err(scmi_optee_private->dev, "Can't invoke channel %u: %d / %#x\n", channel->channel_id, ret, arg.ret); @@ -297,7 +297,7 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t param[2].u.memref.shm = channel->tee_shm; param[2].u.memref.size = SCMI_OPTEE_MAX_MSG_SIZE; - ret = tee_client_invoke_func(scmi_optee_private->tee_ctx, &arg, param); + ret = tee_client_system_invoke_func(scmi_optee_private->tee_ctx, &arg, param); if (ret < 0 || arg.ret) { dev_err(scmi_optee_private->dev, "Can't invoke channel %u: %d / %#x\n", channel->channel_id, ret, arg.ret); diff --git a/drivers/tee/amdtee/core.c b/drivers/tee/amdtee/core.c index 297dc62bca2986..96b3c0e0d569b4 100644 --- a/drivers/tee/amdtee/core.c +++ b/drivers/tee/amdtee/core.c @@ -230,7 +230,7 @@ static void destroy_session(struct kref *ref) int amdtee_open_session(struct tee_context *ctx, struct tee_ioctl_open_session_arg *arg, - struct tee_param *param) + struct tee_param *param, bool system_thread) { struct amdtee_context_data *ctxdata = ctx->data; struct amdtee_session *sess = NULL; @@ -301,7 +301,7 @@ int amdtee_open_session(struct tee_context *ctx, return rc; } -int amdtee_close_session(struct tee_context *ctx, u32 session) +int amdtee_close_session(struct tee_context *ctx, u32 session, bool system_thread) { struct amdtee_context_data *ctxdata = ctx->data; u32 i, ta_handle, session_info; @@ -405,7 +405,7 @@ void amdtee_unmap_shmem(struct tee_shm *shm) int amdtee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, - struct tee_param *param) + struct tee_param *param, bool system_thread) { struct amdtee_context_data *ctxdata = ctx->data; struct amdtee_session *sess; diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index 290b1bb0e9cd72..096f687d99e879 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -328,7 +328,7 @@ int optee_open_session(struct tee_context *ctx, goto out; } - if (optee->ops->do_call_with_arg(ctx, shm, offs)) { + if (optee->ops->do_call_with_arg(ctx, shm, offs, false)) { msg_arg->ret = TEEC_ERROR_COMMUNICATION; msg_arg->ret_origin = TEEC_ORIGIN_COMMS; } @@ -374,7 +374,7 @@ int optee_close_session_helper(struct tee_context *ctx, u32 session) msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION; msg_arg->session = session; - optee->ops->do_call_with_arg(ctx, shm, offs); + optee->ops->do_call_with_arg(ctx, shm, offs, false); optee_free_msg_arg(ctx, entry, offs); @@ -400,7 +400,7 @@ int optee_close_session(struct tee_context *ctx, u32 session) } int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, - struct tee_param *param) + struct tee_param *param, bool system_thread) { struct optee *optee = tee_get_drvdata(ctx->teedev); struct optee_context_data *ctxdata = ctx->data; @@ -432,7 +432,7 @@ int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, if (rc) goto out; - if (optee->ops->do_call_with_arg(ctx, shm, offs)) { + if (optee->ops->do_call_with_arg(ctx, shm, offs, system_thread)) { msg_arg->ret = TEEC_ERROR_COMMUNICATION; msg_arg->ret_origin = TEEC_ORIGIN_COMMS; } @@ -474,7 +474,7 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session) msg_arg->cmd = OPTEE_MSG_CMD_CANCEL; msg_arg->session = session; msg_arg->cancel_id = cancel_id; - optee->ops->do_call_with_arg(ctx, shm, offs); + optee->ops->do_call_with_arg(ctx, shm, offs, false); optee_free_msg_arg(ctx, entry, offs); return 0; diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c index 0828240f27e624..9e4a7aa9053d7b 100644 --- a/drivers/tee/optee/ffa_abi.c +++ b/drivers/tee/optee/ffa_abi.c @@ -604,6 +604,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx, * @ctx: calling context * @shm: shared memory holding the message to pass to secure world * @offs: offset of the message in @shm + * @system_thread True if invocation expects to use a provisioned TEE system thread * * Does a FF-A call to OP-TEE in secure world and handles eventual resulting * Remote Procedure Calls (RPC) from OP-TEE. @@ -612,7 +613,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx, */ static int optee_ffa_do_call_with_arg(struct tee_context *ctx, - struct tee_shm *shm, u_int offs) + struct tee_shm *shm, u_int offs, bool system_thread) { struct ffa_send_direct_data data = { .data0 = OPTEE_FFA_YIELDING_CALL_WITH_ARG, diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 04ae58892608c6..0d760555478989 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -130,7 +130,8 @@ struct optee; */ struct optee_ops { int (*do_call_with_arg)(struct tee_context *ctx, - struct tee_shm *shm_arg, u_int offs); + struct tee_shm *shm_arg, u_int offs, + bool system_thread); int (*to_msg_param)(struct optee *optee, struct optee_msg_param *msg_params, size_t num_params, const struct tee_param *params); @@ -231,7 +232,7 @@ int optee_open_session(struct tee_context *ctx, int optee_close_session_helper(struct tee_context *ctx, u32 session); int optee_close_session(struct tee_context *ctx, u32 session); int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, - struct tee_param *param); + struct tee_param *param, bool system_thread); int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session); #define PTA_CMD_GET_DEVICES 0x0 diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h index 73b5e7760d102d..3c25155004fd13 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 @@ -255,6 +258,12 @@ struct optee_smc_get_shm_config_result { /* 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(8) + +#define MAX_NOTIF_VALUE_MASK GENMASK(15, 0) +#define MAX_NOTIF_IT_SHIFT 16 + #define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9 #define OPTEE_SMC_EXCHANGE_CAPABILITIES \ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES) @@ -426,6 +435,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 22 + /* * 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 a1c1fa1a9c28a7..4e66c86713be16 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -487,7 +487,7 @@ static int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm, msg_arg->params->u.tmem.buf_ptr = virt_to_phys(pages_list) | (tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1)); - if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) || + if (optee->ops->do_call_with_arg(ctx, shm_arg, 0, false) || msg_arg->ret != TEEC_SUCCESS) rc = -EINVAL; @@ -530,7 +530,7 @@ static int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm) msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; msg_arg->params[0].u.rmem.shm_ref = (unsigned long)shm; - if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) || + if (optee->ops->do_call_with_arg(ctx, shm_arg, 0, false) || msg_arg->ret != TEEC_SUCCESS) rc = -EINVAL; out: @@ -858,6 +858,7 @@ static void optee_handle_rpc(struct tee_context *ctx, * @ctx: calling context * @shm: shared memory holding the message to pass to secure world * @offs: offset of the message in @shm + * @system_thread True if invocation can leverage TEE provisioned system thread * * Does and SMC to OP-TEE in secure world and handles eventual resulting * Remote Procedure Calls (RPC) from OP-TEE. @@ -865,7 +866,7 @@ static void optee_handle_rpc(struct tee_context *ctx, * Returns return code from secure world, 0 is OK */ static int optee_smc_do_call_with_arg(struct tee_context *ctx, - struct tee_shm *shm, u_int offs) + struct tee_shm *shm, u_int offs, bool system_thread) { struct optee *optee = tee_get_drvdata(ctx->teedev); struct optee_call_waiter w; @@ -889,7 +890,12 @@ 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 (system_thread && + 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(¶m.a1, ¶m.a2, (u_long)shm); param.a3 = offs; } else { @@ -957,7 +963,7 @@ static int simple_call_with_arg(struct tee_context *ctx, u32 cmd) return PTR_ERR(msg_arg); msg_arg->cmd = cmd; - optee_smc_do_call_with_arg(ctx, shm, offs); + optee_smc_do_call_with_arg(ctx, shm, offs, false); optee_free_msg_arg(ctx, entry, offs); return 0; diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 98da206cd7615b..231c367579f5cf 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -579,7 +579,7 @@ static int tee_ioctl_invoke(struct tee_context *ctx, goto out; } - rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params); + rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params, false); if (rc) goto out; @@ -1170,16 +1170,31 @@ int tee_client_close_session(struct tee_context *ctx, u32 session) } EXPORT_SYMBOL_GPL(tee_client_close_session); +static int _tee_client_invoke_func(struct tee_context *ctx, + struct tee_ioctl_invoke_arg *arg, + struct tee_param *param, bool system_thread) +{ + if (!ctx->teedev->desc->ops->invoke_func) + return -EINVAL; + return ctx->teedev->desc->ops->invoke_func(ctx, arg, param, system_thread); +} + int tee_client_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct tee_param *param) { - if (!ctx->teedev->desc->ops->invoke_func) - return -EINVAL; - return ctx->teedev->desc->ops->invoke_func(ctx, arg, param); + return _tee_client_invoke_func(ctx, arg, param, false); } EXPORT_SYMBOL_GPL(tee_client_invoke_func); +int tee_client_system_invoke_func(struct tee_context *ctx, + struct tee_ioctl_invoke_arg *arg, + struct tee_param *param) +{ + return _tee_client_invoke_func(ctx, arg, param, true); +} +EXPORT_SYMBOL_GPL(tee_client_system_invoke_func); + int tee_client_cancel_req(struct tee_context *ctx, struct tee_ioctl_cancel_arg *arg) { diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h index 17eb1c5205d340..de23fa959597e0 100644 --- a/include/linux/tee_drv.h +++ b/include/linux/tee_drv.h @@ -102,7 +102,7 @@ struct tee_driver_ops { int (*close_session)(struct tee_context *ctx, u32 session); int (*invoke_func)(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, - struct tee_param *param); + struct tee_param *param, bool system_thread); int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session); int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params, struct tee_param *param); @@ -442,6 +442,22 @@ int tee_client_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct tee_param *param); +/** + * tee_client_system_invoke_func() - Invoke a function in a system Trusted Application + * @ctx: TEE Context + * @arg: Invoke arguments, see description of + * struct tee_ioctl_invoke_arg + * @param: Parameters passed to the Trusted Application + * + * System trusted applications are trusted services requiring a provisioned + * execution context. + * + * Returns < 0 on error else see @arg->ret for result. + */ +int tee_client_system_invoke_func(struct tee_context *ctx, + struct tee_ioctl_invoke_arg *arg, + struct tee_param *param); + /** * tee_client_cancel_req() - Request cancellation of the previous open-session * or invoke-command operations in a Trusted Application