OP-TEE can suspend a yielding call to request services from normal world through RPC.
Add handlers for shared-memory allocation and free requests. Use the existing kernel and supplicant allocation helpers, return RPMI parcel references for allocated memory, and resolve those references when freeing it.
Route other commands through the common OP-TEE RPC dispatcher. Store RPC results in the shared arguments for OP-TEE to consume when the yielding call resumes.
Signed-off-by: Amirreza Zarrabi amirreza.zarrabi@oss.qualcomm.com --- drivers/tee/optee/rpmi_abi.c | 104 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+)
diff --git a/drivers/tee/optee/rpmi_abi.c b/drivers/tee/optee/rpmi_abi.c index bbb219ddab38..8b90c3653e80 100644 --- a/drivers/tee/optee/rpmi_abi.c +++ b/drivers/tee/optee/rpmi_abi.c @@ -12,6 +12,7 @@ #include <linux/unaligned.h> #include "optee_private.h" #include "optee_rpmi.h" +#include "optee_rpc_cmd.h"
/* Keep transport errors separate from the control status in a response. */ static int optee_rpmi_call_with_status(struct optee *optee, @@ -353,3 +354,106 @@ static int optee_rpmi_from_msg_param(struct optee *optee,
return 0; } + +static void optee_rpmi_handle_rpc_shm_alloc(struct tee_context *ctx, + struct optee *optee, + struct optee_msg_arg *arg) +{ + struct tee_shm *shm; + u64 type, size; + + if (arg->num_params != 1 || + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) + goto err_bad_param; + + type = arg->params[0].u.value.a; + size = arg->params[0].u.value.b; + if (!size || size > SIZE_MAX - PAGE_SIZE + 1) + goto err_bad_param; + + switch (type) { + case OPTEE_RPC_SHM_TYPE_APPL: + shm = optee_rpc_cmd_alloc_suppl(ctx, size); + break; + case OPTEE_RPC_SHM_TYPE_KERNEL: + shm = tee_shm_alloc_priv_buf(optee->ctx, size); + break; + default: + goto err_bad_param; + } + + if (IS_ERR(shm)) { + arg->ret = TEEC_ERROR_OUT_OF_MEMORY; + return; + } + + arg->params[0] = (struct optee_msg_param) { + .attr = OPTEE_MSG_ATTR_TYPE_PMEM_OUTPUT, + .u.pmem.size = tee_shm_get_size(shm), + .u.pmem.global_id = shm->sec_world_id, + .u.pmem.offs = shm->offset, + }; + + arg->ret = TEEC_SUCCESS; + return; + +err_bad_param: + arg->ret = TEEC_ERROR_BAD_PARAMETERS; +} + +static void optee_rpmi_handle_rpc_shm_free(struct tee_context *ctx, + struct optee *optee, + struct optee_msg_arg *arg) +{ + struct tee_shm *shm; + u64 type, global_id; + + if (arg->num_params != 1 || + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) + goto err_bad_param; + + type = arg->params[0].u.value.a; + global_id = arg->params[0].u.value.b; + /* SHM_FREE requires a non-NULL identity. */ + if (!optee_rpmi_nonce(global_id) || arg->params[0].u.value.c) + goto err_bad_param; + + shm = optee_shm_handle_map_lookup(&optee->rpmi.shm_map, global_id); + if (!shm) + goto err_bad_param; + + switch (type) { + case OPTEE_RPC_SHM_TYPE_APPL: + optee_rpc_cmd_free_suppl(ctx, shm); + break; + case OPTEE_RPC_SHM_TYPE_KERNEL: + tee_shm_free(shm); + break; + default: + goto err_bad_param; + } + + arg->ret = TEEC_SUCCESS; + return; + +err_bad_param: + arg->ret = TEEC_ERROR_BAD_PARAMETERS; +} + +/* OP-TEE leaves the shared arguments unchanged while Linux handles the RPC. */ +static void optee_rpmi_handle_rpc_cmd(struct tee_context *ctx, + struct optee *optee, + struct optee_msg_arg *arg) +{ + arg->ret_origin = TEEC_ORIGIN_COMMS; + switch (arg->cmd) { + case OPTEE_RPC_CMD_SHM_ALLOC: + optee_rpmi_handle_rpc_shm_alloc(ctx, optee, arg); + break; + case OPTEE_RPC_CMD_SHM_FREE: + optee_rpmi_handle_rpc_shm_free(ctx, optee, arg); + break; + default: + optee_rpc_cmd(ctx, optee, arg); + } +}