xref: /optee_os/core/kernel/pseudo_ta.c (revision a54f2bb703cea069f79647bb5bf90ac7088bcb99)
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 = &param->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