TEE_Result tee_svc_copy_to_user(struct tee_ta_session *sess, void *uaddr, const void *kaddr, size_t len) { TEE_Result res; struct tee_ta_session *s; if (sess == NULL) { res = tee_ta_get_current_session(&s); if (res != TEE_SUCCESS) return res; } else { s = sess; tee_ta_set_current_session(s); } res = tee_mmu_check_access_rights(s->ctx, TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER, (tee_uaddr_t)uaddr, len); if (res != TEE_SUCCESS) return res; memcpy(uaddr, kaddr, len); return TEE_SUCCESS; }
TEE_Result tee_svc_close_ta_session(TEE_TASessionHandle ta_sess) { TEE_Result res; struct tee_ta_session *sess; res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) return res; tee_ta_set_current_session(NULL); res = tee_ta_close_session((uint32_t)ta_sess, &sess->ctx->open_sessions); tee_ta_set_current_session(sess); return res; }
void tee_time_wait(uint32_t milliseconds_delay) { struct tee_ta_session *sess = NULL; struct teesmc32_param params; tee_ta_get_current_session(&sess); if (sess) tee_ta_set_current_session(NULL); memset(¶ms, 0, sizeof(params)); params.attr = TEESMC_ATTR_TYPE_VALUE_INPUT; params.u.value.a = milliseconds_delay; thread_rpc_cmd(TEE_RPC_WAIT, 1, ¶ms); if (sess) tee_ta_set_current_session(sess); }
TEE_Result tee_svc_invoke_ta_command(TEE_TASessionHandle ta_sess, uint32_t cancel_req_to, uint32_t cmd_id, uint32_t param_types, TEE_Param params[4], uint32_t *ret_orig) { TEE_Result res; uint32_t ret_o = TEE_ORIGIN_TEE; struct tee_ta_param param = { 0 }; TEE_Identity clnt_id; struct tee_ta_session *sess; struct tee_ta_session *called_sess = (struct tee_ta_session *)ta_sess; tee_mm_entry_t *mm_param = NULL; tee_paddr_t tmp_buf_pa[TEE_NUM_PARAMS]; res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) return res; res = tee_ta_verify_session_pointer(called_sess, &sess->ctx->open_sessions); if (res != TEE_SUCCESS) return res; res = tee_svc_copy_param(sess, called_sess, param_types, params, ¶m, tmp_buf_pa, &mm_param); if (res != TEE_SUCCESS) goto function_exit; res = tee_ta_invoke_command(&ret_o, called_sess, &clnt_id, cancel_req_to, cmd_id, ¶m); if (res != TEE_SUCCESS) goto function_exit; res = tee_svc_update_out_param(sess, called_sess, ¶m, tmp_buf_pa, params); if (res != TEE_SUCCESS) goto function_exit; function_exit: tee_ta_set_current_session(sess); called_sess->calling_sess = NULL; /* clear eventual borrowed mapping */ if (mm_param != NULL) { TEE_Result res2; void *va = 0; res2 = tee_mmu_kmap_pa2va((void *)tee_mm_get_smem(mm_param), &va); if (res2 == TEE_SUCCESS) tee_mmu_kunmap(va, tee_mm_get_bytes(mm_param)); } tee_mm_free(mm_param); if (ret_orig) tee_svc_copy_to_user(sess, ret_orig, &ret_o, sizeof(ret_o)); return res; }
/* * tee_time_get_ree_time(): this function implements the GP Internal API * function TEE_GetREETime() * Goal is to get the time of the Rich Execution Environment * This is why this time is provided through the supplicant */ TEE_Result tee_time_get_ree_time(TEE_Time *time) { struct tee_ta_session *sess = NULL; TEE_Result res = TEE_ERROR_BAD_PARAMETERS; struct teesmc32_param params; paddr_t phpayload = 0; paddr_t cookie = 0; TEE_Time *payload; tee_ta_get_current_session(&sess); tee_ta_set_current_session(NULL); if (!time) goto exit; thread_optee_rpc_alloc_payload(sizeof(TEE_Time), &phpayload, &cookie); if (!phpayload) goto exit; if (!TEE_ALIGNMENT_IS_OK(phpayload, TEE_Time)) goto exit; if (core_pa2va(phpayload, &payload)) goto exit; memset(¶ms, 0, sizeof(params)); params.attr = TEESMC_ATTR_TYPE_MEMREF_OUTPUT | (TEESMC_ATTR_CACHE_I_WRITE_THR | TEESMC_ATTR_CACHE_O_WRITE_THR) << TEESMC_ATTR_CACHE_SHIFT; params.u.memref.buf_ptr = phpayload; params.u.memref.size = sizeof(TEE_Time); res = thread_rpc_cmd(TEE_RPC_GET_TIME, 1, ¶ms); if (res != TEE_SUCCESS) goto exit; *time = *payload; exit: thread_optee_rpc_free_payload(cookie); tee_ta_set_current_session(sess); return res; }
/* Called when a TA calls an OpenSession on another TA */ TEE_Result tee_svc_open_ta_session(const TEE_UUID *dest, uint32_t cancel_req_to, uint32_t param_types, TEE_Param params[4], TEE_TASessionHandle *ta_sess, uint32_t *ret_orig) { TEE_Result res; uint32_t ret_o = TEE_ORIGIN_TEE; struct tee_ta_session *s = NULL; struct tee_ta_session *sess; tee_mm_entry_t *mm_param = NULL; TEE_UUID *uuid = malloc(sizeof(TEE_UUID)); struct tee_ta_param *param = malloc(sizeof(struct tee_ta_param)); TEE_Identity *clnt_id = malloc(sizeof(TEE_Identity)); tee_paddr_t tmp_buf_pa[TEE_NUM_PARAMS]; if (uuid == NULL || param == NULL || clnt_id == NULL) { res = TEE_ERROR_OUT_OF_MEMORY; goto out_free_only; } memset(param, 0, sizeof(struct tee_ta_param)); res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) goto out_free_only; res = tee_svc_copy_from_user(sess, uuid, dest, sizeof(TEE_UUID)); if (res != TEE_SUCCESS) goto function_exit; clnt_id->login = TEE_LOGIN_TRUSTED_APP; memcpy(&clnt_id->uuid, &sess->ctx->head->uuid, sizeof(TEE_UUID)); res = tee_svc_copy_param(sess, NULL, param_types, params, param, tmp_buf_pa, &mm_param); if (res != TEE_SUCCESS) goto function_exit; /* * Find session of a multi session TA or a static TA * In such a case, there is no need to ask the supplicant for the TA * code */ res = tee_ta_open_session(&ret_o, &s, &sess->ctx->open_sessions, uuid, NULL, clnt_id, cancel_req_to, param); if (ret_o != TEE_ORIGIN_TEE || res != TEE_ERROR_ITEM_NOT_FOUND) goto function_exit; if (ret_o == TEE_ORIGIN_TEE && res == TEE_ERROR_ITEM_NOT_FOUND) { kta_signed_header_t *ta = NULL; struct tee_ta_nwumap lp; tee_mmu_set_ctx(NULL); /* Load TA */ res = tee_ta_rpc_load(uuid, &ta, &lp, &ret_o); if (res != TEE_SUCCESS) { tee_mmu_set_ctx(sess->ctx); goto function_exit; } res = tee_ta_open_session(&ret_o, &s, &sess->ctx->open_sessions, uuid, ta, clnt_id, cancel_req_to, param); tee_mmu_set_ctx(sess->ctx); if (res != TEE_SUCCESS) goto function_exit; s->ctx->nwumap = lp; } res = tee_svc_update_out_param(sess, NULL, param, tmp_buf_pa, params); if (res != TEE_SUCCESS) goto function_exit; function_exit: tee_ta_set_current_session(sess); if (mm_param != NULL) { TEE_Result res2; void *va = 0; res2 = tee_mmu_kmap_pa2va((void *)tee_mm_get_smem(mm_param), &va); if (res2 == TEE_SUCCESS) tee_mmu_kunmap(va, tee_mm_get_bytes(mm_param)); } tee_mm_free(mm_param); tee_svc_copy_to_user(sess, ta_sess, &s, sizeof(s)); tee_svc_copy_to_user(sess, ret_orig, &ret_o, sizeof(ret_o)); out_free_only: free(param); free(uuid); free(clnt_id); return res; }
/* * Back from execution of service: update parameters passed from TA: * If some parameters were memory references: * - either the memref was temporary: copy back data and update size * - or it was the original TA memref: update only the size value. */ static TEE_Result tee_svc_update_out_param( struct tee_ta_session *sess, struct tee_ta_session *called_sess, struct tee_ta_param *param, tee_paddr_t tmp_buf_pa[TEE_NUM_PARAMS], TEE_Param params[TEE_NUM_PARAMS]) { size_t n; bool have_private_mem_map = (called_sess == NULL) || (called_sess->ctx->static_ta != NULL) || ((called_sess->ctx->flags & TA_FLAG_USER_MODE) != 0); tee_ta_set_current_session(sess); for (n = 0; n < TEE_NUM_PARAMS; n++) { switch (TEE_PARAM_TYPE_GET(param->types, n)) { case TEE_PARAM_TYPE_MEMREF_OUTPUT: case TEE_PARAM_TYPE_MEMREF_INOUT: /* outside TA private => memref is valid, update size */ if (!tee_mmu_is_vbuf_inside_ta_private(sess->ctx, (uintptr_t)params[n].memref.buffer, param->params[n].memref.size)) { params[n].memref.size = param->params[n].memref.size; break; } /* * If we called a kernel TA the parameters are in shared * memory and no copy is needed. */ if (have_private_mem_map && param->params[n].memref.size <= params[n].memref.size) { uint8_t *src = 0; TEE_Result res; /* FIXME: TA_RAM is already mapped ! */ res = tee_mmu_kmap(tmp_buf_pa[n], param->params[n].memref.size, &src); if (res != TEE_SUCCESS) return TEE_ERROR_GENERIC; res = tee_svc_copy_to_user(sess, params[n].memref. buffer, src, param->params[n]. memref.size); if (res != TEE_SUCCESS) return res; tee_mmu_kunmap(src, param->params[n].memref.size); } params[n].memref.size = param->params[n].memref.size; break; case TEE_PARAM_TYPE_VALUE_OUTPUT: case TEE_PARAM_TYPE_VALUE_INOUT: params[n].value = param->params[n].value; break; default: continue; } } return TEE_SUCCESS; }