1*a54f2bb7SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause 2*a54f2bb7SMarouene Boubakri /* 3*a54f2bb7SMarouene Boubakri * Copyright (c) 2014, STMicroelectronics International N.V. 4*a54f2bb7SMarouene Boubakri * Copyright (c) 2015, Linaro Limited 5*a54f2bb7SMarouene Boubakri * Copyright (c) 2020, Arm Limited 6*a54f2bb7SMarouene Boubakri */ 7*a54f2bb7SMarouene Boubakri #include <initcall.h> 8*a54f2bb7SMarouene Boubakri #include <kernel/linker.h> 9*a54f2bb7SMarouene Boubakri #include <kernel/panic.h> 10*a54f2bb7SMarouene Boubakri #include <kernel/pseudo_ta.h> 11*a54f2bb7SMarouene Boubakri #include <kernel/tee_ta_manager.h> 12*a54f2bb7SMarouene Boubakri #include <mm/core_memprot.h> 13*a54f2bb7SMarouene Boubakri #include <mm/mobj.h> 14*a54f2bb7SMarouene Boubakri #include <stdlib.h> 15*a54f2bb7SMarouene Boubakri #include <string.h> 16*a54f2bb7SMarouene Boubakri #include <trace.h> 17*a54f2bb7SMarouene Boubakri #include <types_ext.h> 18*a54f2bb7SMarouene Boubakri 19*a54f2bb7SMarouene Boubakri #ifdef CFG_SECURE_DATA_PATH 20*a54f2bb7SMarouene Boubakri static bool client_is_secure(struct ts_session *s) 21*a54f2bb7SMarouene Boubakri { 22*a54f2bb7SMarouene Boubakri /* rely on core entry to have constrained client IDs */ 23*a54f2bb7SMarouene Boubakri if (to_ta_session(s)->clnt_id.login == TEE_LOGIN_TRUSTED_APP) 24*a54f2bb7SMarouene Boubakri return true; 25*a54f2bb7SMarouene Boubakri 26*a54f2bb7SMarouene Boubakri return false; 27*a54f2bb7SMarouene Boubakri } 28*a54f2bb7SMarouene Boubakri 29*a54f2bb7SMarouene Boubakri static bool validate_in_param(struct ts_session *s, struct mobj *mobj) 30*a54f2bb7SMarouene Boubakri { 31*a54f2bb7SMarouene Boubakri /* Supplying NULL to query buffer size is OK */ 32*a54f2bb7SMarouene Boubakri if (!mobj) 33*a54f2bb7SMarouene Boubakri return true; 34*a54f2bb7SMarouene Boubakri 35*a54f2bb7SMarouene Boubakri /* for secure clients, core entry always holds valid memref objects */ 36*a54f2bb7SMarouene Boubakri if (client_is_secure(s)) 37*a54f2bb7SMarouene Boubakri return true; 38*a54f2bb7SMarouene Boubakri 39*a54f2bb7SMarouene Boubakri /* all non-secure memory references are handled by PTAs */ 40*a54f2bb7SMarouene Boubakri if (mobj_is_nonsec(mobj)) 41*a54f2bb7SMarouene Boubakri return true; 42*a54f2bb7SMarouene Boubakri 43*a54f2bb7SMarouene Boubakri return false; 44*a54f2bb7SMarouene Boubakri } 45*a54f2bb7SMarouene Boubakri #else 46*a54f2bb7SMarouene Boubakri static bool validate_in_param(struct ts_session *s __unused, 47*a54f2bb7SMarouene Boubakri struct mobj *mobj __unused) 48*a54f2bb7SMarouene Boubakri { 49*a54f2bb7SMarouene Boubakri /* At this point, core has filled only valid accessible memref mobj */ 50*a54f2bb7SMarouene Boubakri return true; 51*a54f2bb7SMarouene Boubakri } 52*a54f2bb7SMarouene Boubakri #endif 53*a54f2bb7SMarouene Boubakri 54*a54f2bb7SMarouene Boubakri /* Maps pseudo TA params */ 55*a54f2bb7SMarouene Boubakri static TEE_Result copy_in_param(struct ts_session *s __maybe_unused, 56*a54f2bb7SMarouene Boubakri struct tee_ta_param *param, 57*a54f2bb7SMarouene Boubakri TEE_Param tee_param[TEE_NUM_PARAMS], 58*a54f2bb7SMarouene Boubakri bool did_map[TEE_NUM_PARAMS]) 59*a54f2bb7SMarouene Boubakri { 60*a54f2bb7SMarouene Boubakri size_t n; 61*a54f2bb7SMarouene Boubakri void *va; 62*a54f2bb7SMarouene Boubakri struct param_mem *mem; 63*a54f2bb7SMarouene Boubakri 64*a54f2bb7SMarouene Boubakri for (n = 0; n < TEE_NUM_PARAMS; n++) { 65*a54f2bb7SMarouene Boubakri switch (TEE_PARAM_TYPE_GET(param->types, n)) { 66*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_VALUE_INPUT: 67*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_VALUE_OUTPUT: 68*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_VALUE_INOUT: 69*a54f2bb7SMarouene Boubakri tee_param[n].value.a = param->u[n].val.a; 70*a54f2bb7SMarouene Boubakri tee_param[n].value.b = param->u[n].val.b; 71*a54f2bb7SMarouene Boubakri break; 72*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_MEMREF_INPUT: 73*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_MEMREF_OUTPUT: 74*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_MEMREF_INOUT: 75*a54f2bb7SMarouene Boubakri mem = ¶m->u[n].mem; 76*a54f2bb7SMarouene Boubakri if (!validate_in_param(s, mem->mobj)) 77*a54f2bb7SMarouene Boubakri return TEE_ERROR_BAD_PARAMETERS; 78*a54f2bb7SMarouene Boubakri if (mem->size) { 79*a54f2bb7SMarouene Boubakri TEE_Result res = mobj_inc_map(mem->mobj); 80*a54f2bb7SMarouene Boubakri 81*a54f2bb7SMarouene Boubakri if (res) 82*a54f2bb7SMarouene Boubakri return res; 83*a54f2bb7SMarouene Boubakri did_map[n] = true; 84*a54f2bb7SMarouene Boubakri va = mobj_get_va(mem->mobj, mem->offs); 85*a54f2bb7SMarouene Boubakri if (!va) 86*a54f2bb7SMarouene Boubakri return TEE_ERROR_BAD_PARAMETERS; 87*a54f2bb7SMarouene Boubakri if (mem->size && 88*a54f2bb7SMarouene Boubakri !mobj_get_va(mem->mobj, 89*a54f2bb7SMarouene Boubakri mem->offs + mem->size - 1)) 90*a54f2bb7SMarouene Boubakri return TEE_ERROR_BAD_PARAMETERS; 91*a54f2bb7SMarouene Boubakri } else { 92*a54f2bb7SMarouene Boubakri va = NULL; 93*a54f2bb7SMarouene Boubakri } 94*a54f2bb7SMarouene Boubakri 95*a54f2bb7SMarouene Boubakri tee_param[n].memref.buffer = va; 96*a54f2bb7SMarouene Boubakri tee_param[n].memref.size = mem->size; 97*a54f2bb7SMarouene Boubakri break; 98*a54f2bb7SMarouene Boubakri default: 99*a54f2bb7SMarouene Boubakri memset(tee_param + n, 0, sizeof(TEE_Param)); 100*a54f2bb7SMarouene Boubakri break; 101*a54f2bb7SMarouene Boubakri } 102*a54f2bb7SMarouene Boubakri } 103*a54f2bb7SMarouene Boubakri 104*a54f2bb7SMarouene Boubakri return TEE_SUCCESS; 105*a54f2bb7SMarouene Boubakri } 106*a54f2bb7SMarouene Boubakri 107*a54f2bb7SMarouene Boubakri static void update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS], 108*a54f2bb7SMarouene Boubakri struct tee_ta_param *param) 109*a54f2bb7SMarouene Boubakri { 110*a54f2bb7SMarouene Boubakri size_t n; 111*a54f2bb7SMarouene Boubakri 112*a54f2bb7SMarouene Boubakri for (n = 0; n < TEE_NUM_PARAMS; n++) { 113*a54f2bb7SMarouene Boubakri switch (TEE_PARAM_TYPE_GET(param->types, n)) { 114*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_VALUE_OUTPUT: 115*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_VALUE_INOUT: 116*a54f2bb7SMarouene Boubakri param->u[n].val.a = tee_param[n].value.a; 117*a54f2bb7SMarouene Boubakri param->u[n].val.b = tee_param[n].value.b; 118*a54f2bb7SMarouene Boubakri break; 119*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_MEMREF_OUTPUT: 120*a54f2bb7SMarouene Boubakri case TEE_PARAM_TYPE_MEMREF_INOUT: 121*a54f2bb7SMarouene Boubakri param->u[n].mem.size = tee_param[n].memref.size; 122*a54f2bb7SMarouene Boubakri break; 123*a54f2bb7SMarouene Boubakri default: 124*a54f2bb7SMarouene Boubakri break; 125*a54f2bb7SMarouene Boubakri } 126*a54f2bb7SMarouene Boubakri } 127*a54f2bb7SMarouene Boubakri } 128*a54f2bb7SMarouene Boubakri 129*a54f2bb7SMarouene Boubakri static void unmap_mapped_param(struct tee_ta_param *param, 130*a54f2bb7SMarouene Boubakri bool did_map[TEE_NUM_PARAMS]) 131*a54f2bb7SMarouene Boubakri { 132*a54f2bb7SMarouene Boubakri size_t n; 133*a54f2bb7SMarouene Boubakri 134*a54f2bb7SMarouene Boubakri for (n = 0; n < TEE_NUM_PARAMS; n++) { 135*a54f2bb7SMarouene Boubakri if (did_map[n]) { 136*a54f2bb7SMarouene Boubakri TEE_Result res __maybe_unused; 137*a54f2bb7SMarouene Boubakri 138*a54f2bb7SMarouene Boubakri res = mobj_dec_map(param->u[n].mem.mobj); 139*a54f2bb7SMarouene Boubakri assert(!res); 140*a54f2bb7SMarouene Boubakri } 141*a54f2bb7SMarouene Boubakri } 142*a54f2bb7SMarouene Boubakri } 143*a54f2bb7SMarouene Boubakri 144*a54f2bb7SMarouene Boubakri static TEE_Result pseudo_ta_enter_open_session(struct ts_session *s) 145*a54f2bb7SMarouene Boubakri { 146*a54f2bb7SMarouene Boubakri TEE_Result res = TEE_SUCCESS; 147*a54f2bb7SMarouene Boubakri struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx); 148*a54f2bb7SMarouene Boubakri struct tee_ta_session *ta_sess = to_ta_session(s); 149*a54f2bb7SMarouene Boubakri TEE_Param tee_param[TEE_NUM_PARAMS] = { }; 150*a54f2bb7SMarouene Boubakri bool did_map[TEE_NUM_PARAMS] = { false }; 151*a54f2bb7SMarouene Boubakri 152*a54f2bb7SMarouene Boubakri ts_push_current_session(s); 153*a54f2bb7SMarouene Boubakri ta_sess->err_origin = TEE_ORIGIN_TRUSTED_APP; 154*a54f2bb7SMarouene Boubakri 155*a54f2bb7SMarouene Boubakri if (stc->ctx.ref_count == 1 && stc->pseudo_ta->create_entry_point) { 156*a54f2bb7SMarouene Boubakri res = stc->pseudo_ta->create_entry_point(); 157*a54f2bb7SMarouene Boubakri if (res != TEE_SUCCESS) 158*a54f2bb7SMarouene Boubakri goto out; 159*a54f2bb7SMarouene Boubakri } 160*a54f2bb7SMarouene Boubakri 161*a54f2bb7SMarouene Boubakri if (stc->pseudo_ta->open_session_entry_point) { 162*a54f2bb7SMarouene Boubakri void **user_ctx = &s->user_ctx; 163*a54f2bb7SMarouene Boubakri uint32_t param_types = 0; 164*a54f2bb7SMarouene Boubakri 165*a54f2bb7SMarouene Boubakri if (ta_sess->param) { 166*a54f2bb7SMarouene Boubakri res = copy_in_param(s, ta_sess->param, tee_param, 167*a54f2bb7SMarouene Boubakri did_map); 168*a54f2bb7SMarouene Boubakri if (res != TEE_SUCCESS) { 169*a54f2bb7SMarouene Boubakri unmap_mapped_param(ta_sess->param, did_map); 170*a54f2bb7SMarouene Boubakri ta_sess->err_origin = TEE_ORIGIN_TEE; 171*a54f2bb7SMarouene Boubakri goto out; 172*a54f2bb7SMarouene Boubakri } 173*a54f2bb7SMarouene Boubakri param_types = ta_sess->param->types; 174*a54f2bb7SMarouene Boubakri } 175*a54f2bb7SMarouene Boubakri 176*a54f2bb7SMarouene Boubakri res = stc->pseudo_ta->open_session_entry_point(param_types, 177*a54f2bb7SMarouene Boubakri tee_param, 178*a54f2bb7SMarouene Boubakri user_ctx); 179*a54f2bb7SMarouene Boubakri if (ta_sess->param) { 180*a54f2bb7SMarouene Boubakri update_out_param(tee_param, ta_sess->param); 181*a54f2bb7SMarouene Boubakri unmap_mapped_param(ta_sess->param, did_map); 182*a54f2bb7SMarouene Boubakri } 183*a54f2bb7SMarouene Boubakri } 184*a54f2bb7SMarouene Boubakri 185*a54f2bb7SMarouene Boubakri out: 186*a54f2bb7SMarouene Boubakri ts_pop_current_session(); 187*a54f2bb7SMarouene Boubakri return res; 188*a54f2bb7SMarouene Boubakri } 189*a54f2bb7SMarouene Boubakri 190*a54f2bb7SMarouene Boubakri static TEE_Result pseudo_ta_enter_invoke_cmd(struct ts_session *s, uint32_t cmd) 191*a54f2bb7SMarouene Boubakri { 192*a54f2bb7SMarouene Boubakri TEE_Result res = TEE_SUCCESS; 193*a54f2bb7SMarouene Boubakri struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx); 194*a54f2bb7SMarouene Boubakri struct tee_ta_session *ta_sess = to_ta_session(s); 195*a54f2bb7SMarouene Boubakri uint32_t param_types = 0; 196*a54f2bb7SMarouene Boubakri TEE_Param tee_param[TEE_NUM_PARAMS] = { }; 197*a54f2bb7SMarouene Boubakri bool did_map[TEE_NUM_PARAMS] = { false }; 198*a54f2bb7SMarouene Boubakri 199*a54f2bb7SMarouene Boubakri ts_push_current_session(s); 200*a54f2bb7SMarouene Boubakri if (ta_sess->param) { 201*a54f2bb7SMarouene Boubakri res = copy_in_param(s, ta_sess->param, tee_param, did_map); 202*a54f2bb7SMarouene Boubakri if (res != TEE_SUCCESS) { 203*a54f2bb7SMarouene Boubakri unmap_mapped_param(ta_sess->param, did_map); 204*a54f2bb7SMarouene Boubakri ta_sess->err_origin = TEE_ORIGIN_TEE; 205*a54f2bb7SMarouene Boubakri goto out; 206*a54f2bb7SMarouene Boubakri } 207*a54f2bb7SMarouene Boubakri param_types = ta_sess->param->types; 208*a54f2bb7SMarouene Boubakri } 209*a54f2bb7SMarouene Boubakri 210*a54f2bb7SMarouene Boubakri ta_sess->err_origin = TEE_ORIGIN_TRUSTED_APP; 211*a54f2bb7SMarouene Boubakri res = stc->pseudo_ta->invoke_command_entry_point(s->user_ctx, cmd, 212*a54f2bb7SMarouene Boubakri param_types, 213*a54f2bb7SMarouene Boubakri tee_param); 214*a54f2bb7SMarouene Boubakri if (ta_sess->param) { 215*a54f2bb7SMarouene Boubakri update_out_param(tee_param, ta_sess->param); 216*a54f2bb7SMarouene Boubakri unmap_mapped_param(ta_sess->param, did_map); 217*a54f2bb7SMarouene Boubakri } 218*a54f2bb7SMarouene Boubakri out: 219*a54f2bb7SMarouene Boubakri ts_pop_current_session(); 220*a54f2bb7SMarouene Boubakri return res; 221*a54f2bb7SMarouene Boubakri } 222*a54f2bb7SMarouene Boubakri 223*a54f2bb7SMarouene Boubakri static void pseudo_ta_enter_close_session(struct ts_session *s) 224*a54f2bb7SMarouene Boubakri { 225*a54f2bb7SMarouene Boubakri struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx); 226*a54f2bb7SMarouene Boubakri void *user_ctx = s->user_ctx; 227*a54f2bb7SMarouene Boubakri 228*a54f2bb7SMarouene Boubakri ts_push_current_session(s); 229*a54f2bb7SMarouene Boubakri 230*a54f2bb7SMarouene Boubakri if (stc->pseudo_ta->close_session_entry_point) 231*a54f2bb7SMarouene Boubakri stc->pseudo_ta->close_session_entry_point(user_ctx); 232*a54f2bb7SMarouene Boubakri 233*a54f2bb7SMarouene Boubakri if (stc->ctx.ref_count == 1 && stc->pseudo_ta->destroy_entry_point) 234*a54f2bb7SMarouene Boubakri stc->pseudo_ta->destroy_entry_point(); 235*a54f2bb7SMarouene Boubakri 236*a54f2bb7SMarouene Boubakri ts_pop_current_session(); 237*a54f2bb7SMarouene Boubakri } 238*a54f2bb7SMarouene Boubakri 239*a54f2bb7SMarouene Boubakri static void pseudo_ta_destroy(struct ts_ctx *ctx) 240*a54f2bb7SMarouene Boubakri { 241*a54f2bb7SMarouene Boubakri free(to_pseudo_ta_ctx(ctx)); 242*a54f2bb7SMarouene Boubakri } 243*a54f2bb7SMarouene Boubakri 244*a54f2bb7SMarouene Boubakri static const struct ts_ops pseudo_ta_ops = { 245*a54f2bb7SMarouene Boubakri .enter_open_session = pseudo_ta_enter_open_session, 246*a54f2bb7SMarouene Boubakri .enter_invoke_cmd = pseudo_ta_enter_invoke_cmd, 247*a54f2bb7SMarouene Boubakri .enter_close_session = pseudo_ta_enter_close_session, 248*a54f2bb7SMarouene Boubakri .destroy = pseudo_ta_destroy, 249*a54f2bb7SMarouene Boubakri }; 250*a54f2bb7SMarouene Boubakri 251*a54f2bb7SMarouene Boubakri bool is_pseudo_ta_ctx(struct ts_ctx *ctx) 252*a54f2bb7SMarouene Boubakri { 253*a54f2bb7SMarouene Boubakri return ctx->ops == &pseudo_ta_ops; 254*a54f2bb7SMarouene Boubakri } 255*a54f2bb7SMarouene Boubakri 256*a54f2bb7SMarouene Boubakri /* Insures declared pseudo TAs conforms with core expectations */ 257*a54f2bb7SMarouene Boubakri static TEE_Result verify_pseudo_tas_conformance(void) 258*a54f2bb7SMarouene Boubakri { 259*a54f2bb7SMarouene Boubakri const struct pseudo_ta_head *start = 260*a54f2bb7SMarouene Boubakri SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head); 261*a54f2bb7SMarouene Boubakri const struct pseudo_ta_head *end = 262*a54f2bb7SMarouene Boubakri SCATTERED_ARRAY_END(pseudo_tas, struct pseudo_ta_head); 263*a54f2bb7SMarouene Boubakri const struct pseudo_ta_head *pta; 264*a54f2bb7SMarouene Boubakri 265*a54f2bb7SMarouene Boubakri for (pta = start; pta < end; pta++) { 266*a54f2bb7SMarouene Boubakri const struct pseudo_ta_head *pta2; 267*a54f2bb7SMarouene Boubakri 268*a54f2bb7SMarouene Boubakri /* PTAs must all have a specific UUID */ 269*a54f2bb7SMarouene Boubakri for (pta2 = pta + 1; pta2 < end; pta2++) { 270*a54f2bb7SMarouene Boubakri if (!memcmp(&pta->uuid, &pta2->uuid, sizeof(TEE_UUID))) 271*a54f2bb7SMarouene Boubakri goto err; 272*a54f2bb7SMarouene Boubakri } 273*a54f2bb7SMarouene Boubakri 274*a54f2bb7SMarouene Boubakri if (!pta->name || 275*a54f2bb7SMarouene Boubakri (pta->flags & PTA_MANDATORY_FLAGS) != PTA_MANDATORY_FLAGS || 276*a54f2bb7SMarouene Boubakri pta->flags & ~PTA_ALLOWED_FLAGS || 277*a54f2bb7SMarouene Boubakri !pta->invoke_command_entry_point) 278*a54f2bb7SMarouene Boubakri goto err; 279*a54f2bb7SMarouene Boubakri } 280*a54f2bb7SMarouene Boubakri return TEE_SUCCESS; 281*a54f2bb7SMarouene Boubakri err: 282*a54f2bb7SMarouene Boubakri DMSG("pseudo TA error at %p", (void *)pta); 283*a54f2bb7SMarouene Boubakri panic("PTA"); 284*a54f2bb7SMarouene Boubakri } 285*a54f2bb7SMarouene Boubakri 286*a54f2bb7SMarouene Boubakri service_init(verify_pseudo_tas_conformance); 287*a54f2bb7SMarouene Boubakri 288*a54f2bb7SMarouene Boubakri /*----------------------------------------------------------------------------- 289*a54f2bb7SMarouene Boubakri * Initialises a session based on the UUID or ptr to the ta 290*a54f2bb7SMarouene Boubakri * Returns ptr to the session (ta_session) and a TEE_Result 291*a54f2bb7SMarouene Boubakri *---------------------------------------------------------------------------*/ 292*a54f2bb7SMarouene Boubakri TEE_Result tee_ta_init_pseudo_ta_session(const TEE_UUID *uuid, 293*a54f2bb7SMarouene Boubakri struct tee_ta_session *s) 294*a54f2bb7SMarouene Boubakri { 295*a54f2bb7SMarouene Boubakri struct pseudo_ta_ctx *stc = NULL; 296*a54f2bb7SMarouene Boubakri struct tee_ta_ctx *ctx; 297*a54f2bb7SMarouene Boubakri const struct pseudo_ta_head *ta; 298*a54f2bb7SMarouene Boubakri 299*a54f2bb7SMarouene Boubakri DMSG("Lookup pseudo TA %pUl", (void *)uuid); 300*a54f2bb7SMarouene Boubakri 301*a54f2bb7SMarouene Boubakri ta = SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head); 302*a54f2bb7SMarouene Boubakri while (true) { 303*a54f2bb7SMarouene Boubakri if (ta >= SCATTERED_ARRAY_END(pseudo_tas, 304*a54f2bb7SMarouene Boubakri struct pseudo_ta_head)) 305*a54f2bb7SMarouene Boubakri return TEE_ERROR_ITEM_NOT_FOUND; 306*a54f2bb7SMarouene Boubakri if (memcmp(&ta->uuid, uuid, sizeof(TEE_UUID)) == 0) 307*a54f2bb7SMarouene Boubakri break; 308*a54f2bb7SMarouene Boubakri ta++; 309*a54f2bb7SMarouene Boubakri } 310*a54f2bb7SMarouene Boubakri 311*a54f2bb7SMarouene Boubakri /* Load a new TA and create a session */ 312*a54f2bb7SMarouene Boubakri DMSG("Open %s", ta->name); 313*a54f2bb7SMarouene Boubakri stc = calloc(1, sizeof(struct pseudo_ta_ctx)); 314*a54f2bb7SMarouene Boubakri if (!stc) 315*a54f2bb7SMarouene Boubakri return TEE_ERROR_OUT_OF_MEMORY; 316*a54f2bb7SMarouene Boubakri ctx = &stc->ctx; 317*a54f2bb7SMarouene Boubakri 318*a54f2bb7SMarouene Boubakri ctx->ref_count = 1; 319*a54f2bb7SMarouene Boubakri ctx->flags = ta->flags; 320*a54f2bb7SMarouene Boubakri stc->pseudo_ta = ta; 321*a54f2bb7SMarouene Boubakri ctx->ts_ctx.uuid = ta->uuid; 322*a54f2bb7SMarouene Boubakri ctx->ts_ctx.ops = &pseudo_ta_ops; 323*a54f2bb7SMarouene Boubakri 324*a54f2bb7SMarouene Boubakri mutex_lock(&tee_ta_mutex); 325*a54f2bb7SMarouene Boubakri s->ts_sess.ctx = &ctx->ts_ctx; 326*a54f2bb7SMarouene Boubakri TAILQ_INSERT_TAIL(&tee_ctxes, ctx, link); 327*a54f2bb7SMarouene Boubakri mutex_unlock(&tee_ta_mutex); 328*a54f2bb7SMarouene Boubakri 329*a54f2bb7SMarouene Boubakri DMSG("%s : %pUl", stc->pseudo_ta->name, (void *)&ctx->ts_ctx.uuid); 330*a54f2bb7SMarouene Boubakri 331*a54f2bb7SMarouene Boubakri return TEE_SUCCESS; 332*a54f2bb7SMarouene Boubakri } 333