diff --git a/core/arch/arm/include/kernel/thread.h b/core/arch/arm/include/kernel/thread.h index 74a3676ea20..608db1b4df3 100644 --- a/core/arch/arm/include/kernel/thread.h +++ b/core/arch/arm/include/kernel/thread.h @@ -19,7 +19,7 @@ #define THREAD_ID_0 0 #define THREAD_ID_INVALID -1 -#define THREAD_RPC_MAX_NUM_PARAMS 4 +#define THREAD_RPC_MAX_NUM_PARAMS 6 #ifndef __ASSEMBLER__ @@ -721,6 +721,24 @@ struct mobj *thread_rpc_alloc_global_payload(size_t size); */ void thread_rpc_free_global_payload(struct mobj *mobj); +/** + * Request that the Client Application allocate shared memory for OCALL payload + * buffers. + * + * @size: size in bytes of payload buffer + * + * @returns mobj that describes allocated buffer or NULL on error + */ +struct mobj *thread_rpc_alloc_client_app_payload(size_t size); + +/** + * Free physical memory previously allocated with + * thread_rpc_alloc_client_app_payload() + * + * @mobj: mobj that describes the buffer + */ +void thread_rpc_free_client_app_payload(struct mobj *mobj); + /* * enum thread_shm_type - type of non-secure shared memory * @THREAD_SHM_TYPE_APPLICATION - user space application shared memory diff --git a/core/arch/arm/include/sm/optee_smc.h b/core/arch/arm/include/sm/optee_smc.h index 8a8df34388e..21291eb251a 100644 --- a/core/arch/arm/include/sm/optee_smc.h +++ b/core/arch/arm/include/sm/optee_smc.h @@ -280,6 +280,8 @@ #define OPTEE_SMC_SEC_CAP_VIRTUALIZATION BIT(3) /* Secure world supports Shared Memory with a NULL reference */ #define OPTEE_SMC_SEC_CAP_MEMREF_NULL BIT(4) +/* Secure world is built with OCALL support */ +#define OPTEE_SMC_SEC_CAP_OCALL BIT(5) #define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9 #define OPTEE_SMC_EXCHANGE_CAPABILITIES \ diff --git a/core/arch/arm/kernel/thread_optee_smc.c b/core/arch/arm/kernel/thread_optee_smc.c index 7fe97b9c2b2..7caaf522939 100644 --- a/core/arch/arm/kernel/thread_optee_smc.c +++ b/core/arch/arm/kernel/thread_optee_smc.c @@ -611,3 +611,14 @@ void thread_rpc_free_global_payload(struct mobj *mobj) thread_rpc_free(OPTEE_RPC_SHM_TYPE_GLOBAL, mobj_get_cookie(mobj), mobj); } + +struct mobj *thread_rpc_alloc_client_app_payload(size_t size) +{ + return thread_rpc_alloc(size, 8, OPTEE_RPC_SHM_TYPE_CLIENT_APP); +} + +void thread_rpc_free_client_app_payload(struct mobj *mobj) +{ + thread_rpc_free(OPTEE_RPC_SHM_TYPE_CLIENT_APP, mobj_get_cookie(mobj), + mobj); +} diff --git a/core/arch/arm/tee/entry_fast.c b/core/arch/arm/tee/entry_fast.c index 26682baa75c..d927532e686 100644 --- a/core/arch/arm/tee/entry_fast.c +++ b/core/arch/arm/tee/entry_fast.c @@ -92,6 +92,9 @@ static void tee_entry_exchange_capabilities(struct thread_smc_args *args) args->a1 |= OPTEE_SMC_SEC_CAP_VIRTUALIZATION; #endif args->a1 |= OPTEE_SMC_SEC_CAP_MEMREF_NULL; +#if defined(CFG_OCALL) + args->a1 |= OPTEE_SMC_SEC_CAP_OCALL; +#endif #if defined(CFG_CORE_DYN_SHM) dyn_shm_en = core_mmu_nsec_ddr_is_defined(); diff --git a/core/include/optee_rpc_cmd.h b/core/include/optee_rpc_cmd.h index 3b8d0290c66..3319ed5f5f2 100644 --- a/core/include/optee_rpc_cmd.h +++ b/core/include/optee_rpc_cmd.h @@ -97,6 +97,12 @@ * space application */ #define OPTEE_RPC_SHM_TYPE_GLOBAL 2 +/* + * Memory shared with the non-secure application that is the client of the TA + * that requests shared memory of this type; the client could be running in + * non-secure user-mode or in non-secure kernel-mode + */ +#define OPTEE_RPC_SHM_TYPE_CLIENT_APP 3 /* * Free shared memory previously allocated with OPTEE_RPC_CMD_SHM_ALLOC @@ -170,6 +176,18 @@ /* I2C master control flags */ #define OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT BIT(0) +/* + * Send an OCALL to the Client Application + * + * [in] value[0].a CA Command ID (i.e., OCALL# for the CA to execute) + * [out] value[0].b OCALL return value + * [out] value[0].c OCALL return value origin + * [in] value[1].a UUID of TA whence OCALL originated (HI bits) + * [out] value[1].b UUID of TA whence OCALL originated (LO bits) + * [in/out] any[2..5].* OCALL parameters as specified by the TA, if any + */ +#define OPTEE_RPC_CMD_OCALL 22 + /* * Definition of protocol for command OPTEE_RPC_CMD_FS */ diff --git a/core/pta/system.c b/core/pta/system.c index c25a8170594..f47c281e541 100644 --- a/core/pta/system.c +++ b/core/pta/system.c @@ -17,14 +17,24 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include +#define PTR_ADD(ptr, offs) ((void *)((uintptr_t)(ptr) + (uintptr_t)(offs))) + +#define ACCESS_RIGHTS_READ \ + (TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_ANY_OWNER) +#define ACCESS_RIGHTS_WRITE \ + (TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER) +#define ACCESS_RIGHTS_READ_WRITE (ACCESS_RIGHTS_READ | ACCESS_RIGHTS_WRITE) + struct bin_handle { const struct user_ta_store_ops *op; struct user_ta_store_handle *h; @@ -840,6 +850,302 @@ static TEE_Result system_get_tpm_event_log(uint32_t param_types, return res; } +#ifdef CFG_OCALL +static TEE_Result +ocall_check_memref_access_rights(const struct user_mode_ctx *uctx, uint32_t pt, + uaddr_t buffer, size_t size) +{ + uint32_t flags = 0; + + switch (pt) { + case TEE_PARAM_TYPE_MEMREF_INPUT: + flags = ACCESS_RIGHTS_READ; + break; + case TEE_PARAM_TYPE_MEMREF_INOUT: + flags = ACCESS_RIGHTS_READ_WRITE; + break; + case TEE_PARAM_TYPE_MEMREF_OUTPUT: + flags = ACCESS_RIGHTS_WRITE; + break; + default: + return TEE_ERROR_BAD_PARAMETERS; + } + + return tee_mmu_check_access_rights(uctx, flags, buffer, size); +} + +static TEE_Result ocall_check_parameters(const struct user_mode_ctx *uctx, + const struct utee_params *up) +{ + TEE_Result res = TEE_SUCCESS; + uaddr_t buffer = 0; + size_t size = 0; + uint32_t pt = 0; + size_t n = 0; + + res = tee_mmu_check_access_rights(uctx, ACCESS_RIGHTS_READ_WRITE, + (uaddr_t)up, sizeof(*up)); + if (res) + return res; + + for (n = 0; n < TEE_NUM_PARAMS; n++) { + pt = TEE_PARAM_TYPE_GET(up->types, n); + switch (pt) { + case TEE_PARAM_TYPE_NONE: + case TEE_PARAM_TYPE_VALUE_INPUT: + case TEE_PARAM_TYPE_VALUE_INOUT: + case TEE_PARAM_TYPE_VALUE_OUTPUT: + break; + case TEE_PARAM_TYPE_MEMREF_INPUT: + case TEE_PARAM_TYPE_MEMREF_INOUT: + case TEE_PARAM_TYPE_MEMREF_OUTPUT: + buffer = (uaddr_t)up->vals[n * 2]; + size = up->vals[n * 2 + 1]; + if ((buffer && !size) || (!buffer && size)) + return TEE_ERROR_BAD_PARAMETERS; + res = ocall_check_memref_access_rights(uctx, pt, buffer, + size); + if (res) + return res; + break; + default: + return TEE_ERROR_BAD_PARAMETERS; + } + } + + return res; +} + +static TEE_Result ocall_compute_mobj_size(struct utee_params *up, + size_t *mobj_size) +{ + size_t total = 0; + size_t size = 0; + size_t n = 0; + + for (n = 0; n < TEE_NUM_PARAMS; n++) { + switch (TEE_PARAM_TYPE_GET(up->types, n)) { + case TEE_PARAM_TYPE_NONE: + case TEE_PARAM_TYPE_VALUE_INPUT: + case TEE_PARAM_TYPE_VALUE_INOUT: + case TEE_PARAM_TYPE_VALUE_OUTPUT: + break; + case TEE_PARAM_TYPE_MEMREF_INPUT: + case TEE_PARAM_TYPE_MEMREF_INOUT: + case TEE_PARAM_TYPE_MEMREF_OUTPUT: + size = up->vals[n * 2 + 1]; + if (ADD_OVERFLOW(total, size, &total)) + return TEE_ERROR_SECURITY; + break; + default: + return TEE_ERROR_BAD_PARAMETERS; + } + } + + *mobj_size = total; + + return TEE_SUCCESS; +} + +static TEE_Result ocall_pre_process(struct thread_param *params, + struct utee_params *up, + struct mobj *mobj, + void *mobj_va) +{ + uint32_t pt = 0; + void *buffer = NULL; + size_t size = 0; + void *destination = NULL; + size_t mobj_offs = 0; + size_t n = 0; + + for (n = 0; n < TEE_NUM_PARAMS; n++) { + pt = TEE_PARAM_TYPE_GET(up->types, n); + switch (pt) { + case TEE_PARAM_TYPE_NONE: + params[n].attr = THREAD_PARAM_ATTR_NONE; + break; + case TEE_PARAM_TYPE_VALUE_INPUT: + case TEE_PARAM_TYPE_VALUE_INOUT: + params[n].u.value.a = up->vals[n * 2]; + params[n].u.value.b = up->vals[n * 2 + 1]; + fallthrough; + case TEE_PARAM_TYPE_VALUE_OUTPUT: + params[n].attr = THREAD_PARAM_ATTR_VALUE_IN + pt - + TEE_PARAM_TYPE_VALUE_INPUT; + break; + case TEE_PARAM_TYPE_MEMREF_INPUT: + case TEE_PARAM_TYPE_MEMREF_INOUT: + case TEE_PARAM_TYPE_MEMREF_OUTPUT: + buffer = (void *)(uintptr_t)up->vals[n * 2]; + size = up->vals[n * 2 + 1]; + if (buffer && pt != TEE_PARAM_TYPE_MEMREF_OUTPUT) { + destination = PTR_ADD(mobj_va, mobj_offs); + memcpy(destination, buffer, size); + } + params[n].u.memref.mobj = mobj; + params[n].u.memref.offs = mobj_offs; + params[n].u.memref.size = size; + params[n].attr = THREAD_PARAM_ATTR_MEMREF_IN + pt - + TEE_PARAM_TYPE_MEMREF_INPUT; + if (ADD_OVERFLOW(mobj_offs, size, &mobj_offs)) + return TEE_ERROR_SECURITY; + break; + default: + return TEE_ERROR_BAD_PARAMETERS; + } + } + + return TEE_SUCCESS; +} + +static TEE_Result ocall_post_process(struct thread_param *params, + struct utee_params *up, + void *mobj_va) +{ + uint32_t pt = 0; + void *buffer = NULL; + size_t size = 0; + void *source = NULL; + size_t mobj_offs = 0; + size_t n = 0; + + for (n = 0; n < TEE_NUM_PARAMS; n++) { + pt = TEE_PARAM_TYPE_GET(up->types, n); + switch (pt) { + case TEE_PARAM_TYPE_NONE: + case TEE_PARAM_TYPE_VALUE_INPUT: + break; + case TEE_PARAM_TYPE_VALUE_INOUT: + case TEE_PARAM_TYPE_VALUE_OUTPUT: + up->vals[n * 2] = params[n].u.value.a; + up->vals[n * 2 + 1] = params[n].u.value.b; + break; + case TEE_PARAM_TYPE_MEMREF_INPUT: + size = up->vals[n * 2 + 1]; + if (params[n].u.memref.size != size) + return TEE_ERROR_BAD_PARAMETERS; + if (ADD_OVERFLOW(mobj_offs, size, &mobj_offs)) + return TEE_ERROR_SECURITY; + break; + case TEE_PARAM_TYPE_MEMREF_INOUT: + case TEE_PARAM_TYPE_MEMREF_OUTPUT: + buffer = (void *)(uintptr_t)up->vals[n * 2]; + size = up->vals[n * 2 + 1]; + if (params[n].u.memref.size > size) + return TEE_ERROR_BAD_PARAMETERS; + if (buffer) { + source = PTR_ADD(mobj_va, mobj_offs); + memcpy(buffer, source, params[n].u.memref.size); + if (ADD_OVERFLOW(mobj_offs, size, &mobj_offs)) + return TEE_ERROR_SECURITY; + } + break; + default: + return TEE_ERROR_BAD_PARAMETERS; + } + } + + return TEE_SUCCESS; +} + +static TEE_Result system_ocall(struct tee_ta_session *s, uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx); + struct thread_param rpc_params[THREAD_RPC_MAX_NUM_PARAMS] = { }; + const size_t rpc_num_params = ARRAY_SIZE(rpc_params); + struct tee_ta_session *session = NULL; + uint32_t ocall_id = 0; + struct utee_params *ocall_up = NULL; + size_t ocall_up_size = 0; + struct mobj *mobj = NULL; + size_t mobj_size = 0; + void *mobj_va = NULL; + TEE_Result res = TEE_SUCCESS; + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + if (param_types != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + res = tee_ta_get_current_session(&session); + if (res) + return res; + + ocall_up_size = params[1].memref.size; + if (ocall_up_size != sizeof(*ocall_up)) + return TEE_ERROR_BAD_PARAMETERS; + + ocall_id = params[0].value.a; + ocall_up = (struct utee_params *)params[1].memref.buffer; /* User ptr */ + + res = ocall_check_parameters(&utc->uctx, ocall_up); + if (res) + return res; + + res = ocall_compute_mobj_size(ocall_up, &mobj_size); + if (res) + return res; + + if (mobj_size) { + mobj = thread_rpc_alloc_client_app_payload(mobj_size); + if (!mobj) + return TEE_ERROR_OUT_OF_MEMORY; + + mobj_va = mobj_get_va(mobj, 0); + if (!mobj_va) { + res = TEE_ERROR_GENERIC; + goto exit; + } + } + + rpc_params[0] = THREAD_PARAM_VALUE(INOUT, ocall_id, 0, 0); + rpc_params[1] = THREAD_PARAM_VALUE(IN, 0, 0, 0); + tee_uuid_to_octets((uint8_t *)&rpc_params[1].u.value, + &session->clnt_id.uuid); + + res = ocall_pre_process(rpc_params + 2, ocall_up, mobj, mobj_va); + if (res) + goto exit; + + res = thread_rpc_cmd(OPTEE_RPC_CMD_OCALL, rpc_num_params, rpc_params); + if (res) { + /* + * Failure to process the OCALL request, as indicated by the + * return code of the RPC, denotes that the state of normal + * world is such that it may not be able to handle an additional + * round-trip to the CA to free the SHM. As such, simply put the + * memory object here. + */ + mobj_put(mobj); + return res; + } + + res = ocall_post_process(rpc_params + 2, ocall_up, mobj_va); + if (res) + goto exit; + + params[0].value.a = rpc_params[0].u.value.b; /* OCALL ret val */ + params[0].value.b = rpc_params[0].u.value.c; /* OCALL ret val origin */ + +exit: + if (mobj) + thread_rpc_free_client_app_payload(mobj); + + return res; +} +#else +static TEE_Result system_ocall(struct tee_ta_session *s __unused, + uint32_t param_types __unused, + TEE_Param params[TEE_NUM_PARAMS] __unused) +{ + return TEE_ERROR_NOT_IMPLEMENTED; +} +#endif /*CFG_OCALL*/ + static TEE_Result open_session(uint32_t param_types __unused, TEE_Param params[TEE_NUM_PARAMS] __unused, void **sess_ctx) @@ -905,6 +1211,8 @@ static TEE_Result invoke_command(void *sess_ctx, uint32_t cmd_id, return system_dlsym(s, param_types, params); case PTA_SYSTEM_GET_TPM_EVENT_LOG: return system_get_tpm_event_log(param_types, params); + case PTA_SYSTEM_OCALL: + return system_ocall(s, param_types, params); default: break; } diff --git a/lib/libutee/arch/arm/user_ta_entry.c b/lib/libutee/arch/arm/user_ta_entry.c index c470ceec2ee..d570640b17b 100644 --- a/lib/libutee/arch/arm/user_ta_entry.c +++ b/lib/libutee/arch/arm/user_ta_entry.c @@ -165,6 +165,8 @@ static void uninit_instance(void) { __utee_gprof_fini(); TA_DestroyEntryPoint(); + if (__tee_api_system_session) + TEE_CloseTASession(__tee_api_system_session); __utee_call_elf_fini_fn(); } diff --git a/lib/libutee/include/pta_system.h b/lib/libutee/include/pta_system.h index c5df748af62..7498622ebea 100644 --- a/lib/libutee/include/pta_system.h +++ b/lib/libutee/include/pta_system.h @@ -189,4 +189,24 @@ */ #define PTA_SYSTEM_GET_TPM_EVENT_LOG 12 +/* + * Send an OCALL to the calling TA's Client Application + * + * Note that if TA 1 invokes TA 2 which invokes TA N+1 and the latter sends an + * OCALL, it is the CA of TA 1 that receives the OCALL. Nevertheless, the OCALL + * carries the UUID of the TA that sent it. Therefore, the CA can determine that + * the OCALL originated from TA N+1, even though the CA receives the OCALL as a + * result of having communicated with TA 1. + * + * [in/out] value[0].a: CA command Id (IN), CA command return value (OUT) + * [out] value[0].b: CA command return value origin + * [in/out] memref[1]: Array of TEE_Param[TEE_NUM_PARAMS], the OCALL params + * + * Returns TEE_SUCCESS if the OCALL was sent and was processed successfully. + * This value is not necessarily the same as the return value of the OCALL + * itself, whose interpretation is up to the CA & TA, and is passed to the TA + * along with its origin code via this command's parameters as specified above. + */ +#define PTA_SYSTEM_OCALL 13 + #endif /* __PTA_SYSTEM_H */ diff --git a/lib/libutee/include/tee_api_defines_extensions.h b/lib/libutee/include/tee_api_defines_extensions.h index 892760e099b..af8f5b12a9b 100644 --- a/lib/libutee/include/tee_api_defines_extensions.h +++ b/lib/libutee/include/tee_api_defines_extensions.h @@ -96,4 +96,11 @@ /* Private login method for REE kernel clients */ #define TEE_LOGIN_REE_KERNEL 0x80000000 +/* + * Implementation-specific origin code constants + */ + +/* The error code originated from the TA's Client Application (CA) */ +#define TEE_ORIGIN_CLIENT_APP 0xF0000001 + #endif /* TEE_API_DEFINES_EXTENSIONS_H */ diff --git a/lib/libutee/include/tee_internal_api_extensions.h b/lib/libutee/include/tee_internal_api_extensions.h index 76960b0e5b5..24ddc5fb0f0 100644 --- a/lib/libutee/include/tee_internal_api_extensions.h +++ b/lib/libutee/include/tee_internal_api_extensions.h @@ -34,6 +34,17 @@ TEE_Result TEE_CacheClean(char *buf, size_t len); TEE_Result TEE_CacheFlush(char *buf, size_t len); TEE_Result TEE_CacheInvalidate(char *buf, size_t len); +/* + * Send an OCALL to the Client Application + * + * The semantics are identical to TEEC_InvokeCommand but in the opposite + * direction. + */ +TEE_Result TEE_InvokeCACommand(uint32_t cancellationRequestTimeout, + uint32_t commandID, uint32_t paramTypes, + TEE_Param params[TEE_NUM_PARAMS], + uint32_t *returnOrigin); + /* * tee_map_zi() - Map zero initialized memory * @len: Number of bytes diff --git a/lib/libutee/tee_api.c b/lib/libutee/tee_api.c index 20acccbaba6..ada8a411826 100644 --- a/lib/libutee/tee_api.c +++ b/lib/libutee/tee_api.c @@ -10,10 +10,13 @@ #include #include #include +#include "pta_system.h" #include "tee_api_private.h" static const void *tee_api_instance_data; +TEE_TASessionHandle __tee_api_system_session; + /* System API - Internal Client API */ static TEE_Result copy_param(struct utee_params *up, uint32_t param_types, @@ -245,6 +248,136 @@ TEE_Result TEE_InvokeTACommand(TEE_TASessionHandle session, return res; } +#ifdef CFG_OCALL +TEE_Result TEE_InvokeCACommand(uint32_t cancellationRequestTimeout, + uint32_t commandID, uint32_t paramTypes, + TEE_Param params[TEE_NUM_PARAMS], + uint32_t *returnOrigin) +{ + const TEE_UUID uuid = PTA_SYSTEM_UUID; + TEE_Result res = TEE_SUCCESS; + uint32_t ret_origin = TEE_ORIGIN_TEE; + struct utee_params pta_up = { }; + struct utee_params ocall_up = { }; + void *buffer = NULL; + size_t size = 0; + size_t n = 0; + + /* Open session with the System PTA, if necessary */ + if (!__tee_api_system_session) { + res = TEE_OpenTASession(&uuid, TEE_TIMEOUT_INFINITE, 0, NULL, + &__tee_api_system_session, &ret_origin); + /* The System PTA is optional */ + if (res == TEE_ERROR_ITEM_NOT_FOUND && + ret_origin == TEE_ORIGIN_TEE) { + res = TEE_ERROR_NOT_SUPPORTED; + ret_origin = TEE_ORIGIN_API; + } + if (res) + goto exit; + } + + /* Convert the OCALL's parameters into a utee_params structure */ + ocall_up.types = paramTypes; + for (n = 0; n < TEE_NUM_PARAMS; n++) { + switch (TEE_PARAM_TYPE_GET(paramTypes, n)) { + case TEE_PARAM_TYPE_VALUE_INPUT: + case TEE_PARAM_TYPE_VALUE_INOUT: + ocall_up.vals[n * 2] = params[n].value.a; + ocall_up.vals[n * 2 + 1] = params[n].value.b; + break; + case TEE_PARAM_TYPE_MEMREF_INPUT: + case TEE_PARAM_TYPE_MEMREF_OUTPUT: + case TEE_PARAM_TYPE_MEMREF_INOUT: + buffer = params[n].memref.buffer; + size = params[n].memref.size; + if ((buffer && !size) || (!buffer && size)) { + res = TEE_ERROR_BAD_PARAMETERS; + ret_origin = TEE_ORIGIN_API; + goto exit; + } + ocall_up.vals[n * 2] = (vaddr_t)buffer; + ocall_up.vals[n * 2 + 1] = size; + break; + default: + break; + } + } + + /* Construct the parameters for the call to the PTA */ + pta_up.vals[0] = commandID; + pta_up.vals[2] = (uintptr_t)&ocall_up; + pta_up.vals[3] = sizeof(ocall_up); + pta_up.types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + /* Send the OCALL request */ + res = _utee_invoke_ta_command((uintptr_t)__tee_api_system_session, + cancellationRequestTimeout, + PTA_SYSTEM_OCALL, + &pta_up, + &ret_origin); + if (res != TEE_SUCCESS) + goto exit; + + /* Convert the utee_params structure into the OCALL's parameters */ + for (n = 0; n < TEE_NUM_PARAMS; n++) { + switch (TEE_PARAM_TYPE_GET(paramTypes, n)) { + case TEE_PARAM_TYPE_VALUE_OUTPUT: + case TEE_PARAM_TYPE_VALUE_INOUT: + params[n].value.a = ocall_up.vals[n * 2]; + params[n].value.b = ocall_up.vals[n * 2 + 1]; + break; + case TEE_PARAM_TYPE_MEMREF_OUTPUT: + case TEE_PARAM_TYPE_MEMREF_INOUT: + buffer = (void *)(uintptr_t)ocall_up.vals[n * 2]; + size = ocall_up.vals[n * 2 + 1]; + if (buffer != params[n].memref.buffer || + size > params[n].memref.size) { + res = TEE_ERROR_BAD_PARAMETERS; + ret_origin = TEE_ORIGIN_API; + goto exit; + } + params[n].memref.size = size; + break; + default: + break; + } + } + + /* Extract the OCALL return value and error origin */ + res = (TEE_Result)pta_up.vals[0]; + ret_origin = (uint32_t)pta_up.vals[1]; + +exit: + /* The PTA is a communications conduit to normal world */ + if (ret_origin == TEE_ORIGIN_TRUSTED_APP) + ret_origin = TEE_ORIGIN_COMMS; + + if (returnOrigin) + *returnOrigin = ret_origin; + + if (ret_origin == TEE_ORIGIN_TEE && + (res != TEE_SUCCESS || + res != TEE_ERROR_OUT_OF_MEMORY || + res != TEE_ERROR_TARGET_DEAD)) + TEE_Panic(res); + + return res; +} +#else +TEE_Result TEE_InvokeCACommand(uint32_t cancellationRequestTimeout __unused, + uint32_t commandID __unused, + uint32_t paramTypes __unused, + TEE_Param params[TEE_NUM_PARAMS] __unused, + uint32_t *returnOrigin __unused) +{ + return TEE_ERROR_NOT_IMPLEMENTED; +} +#endif /*CFG_OCALL*/ + /* System API - Cancellations */ bool TEE_GetCancellationFlag(void) diff --git a/lib/libutee/tee_api_private.h b/lib/libutee/tee_api_private.h index 91518878c4c..445b30d060c 100644 --- a/lib/libutee/tee_api_private.h +++ b/lib/libutee/tee_api_private.h @@ -8,6 +8,8 @@ #include #include +/* From tee_api.c */ +extern TEE_TASessionHandle __tee_api_system_session; void __utee_from_attr(struct utee_attribute *ua, const TEE_Attribute *attrs, uint32_t attr_count); diff --git a/mk/config.mk b/mk/config.mk index 5e48ae709f4..b9618c775ec 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -619,3 +619,10 @@ CFG_COMPAT_GP10_DES ?= y # Defines a limit for many levels TAs may call each others. CFG_CORE_MAX_SYSCALL_RECURSION ?= 4 + +# Enables support for OCALLs, allowing TAs to invoke commands on their CA. +# Since OCALLs are implemented in the System PTA, the latter is a prerequisite. +CFG_OCALL ?= y +ifeq ($(CFG_OCALL),y) +$(call force,CFG_SYSTEM_PTA,y) +endif