xref: /optee_os/core/kernel/pseudo_ta.c (revision 956c2d50d60109a6053e14da6ff97d6243ea5d65)
1a54f2bb7SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause
2a54f2bb7SMarouene Boubakri /*
3a54f2bb7SMarouene Boubakri  * Copyright (c) 2014, STMicroelectronics International N.V.
4a54f2bb7SMarouene Boubakri  * Copyright (c) 2015, Linaro Limited
5a54f2bb7SMarouene Boubakri  * Copyright (c) 2020, Arm Limited
6a54f2bb7SMarouene Boubakri  */
7a54f2bb7SMarouene Boubakri #include <initcall.h>
8a54f2bb7SMarouene Boubakri #include <kernel/linker.h>
9a54f2bb7SMarouene Boubakri #include <kernel/panic.h>
10a54f2bb7SMarouene Boubakri #include <kernel/pseudo_ta.h>
11a54f2bb7SMarouene Boubakri #include <kernel/tee_ta_manager.h>
12653409a2SJerome Forissier #include <kernel/user_access.h>
13a54f2bb7SMarouene Boubakri #include <mm/core_memprot.h>
14a54f2bb7SMarouene Boubakri #include <mm/mobj.h>
15a54f2bb7SMarouene Boubakri #include <stdlib.h>
16a54f2bb7SMarouene Boubakri #include <string.h>
17a54f2bb7SMarouene Boubakri #include <trace.h>
18a54f2bb7SMarouene Boubakri #include <types_ext.h>
19a54f2bb7SMarouene Boubakri 
20a54f2bb7SMarouene Boubakri #ifdef CFG_SECURE_DATA_PATH
client_is_secure(struct ts_session * s)21a54f2bb7SMarouene Boubakri static bool client_is_secure(struct ts_session *s)
22a54f2bb7SMarouene Boubakri {
23a54f2bb7SMarouene Boubakri 	/* rely on core entry to have constrained client IDs */
24a54f2bb7SMarouene Boubakri 	if (to_ta_session(s)->clnt_id.login == TEE_LOGIN_TRUSTED_APP)
25a54f2bb7SMarouene Boubakri 		return true;
26a54f2bb7SMarouene Boubakri 
27a54f2bb7SMarouene Boubakri 	return false;
28a54f2bb7SMarouene Boubakri }
29a54f2bb7SMarouene Boubakri 
validate_in_param(struct ts_session * s,struct mobj * mobj)30a54f2bb7SMarouene Boubakri static bool validate_in_param(struct ts_session *s, struct mobj *mobj)
31a54f2bb7SMarouene Boubakri {
32a54f2bb7SMarouene Boubakri 	/* Supplying NULL to query buffer size is OK */
33a54f2bb7SMarouene Boubakri 	if (!mobj)
34a54f2bb7SMarouene Boubakri 		return true;
35a54f2bb7SMarouene Boubakri 
36a54f2bb7SMarouene Boubakri 	/* for secure clients, core entry always holds valid memref objects */
37a54f2bb7SMarouene Boubakri 	if (client_is_secure(s))
38a54f2bb7SMarouene Boubakri 		return true;
39a54f2bb7SMarouene Boubakri 
40a54f2bb7SMarouene Boubakri 	/* all non-secure memory references are handled by PTAs */
41a54f2bb7SMarouene Boubakri 	if (mobj_is_nonsec(mobj))
42a54f2bb7SMarouene Boubakri 		return true;
43a54f2bb7SMarouene Boubakri 
44a54f2bb7SMarouene Boubakri 	return false;
45a54f2bb7SMarouene Boubakri }
46a54f2bb7SMarouene Boubakri #else
validate_in_param(struct ts_session * s __unused,struct mobj * mobj __unused)47a54f2bb7SMarouene Boubakri static bool validate_in_param(struct ts_session *s __unused,
48a54f2bb7SMarouene Boubakri 			      struct mobj *mobj __unused)
49a54f2bb7SMarouene Boubakri {
50a54f2bb7SMarouene Boubakri 	/* At this point, core has filled only valid accessible memref mobj */
51a54f2bb7SMarouene Boubakri 	return true;
52a54f2bb7SMarouene Boubakri }
53a54f2bb7SMarouene Boubakri #endif
54a54f2bb7SMarouene Boubakri 
55a54f2bb7SMarouene Boubakri /* Maps pseudo TA params */
copy_in_param(struct ts_session * s __maybe_unused,struct tee_ta_param * param,TEE_Param tee_param[TEE_NUM_PARAMS],bool did_map[TEE_NUM_PARAMS])56a54f2bb7SMarouene Boubakri static TEE_Result copy_in_param(struct ts_session *s __maybe_unused,
57a54f2bb7SMarouene Boubakri 				struct tee_ta_param *param,
58a54f2bb7SMarouene Boubakri 				TEE_Param tee_param[TEE_NUM_PARAMS],
59a54f2bb7SMarouene Boubakri 				bool did_map[TEE_NUM_PARAMS])
60a54f2bb7SMarouene Boubakri {
61a54f2bb7SMarouene Boubakri 	size_t n;
62a54f2bb7SMarouene Boubakri 	void *va;
63a54f2bb7SMarouene Boubakri 	struct param_mem *mem;
64a54f2bb7SMarouene Boubakri 
65a54f2bb7SMarouene Boubakri 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
66a54f2bb7SMarouene Boubakri 		switch (TEE_PARAM_TYPE_GET(param->types, n)) {
67a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_VALUE_INPUT:
68a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
69a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_VALUE_INOUT:
70a54f2bb7SMarouene Boubakri 			tee_param[n].value.a = param->u[n].val.a;
71a54f2bb7SMarouene Boubakri 			tee_param[n].value.b = param->u[n].val.b;
72a54f2bb7SMarouene Boubakri 			break;
73a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_MEMREF_INPUT:
74a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
75a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_MEMREF_INOUT:
76a54f2bb7SMarouene Boubakri 			mem = &param->u[n].mem;
77a54f2bb7SMarouene Boubakri 			if (!validate_in_param(s, mem->mobj))
78a54f2bb7SMarouene Boubakri 				return TEE_ERROR_BAD_PARAMETERS;
79a54f2bb7SMarouene Boubakri 			if (mem->size) {
80a54f2bb7SMarouene Boubakri 				TEE_Result res = mobj_inc_map(mem->mobj);
81a54f2bb7SMarouene Boubakri 
82a54f2bb7SMarouene Boubakri 				if (res)
83a54f2bb7SMarouene Boubakri 					return res;
84a54f2bb7SMarouene Boubakri 				did_map[n] = true;
859c4aaf67SJens Wiklander 				va = mobj_get_va(mem->mobj, mem->offs,
869c4aaf67SJens Wiklander 						 mem->size);
87a54f2bb7SMarouene Boubakri 				if (!va)
88a54f2bb7SMarouene Boubakri 					return TEE_ERROR_BAD_PARAMETERS;
89a54f2bb7SMarouene Boubakri 			} else {
90a54f2bb7SMarouene Boubakri 				va = NULL;
91a54f2bb7SMarouene Boubakri 			}
92a54f2bb7SMarouene Boubakri 
93a54f2bb7SMarouene Boubakri 			tee_param[n].memref.buffer = va;
94a54f2bb7SMarouene Boubakri 			tee_param[n].memref.size = mem->size;
95a54f2bb7SMarouene Boubakri 			break;
96a54f2bb7SMarouene Boubakri 		default:
97a54f2bb7SMarouene Boubakri 			memset(tee_param + n, 0, sizeof(TEE_Param));
98a54f2bb7SMarouene Boubakri 			break;
99a54f2bb7SMarouene Boubakri 		}
100a54f2bb7SMarouene Boubakri 	}
101a54f2bb7SMarouene Boubakri 
102a54f2bb7SMarouene Boubakri 	return TEE_SUCCESS;
103a54f2bb7SMarouene Boubakri }
104a54f2bb7SMarouene Boubakri 
update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS],struct tee_ta_param * param)105a54f2bb7SMarouene Boubakri static void update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS],
106a54f2bb7SMarouene Boubakri 			     struct tee_ta_param *param)
107a54f2bb7SMarouene Boubakri {
108a54f2bb7SMarouene Boubakri 	size_t n;
109a54f2bb7SMarouene Boubakri 
110a54f2bb7SMarouene Boubakri 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
111a54f2bb7SMarouene Boubakri 		switch (TEE_PARAM_TYPE_GET(param->types, n)) {
112a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
113a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_VALUE_INOUT:
114a54f2bb7SMarouene Boubakri 			param->u[n].val.a = tee_param[n].value.a;
115a54f2bb7SMarouene Boubakri 			param->u[n].val.b = tee_param[n].value.b;
116a54f2bb7SMarouene Boubakri 			break;
117a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
118a54f2bb7SMarouene Boubakri 		case TEE_PARAM_TYPE_MEMREF_INOUT:
119a54f2bb7SMarouene Boubakri 			param->u[n].mem.size = tee_param[n].memref.size;
120a54f2bb7SMarouene Boubakri 			break;
121a54f2bb7SMarouene Boubakri 		default:
122a54f2bb7SMarouene Boubakri 			break;
123a54f2bb7SMarouene Boubakri 		}
124a54f2bb7SMarouene Boubakri 	}
125a54f2bb7SMarouene Boubakri }
126a54f2bb7SMarouene Boubakri 
unmap_mapped_param(struct tee_ta_param * param,bool did_map[TEE_NUM_PARAMS])127a54f2bb7SMarouene Boubakri static void unmap_mapped_param(struct tee_ta_param *param,
128a54f2bb7SMarouene Boubakri 			       bool did_map[TEE_NUM_PARAMS])
129a54f2bb7SMarouene Boubakri {
130a54f2bb7SMarouene Boubakri 	size_t n;
131a54f2bb7SMarouene Boubakri 
132a54f2bb7SMarouene Boubakri 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
133a54f2bb7SMarouene Boubakri 		if (did_map[n]) {
134a54f2bb7SMarouene Boubakri 			TEE_Result res __maybe_unused;
135a54f2bb7SMarouene Boubakri 
136a54f2bb7SMarouene Boubakri 			res = mobj_dec_map(param->u[n].mem.mobj);
137a54f2bb7SMarouene Boubakri 			assert(!res);
138a54f2bb7SMarouene Boubakri 		}
139a54f2bb7SMarouene Boubakri 	}
140a54f2bb7SMarouene Boubakri }
141a54f2bb7SMarouene Boubakri 
pseudo_ta_enter_open_session(struct ts_session * s)142a54f2bb7SMarouene Boubakri static TEE_Result pseudo_ta_enter_open_session(struct ts_session *s)
143a54f2bb7SMarouene Boubakri {
144a54f2bb7SMarouene Boubakri 	TEE_Result res = TEE_SUCCESS;
145a54f2bb7SMarouene Boubakri 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
146a54f2bb7SMarouene Boubakri 	struct tee_ta_session *ta_sess = to_ta_session(s);
147a54f2bb7SMarouene Boubakri 	TEE_Param tee_param[TEE_NUM_PARAMS] = { };
148a54f2bb7SMarouene Boubakri 	bool did_map[TEE_NUM_PARAMS] = { false };
149a54f2bb7SMarouene Boubakri 
150a54f2bb7SMarouene Boubakri 	ts_push_current_session(s);
151a54f2bb7SMarouene Boubakri 	ta_sess->err_origin = TEE_ORIGIN_TRUSTED_APP;
152a54f2bb7SMarouene Boubakri 
153a54f2bb7SMarouene Boubakri 	if (stc->ctx.ref_count == 1 && stc->pseudo_ta->create_entry_point) {
154a54f2bb7SMarouene Boubakri 		res = stc->pseudo_ta->create_entry_point();
155a54f2bb7SMarouene Boubakri 		if (res != TEE_SUCCESS)
156a54f2bb7SMarouene Boubakri 			goto out;
157a54f2bb7SMarouene Boubakri 	}
158a54f2bb7SMarouene Boubakri 
159a54f2bb7SMarouene Boubakri 	if (stc->pseudo_ta->open_session_entry_point) {
160a54f2bb7SMarouene Boubakri 		void **user_ctx = &s->user_ctx;
161a54f2bb7SMarouene Boubakri 		uint32_t param_types = 0;
162a54f2bb7SMarouene Boubakri 
163a54f2bb7SMarouene Boubakri 		if (ta_sess->param) {
164a54f2bb7SMarouene Boubakri 			res = copy_in_param(s, ta_sess->param, tee_param,
165a54f2bb7SMarouene Boubakri 					    did_map);
166a54f2bb7SMarouene Boubakri 			if (res != TEE_SUCCESS) {
167a54f2bb7SMarouene Boubakri 				unmap_mapped_param(ta_sess->param, did_map);
168a54f2bb7SMarouene Boubakri 				ta_sess->err_origin = TEE_ORIGIN_TEE;
169a54f2bb7SMarouene Boubakri 				goto out;
170a54f2bb7SMarouene Boubakri 			}
171a54f2bb7SMarouene Boubakri 			param_types = ta_sess->param->types;
172a54f2bb7SMarouene Boubakri 		}
173a54f2bb7SMarouene Boubakri 
174a54f2bb7SMarouene Boubakri 		res = stc->pseudo_ta->open_session_entry_point(param_types,
175a54f2bb7SMarouene Boubakri 							       tee_param,
176a54f2bb7SMarouene Boubakri 							       user_ctx);
177a54f2bb7SMarouene Boubakri 		if (ta_sess->param) {
178a54f2bb7SMarouene Boubakri 			update_out_param(tee_param, ta_sess->param);
179a54f2bb7SMarouene Boubakri 			unmap_mapped_param(ta_sess->param, did_map);
180a54f2bb7SMarouene Boubakri 		}
181a54f2bb7SMarouene Boubakri 	}
182a54f2bb7SMarouene Boubakri 
183a54f2bb7SMarouene Boubakri out:
184a54f2bb7SMarouene Boubakri 	ts_pop_current_session();
185a54f2bb7SMarouene Boubakri 	return res;
186a54f2bb7SMarouene Boubakri }
187a54f2bb7SMarouene Boubakri 
pseudo_ta_enter_invoke_cmd(struct ts_session * s,uint32_t cmd)188a54f2bb7SMarouene Boubakri static TEE_Result pseudo_ta_enter_invoke_cmd(struct ts_session *s, uint32_t cmd)
189a54f2bb7SMarouene Boubakri {
190a54f2bb7SMarouene Boubakri 	TEE_Result res = TEE_SUCCESS;
191a54f2bb7SMarouene Boubakri 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
192a54f2bb7SMarouene Boubakri 	struct tee_ta_session *ta_sess = to_ta_session(s);
193a54f2bb7SMarouene Boubakri 	uint32_t param_types = 0;
194a54f2bb7SMarouene Boubakri 	TEE_Param tee_param[TEE_NUM_PARAMS] = { };
195a54f2bb7SMarouene Boubakri 	bool did_map[TEE_NUM_PARAMS] = { false };
196a54f2bb7SMarouene Boubakri 
197a54f2bb7SMarouene Boubakri 	ts_push_current_session(s);
198a54f2bb7SMarouene Boubakri 	if (ta_sess->param) {
199a54f2bb7SMarouene Boubakri 		res = copy_in_param(s, ta_sess->param, tee_param, did_map);
200a54f2bb7SMarouene Boubakri 		if (res != TEE_SUCCESS) {
201a54f2bb7SMarouene Boubakri 			unmap_mapped_param(ta_sess->param, did_map);
202a54f2bb7SMarouene Boubakri 			ta_sess->err_origin = TEE_ORIGIN_TEE;
203a54f2bb7SMarouene Boubakri 			goto out;
204a54f2bb7SMarouene Boubakri 		}
205a54f2bb7SMarouene Boubakri 		param_types = ta_sess->param->types;
206a54f2bb7SMarouene Boubakri 	}
207a54f2bb7SMarouene Boubakri 
208a54f2bb7SMarouene Boubakri 	ta_sess->err_origin = TEE_ORIGIN_TRUSTED_APP;
209a54f2bb7SMarouene Boubakri 	res = stc->pseudo_ta->invoke_command_entry_point(s->user_ctx, cmd,
210a54f2bb7SMarouene Boubakri 							 param_types,
211a54f2bb7SMarouene Boubakri 							 tee_param);
212a54f2bb7SMarouene Boubakri 	if (ta_sess->param) {
213a54f2bb7SMarouene Boubakri 		update_out_param(tee_param, ta_sess->param);
214a54f2bb7SMarouene Boubakri 		unmap_mapped_param(ta_sess->param, did_map);
215a54f2bb7SMarouene Boubakri 	}
216a54f2bb7SMarouene Boubakri out:
217a54f2bb7SMarouene Boubakri 	ts_pop_current_session();
218a54f2bb7SMarouene Boubakri 	return res;
219a54f2bb7SMarouene Boubakri }
220a54f2bb7SMarouene Boubakri 
pseudo_ta_enter_close_session(struct ts_session * s)221a54f2bb7SMarouene Boubakri static void pseudo_ta_enter_close_session(struct ts_session *s)
222a54f2bb7SMarouene Boubakri {
223a54f2bb7SMarouene Boubakri 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
224a54f2bb7SMarouene Boubakri 	void *user_ctx = s->user_ctx;
225a54f2bb7SMarouene Boubakri 
226a54f2bb7SMarouene Boubakri 	ts_push_current_session(s);
227a54f2bb7SMarouene Boubakri 
228a54f2bb7SMarouene Boubakri 	if (stc->pseudo_ta->close_session_entry_point)
229a54f2bb7SMarouene Boubakri 		stc->pseudo_ta->close_session_entry_point(user_ctx);
230a54f2bb7SMarouene Boubakri 
231a54f2bb7SMarouene Boubakri 	if (stc->ctx.ref_count == 1 && stc->pseudo_ta->destroy_entry_point)
232a54f2bb7SMarouene Boubakri 		stc->pseudo_ta->destroy_entry_point();
233a54f2bb7SMarouene Boubakri 
234a54f2bb7SMarouene Boubakri 	ts_pop_current_session();
235a54f2bb7SMarouene Boubakri }
236a54f2bb7SMarouene Boubakri 
pseudo_ta_destroy(struct ts_ctx * ctx)237a54f2bb7SMarouene Boubakri static void pseudo_ta_destroy(struct ts_ctx *ctx)
238a54f2bb7SMarouene Boubakri {
239a54f2bb7SMarouene Boubakri 	free(to_pseudo_ta_ctx(ctx));
240a54f2bb7SMarouene Boubakri }
241a54f2bb7SMarouene Boubakri 
242a54f2bb7SMarouene Boubakri static const struct ts_ops pseudo_ta_ops = {
243a54f2bb7SMarouene Boubakri 	.enter_open_session = pseudo_ta_enter_open_session,
244a54f2bb7SMarouene Boubakri 	.enter_invoke_cmd = pseudo_ta_enter_invoke_cmd,
245a54f2bb7SMarouene Boubakri 	.enter_close_session = pseudo_ta_enter_close_session,
246a54f2bb7SMarouene Boubakri 	.destroy = pseudo_ta_destroy,
247a54f2bb7SMarouene Boubakri };
248a54f2bb7SMarouene Boubakri 
is_pseudo_ta_ctx(struct ts_ctx * ctx)2490a75d408SJens Wiklander bool __noprof is_pseudo_ta_ctx(struct ts_ctx *ctx)
250a54f2bb7SMarouene Boubakri {
251a54f2bb7SMarouene Boubakri 	return ctx->ops == &pseudo_ta_ops;
252a54f2bb7SMarouene Boubakri }
253a54f2bb7SMarouene Boubakri 
254a54f2bb7SMarouene Boubakri /* Insures declared pseudo TAs conforms with core expectations */
verify_pseudo_tas_conformance(void)255a54f2bb7SMarouene Boubakri static TEE_Result verify_pseudo_tas_conformance(void)
256a54f2bb7SMarouene Boubakri {
257a54f2bb7SMarouene Boubakri 	const struct pseudo_ta_head *start =
258a54f2bb7SMarouene Boubakri 		SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head);
259a54f2bb7SMarouene Boubakri 	const struct pseudo_ta_head *end =
260a54f2bb7SMarouene Boubakri 		SCATTERED_ARRAY_END(pseudo_tas, struct pseudo_ta_head);
261a54f2bb7SMarouene Boubakri 	const struct pseudo_ta_head *pta;
262a54f2bb7SMarouene Boubakri 
263a54f2bb7SMarouene Boubakri 	for (pta = start; pta < end; pta++) {
264a54f2bb7SMarouene Boubakri 		const struct pseudo_ta_head *pta2;
265a54f2bb7SMarouene Boubakri 
266a54f2bb7SMarouene Boubakri 		/* PTAs must all have a specific UUID */
267a54f2bb7SMarouene Boubakri 		for (pta2 = pta + 1; pta2 < end; pta2++) {
268a54f2bb7SMarouene Boubakri 			if (!memcmp(&pta->uuid, &pta2->uuid, sizeof(TEE_UUID)))
269a54f2bb7SMarouene Boubakri 				goto err;
270a54f2bb7SMarouene Boubakri 		}
271a54f2bb7SMarouene Boubakri 
272a54f2bb7SMarouene Boubakri 		if (!pta->name ||
273a54f2bb7SMarouene Boubakri 		    (pta->flags & PTA_MANDATORY_FLAGS) != PTA_MANDATORY_FLAGS ||
274a54f2bb7SMarouene Boubakri 		    pta->flags & ~PTA_ALLOWED_FLAGS ||
275a54f2bb7SMarouene Boubakri 		    !pta->invoke_command_entry_point)
276a54f2bb7SMarouene Boubakri 			goto err;
277a54f2bb7SMarouene Boubakri 	}
278a54f2bb7SMarouene Boubakri 	return TEE_SUCCESS;
279a54f2bb7SMarouene Boubakri err:
280a54f2bb7SMarouene Boubakri 	DMSG("pseudo TA error at %p", (void *)pta);
281a54f2bb7SMarouene Boubakri 	panic("PTA");
282a54f2bb7SMarouene Boubakri }
283a54f2bb7SMarouene Boubakri 
284a54f2bb7SMarouene Boubakri service_init(verify_pseudo_tas_conformance);
285a54f2bb7SMarouene Boubakri 
286a54f2bb7SMarouene Boubakri /*-----------------------------------------------------------------------------
287a54f2bb7SMarouene Boubakri  * Initialises a session based on the UUID or ptr to the ta
288a54f2bb7SMarouene Boubakri  * Returns ptr to the session (ta_session) and a TEE_Result
289a54f2bb7SMarouene Boubakri  *---------------------------------------------------------------------------*/
tee_ta_init_pseudo_ta_session(const TEE_UUID * uuid,struct tee_ta_session * s)290a54f2bb7SMarouene Boubakri TEE_Result tee_ta_init_pseudo_ta_session(const TEE_UUID *uuid,
291a54f2bb7SMarouene Boubakri 			struct tee_ta_session *s)
292a54f2bb7SMarouene Boubakri {
293a54f2bb7SMarouene Boubakri 	struct pseudo_ta_ctx *stc = NULL;
294a54f2bb7SMarouene Boubakri 	struct tee_ta_ctx *ctx;
295a54f2bb7SMarouene Boubakri 	const struct pseudo_ta_head *ta;
296a54f2bb7SMarouene Boubakri 
297*956c2d50SEtienne Carriere 	/*
298*956c2d50SEtienne Carriere 	 * Caller is expected to hold tee_ta_mutex for safe changes
299*956c2d50SEtienne Carriere 	 * in @s and registering of the context in tee_ctxes list.
300*956c2d50SEtienne Carriere 	 */
301*956c2d50SEtienne Carriere 	assert(mutex_is_locked(&tee_ta_mutex));
302*956c2d50SEtienne Carriere 
303a54f2bb7SMarouene Boubakri 	DMSG("Lookup pseudo TA %pUl", (void *)uuid);
304a54f2bb7SMarouene Boubakri 
305a54f2bb7SMarouene Boubakri 	ta = SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head);
306a54f2bb7SMarouene Boubakri 	while (true) {
307a54f2bb7SMarouene Boubakri 		if (ta >= SCATTERED_ARRAY_END(pseudo_tas,
308a54f2bb7SMarouene Boubakri 					      struct pseudo_ta_head))
309a54f2bb7SMarouene Boubakri 			return TEE_ERROR_ITEM_NOT_FOUND;
310a54f2bb7SMarouene Boubakri 		if (memcmp(&ta->uuid, uuid, sizeof(TEE_UUID)) == 0)
311a54f2bb7SMarouene Boubakri 			break;
312a54f2bb7SMarouene Boubakri 		ta++;
313a54f2bb7SMarouene Boubakri 	}
314a54f2bb7SMarouene Boubakri 
315a54f2bb7SMarouene Boubakri 	DMSG("Open %s", ta->name);
316a54f2bb7SMarouene Boubakri 	stc = calloc(1, sizeof(struct pseudo_ta_ctx));
317a54f2bb7SMarouene Boubakri 	if (!stc)
318a54f2bb7SMarouene Boubakri 		return TEE_ERROR_OUT_OF_MEMORY;
319a54f2bb7SMarouene Boubakri 	ctx = &stc->ctx;
320a54f2bb7SMarouene Boubakri 
321a54f2bb7SMarouene Boubakri 	ctx->ref_count = 1;
322a54f2bb7SMarouene Boubakri 	ctx->flags = ta->flags;
323a54f2bb7SMarouene Boubakri 	stc->pseudo_ta = ta;
324a54f2bb7SMarouene Boubakri 	ctx->ts_ctx.uuid = ta->uuid;
325a54f2bb7SMarouene Boubakri 	ctx->ts_ctx.ops = &pseudo_ta_ops;
326a54f2bb7SMarouene Boubakri 
327a54f2bb7SMarouene Boubakri 	s->ts_sess.ctx = &ctx->ts_ctx;
328a54f2bb7SMarouene Boubakri 	TAILQ_INSERT_TAIL(&tee_ctxes, ctx, link);
329a54f2bb7SMarouene Boubakri 
330a54f2bb7SMarouene Boubakri 	DMSG("%s : %pUl", stc->pseudo_ta->name, (void *)&ctx->ts_ctx.uuid);
331a54f2bb7SMarouene Boubakri 
332a54f2bb7SMarouene Boubakri 	return TEE_SUCCESS;
333a54f2bb7SMarouene Boubakri }
334653409a2SJerome Forissier 
to_bounce_params(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS],TEE_Param bparams[TEE_NUM_PARAMS],TEE_Param ** oparams)335653409a2SJerome Forissier TEE_Result to_bounce_params(uint32_t param_types,
336653409a2SJerome Forissier 			    TEE_Param params[TEE_NUM_PARAMS],
337653409a2SJerome Forissier 			    TEE_Param bparams[TEE_NUM_PARAMS],
338653409a2SJerome Forissier 			    TEE_Param **oparams)
339653409a2SJerome Forissier {
340653409a2SJerome Forissier 	TEE_Result res = TEE_ERROR_GENERIC;
341653409a2SJerome Forissier 	void *kptr = NULL;
342653409a2SJerome Forissier 	void *uptr = NULL;
343653409a2SJerome Forissier 	size_t size = 0;
344653409a2SJerome Forissier 	int i = 0;
345653409a2SJerome Forissier 
346653409a2SJerome Forissier 	if (!is_caller_ta_with_pan()) {
347653409a2SJerome Forissier 		*oparams = params;
348653409a2SJerome Forissier 		return TEE_SUCCESS;
349653409a2SJerome Forissier 	}
350653409a2SJerome Forissier 
351653409a2SJerome Forissier 	for (i = 0; i < TEE_NUM_PARAMS; i++) {
352653409a2SJerome Forissier 		switch (TEE_PARAM_TYPE_GET(param_types, i)) {
353653409a2SJerome Forissier 		case TEE_PARAM_TYPE_MEMREF_INPUT:
354653409a2SJerome Forissier 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
355653409a2SJerome Forissier 		case TEE_PARAM_TYPE_MEMREF_INOUT:
356653409a2SJerome Forissier 			size = params[i].memref.size;
357653409a2SJerome Forissier 			uptr = params[i].memref.buffer;
358653409a2SJerome Forissier 			kptr = bb_alloc(size);
359653409a2SJerome Forissier 			if (!kptr)
360653409a2SJerome Forissier 				return TEE_ERROR_OUT_OF_MEMORY;
361653409a2SJerome Forissier 			bparams[i].memref.buffer = kptr;
362653409a2SJerome Forissier 			bparams[i].memref.size = size;
363653409a2SJerome Forissier 			break;
364653409a2SJerome Forissier 		default:
365653409a2SJerome Forissier 			break;
366653409a2SJerome Forissier 		}
367653409a2SJerome Forissier 		switch (TEE_PARAM_TYPE_GET(param_types, i)) {
368653409a2SJerome Forissier 		case TEE_PARAM_TYPE_MEMREF_INPUT:
369653409a2SJerome Forissier 		case TEE_PARAM_TYPE_MEMREF_INOUT:
370653409a2SJerome Forissier 			res = copy_from_user(kptr, uptr, size);
371653409a2SJerome Forissier 			if (res)
372653409a2SJerome Forissier 				return res;
373653409a2SJerome Forissier 			break;
374653409a2SJerome Forissier 		case TEE_PARAM_TYPE_VALUE_INPUT:
375653409a2SJerome Forissier 		case TEE_PARAM_TYPE_VALUE_INOUT:
376653409a2SJerome Forissier 			bparams[i].value.a = params[i].value.a;
377653409a2SJerome Forissier 			bparams[i].value.b = params[i].value.b;
378653409a2SJerome Forissier 			break;
379653409a2SJerome Forissier 		default:
380653409a2SJerome Forissier 			break;
381653409a2SJerome Forissier 		}
382653409a2SJerome Forissier 	}
383653409a2SJerome Forissier 	*oparams = bparams;
384653409a2SJerome Forissier 
385653409a2SJerome Forissier 	return TEE_SUCCESS;
386653409a2SJerome Forissier }
387653409a2SJerome Forissier 
from_bounce_params(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS],TEE_Param bparams[TEE_NUM_PARAMS],TEE_Param * eparams)388653409a2SJerome Forissier TEE_Result from_bounce_params(uint32_t param_types,
389653409a2SJerome Forissier 			      TEE_Param params[TEE_NUM_PARAMS],
390653409a2SJerome Forissier 			      TEE_Param bparams[TEE_NUM_PARAMS],
391653409a2SJerome Forissier 			      TEE_Param *eparams)
392653409a2SJerome Forissier {
393653409a2SJerome Forissier 	TEE_Result res = TEE_ERROR_GENERIC;
394653409a2SJerome Forissier 	void *kptr = NULL;
395653409a2SJerome Forissier 	void *uptr = NULL;
396653409a2SJerome Forissier 	size_t size = 0;
397653409a2SJerome Forissier 	int i = 0;
398653409a2SJerome Forissier 
399653409a2SJerome Forissier 	if (eparams == params)
400653409a2SJerome Forissier 		return TEE_SUCCESS;
401653409a2SJerome Forissier 
402653409a2SJerome Forissier 	for (i = 0; i < TEE_NUM_PARAMS; i++) {
403653409a2SJerome Forissier 		switch (TEE_PARAM_TYPE_GET(param_types, i)) {
404653409a2SJerome Forissier 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
405653409a2SJerome Forissier 		case TEE_PARAM_TYPE_MEMREF_INOUT:
406653409a2SJerome Forissier 			uptr = params[i].memref.buffer;
407653409a2SJerome Forissier 			kptr = bparams[i].memref.buffer;
408653409a2SJerome Forissier 			size = bparams[i].memref.size;
409653409a2SJerome Forissier 			res = copy_to_user(uptr, kptr, size);
410653409a2SJerome Forissier 			if (res)
411653409a2SJerome Forissier 				return res;
412653409a2SJerome Forissier 			params[i].memref.size = size;
413653409a2SJerome Forissier 			break;
414653409a2SJerome Forissier 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
415653409a2SJerome Forissier 		case TEE_PARAM_TYPE_VALUE_INOUT:
416653409a2SJerome Forissier 			params[i].value.a = bparams[i].value.a;
417653409a2SJerome Forissier 			params[i].value.b = bparams[i].value.b;
418653409a2SJerome Forissier 			break;
419653409a2SJerome Forissier 		default:
420653409a2SJerome Forissier 			break;
421653409a2SJerome Forissier 		}
422653409a2SJerome Forissier 	}
423653409a2SJerome Forissier 
424653409a2SJerome Forissier 	return res;
425653409a2SJerome Forissier }
426