xref: /optee_os/core/tee/entry_std.c (revision 8cb985ee7921d85dff2aae98d438999d4ebca5b8)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015-2016, Linaro Limited
4  * Copyright (c) 2014, STMicroelectronics International N.V.
5  */
6 
7 #include <assert.h>
8 #include <compiler.h>
9 #include <initcall.h>
10 #include <io.h>
11 #include <kernel/linker.h>
12 #include <kernel/msg_param.h>
13 #include <kernel/notif.h>
14 #include <kernel/panic.h>
15 #include <kernel/tee_misc.h>
16 #include <mm/core_memprot.h>
17 #include <mm/core_mmu.h>
18 #include <mm/mobj.h>
19 #include <optee_msg.h>
20 #include <string.h>
21 #include <tee/entry_std.h>
22 #include <tee/tee_cryp_utl.h>
23 #include <tee/uuid.h>
24 #include <util.h>
25 
26 #ifdef CFG_CORE_FFA
27 #include <kernel/thread_spmc.h>
28 #endif
29 
30 #define SHM_CACHE_ATTRS	\
31 	(uint32_t)(core_mmu_is_shm_cached() ? \
32 		   TEE_MATTR_MEM_TYPE_CACHED : TEE_MATTR_MEM_TYPE_DEV)
33 
34 /* Sessions opened from normal world */
35 static struct tee_ta_session_head tee_open_sessions =
36 TAILQ_HEAD_INITIALIZER(tee_open_sessions);
37 
38 #ifdef CFG_CORE_RESERVED_SHM
39 static struct mobj *shm_mobj;
40 #endif
41 #ifdef CFG_SECURE_DATA_PATH
42 static struct mobj **sdp_mem_mobjs;
43 #endif
44 
45 static unsigned int session_pnum;
46 
param_mem_from_mobj(struct param_mem * mem,struct mobj * mobj,const paddr_t pa,const size_t sz)47 static bool __maybe_unused param_mem_from_mobj(struct param_mem *mem,
48 					       struct mobj *mobj,
49 					       const paddr_t pa,
50 					       const size_t sz)
51 {
52 	paddr_t b;
53 
54 	if (mobj_get_pa(mobj, 0, 0, &b) != TEE_SUCCESS)
55 		panic("mobj_get_pa failed");
56 
57 	if (!core_is_buffer_inside(pa, MAX(sz, 1UL), b, mobj->size))
58 		return false;
59 
60 	mem->mobj = mobj_get(mobj);
61 	mem->offs = pa - b;
62 	mem->size = sz;
63 	return true;
64 }
65 
66 #ifdef CFG_CORE_FFA
set_fmem_param(const struct optee_msg_param_fmem * fmem,struct param_mem * mem)67 static TEE_Result set_fmem_param(const struct optee_msg_param_fmem *fmem,
68 				 struct param_mem *mem)
69 {
70 	size_t req_size = 0;
71 	uint64_t global_id = READ_ONCE(fmem->global_id);
72 	size_t sz = READ_ONCE(fmem->size);
73 
74 	if (global_id == OPTEE_MSG_FMEM_INVALID_GLOBAL_ID && !sz) {
75 		mem->mobj = NULL;
76 		mem->offs = 0;
77 		mem->size = 0;
78 		return TEE_SUCCESS;
79 	}
80 	mem->mobj = mobj_ffa_get_by_cookie(global_id,
81 					   READ_ONCE(fmem->internal_offs));
82 	if (!mem->mobj)
83 		return TEE_ERROR_BAD_PARAMETERS;
84 
85 	mem->offs = reg_pair_to_64(READ_ONCE(fmem->offs_high),
86 				   READ_ONCE(fmem->offs_low));
87 	mem->size = sz;
88 
89 	/*
90 	 * Check that the supplied offset and size is covered by the
91 	 * previously verified MOBJ.
92 	 */
93 	if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) ||
94 	    mem->mobj->size < req_size)
95 		return TEE_ERROR_SECURITY;
96 
97 	return TEE_SUCCESS;
98 }
99 #else /*!CFG_CORE_FFA*/
100 /* fill 'struct param_mem' structure if buffer matches a valid memory object */
set_tmem_param(const struct optee_msg_param_tmem * tmem,uint32_t attr,struct param_mem * mem)101 static TEE_Result set_tmem_param(const struct optee_msg_param_tmem *tmem,
102 				 uint32_t attr, struct param_mem *mem)
103 {
104 	struct mobj __maybe_unused **mobj = NULL;
105 	paddr_t pa = READ_ONCE(tmem->buf_ptr);
106 	size_t sz = READ_ONCE(tmem->size);
107 	struct mobj *rmobj = NULL;
108 
109 	/*
110 	 * Handle NULL memory reference
111 	 */
112 	if (!pa) {
113 		mem->mobj = NULL;
114 		mem->offs = 0;
115 		mem->size = 0;
116 		return TEE_SUCCESS;
117 	}
118 
119 	/* Handle non-contiguous reference from a shared memory area */
120 	if (attr & OPTEE_MSG_ATTR_NONCONTIG) {
121 		uint64_t shm_ref = READ_ONCE(tmem->shm_ref);
122 
123 		mem->mobj = msg_param_mobj_from_noncontig(pa, sz, shm_ref,
124 							  false);
125 		if (!mem->mobj)
126 			return TEE_ERROR_BAD_PARAMETERS;
127 		mem->offs = 0;
128 		mem->size = sz;
129 		return TEE_SUCCESS;
130 	}
131 
132 #ifdef CFG_CORE_RESERVED_SHM
133 	/* Handle memory reference in the contiguous shared memory */
134 	if (param_mem_from_mobj(mem, shm_mobj, pa, sz))
135 		return TEE_SUCCESS;
136 #endif
137 
138 #ifdef CFG_SECURE_DATA_PATH
139 	/* Handle memory reference to Secure Data Path memory areas */
140 	for (mobj = sdp_mem_mobjs; *mobj; mobj++)
141 		if (param_mem_from_mobj(mem, *mobj, pa, sz))
142 			return TEE_SUCCESS;
143 #endif
144 	rmobj = mobj_protmem_get_by_pa(pa, sz);
145 	if (rmobj) {
146 		bool rc = param_mem_from_mobj(mem, rmobj, pa, sz);
147 
148 		mobj_put(rmobj);
149 		if (rc)
150 			return TEE_SUCCESS;
151 	}
152 
153 	return TEE_ERROR_BAD_PARAMETERS;
154 }
155 
156 #ifdef CFG_CORE_DYN_SHM
set_rmem_param(const struct optee_msg_param_rmem * rmem,struct param_mem * mem)157 static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem,
158 				 struct param_mem *mem)
159 {
160 	size_t req_size = 0;
161 	uint64_t shm_ref = READ_ONCE(rmem->shm_ref);
162 	size_t sz = READ_ONCE(rmem->size);
163 
164 	mem->mobj = mobj_reg_shm_get_by_cookie(shm_ref);
165 	if (!mem->mobj)
166 		return TEE_ERROR_BAD_PARAMETERS;
167 
168 	mem->offs = READ_ONCE(rmem->offs);
169 	mem->size = sz;
170 
171 	/*
172 	 * Check that the supplied offset and size is covered by the
173 	 * previously verified MOBJ.
174 	 */
175 	if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) ||
176 	    mem->mobj->size < req_size)
177 		return TEE_ERROR_SECURITY;
178 
179 	return TEE_SUCCESS;
180 }
181 #endif /*CFG_CORE_DYN_SHM*/
182 #endif /*!CFG_CORE_FFA*/
183 
copy_in_params(const struct optee_msg_param * params,uint32_t num_params,struct tee_ta_param * ta_param,uint64_t * saved_attr)184 static TEE_Result copy_in_params(const struct optee_msg_param *params,
185 				 uint32_t num_params,
186 				 struct tee_ta_param *ta_param,
187 				 uint64_t *saved_attr)
188 {
189 	TEE_Result res;
190 	size_t n;
191 	uint8_t pt[TEE_NUM_PARAMS] = { 0 };
192 
193 	if (num_params > TEE_NUM_PARAMS)
194 		return TEE_ERROR_BAD_PARAMETERS;
195 
196 	memset(ta_param, 0, sizeof(*ta_param));
197 
198 	for (n = 0; n < num_params; n++) {
199 		uint32_t attr;
200 
201 		saved_attr[n] = READ_ONCE(params[n].attr);
202 
203 		if (saved_attr[n] & OPTEE_MSG_ATTR_META)
204 			return TEE_ERROR_BAD_PARAMETERS;
205 
206 		attr = saved_attr[n] & OPTEE_MSG_ATTR_TYPE_MASK;
207 		switch (attr) {
208 		case OPTEE_MSG_ATTR_TYPE_NONE:
209 			pt[n] = TEE_PARAM_TYPE_NONE;
210 			break;
211 		case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
212 		case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
213 		case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
214 			pt[n] = TEE_PARAM_TYPE_VALUE_INPUT + attr -
215 				OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
216 			ta_param->u[n].val.a = READ_ONCE(params[n].u.value.a);
217 			ta_param->u[n].val.b = READ_ONCE(params[n].u.value.b);
218 			break;
219 #ifdef CFG_CORE_FFA
220 		case OPTEE_MSG_ATTR_TYPE_FMEM_INPUT:
221 		case OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT:
222 		case OPTEE_MSG_ATTR_TYPE_FMEM_INOUT:
223 			res = set_fmem_param(&params[n].u.fmem,
224 					     &ta_param->u[n].mem);
225 			if (res)
226 				return res;
227 			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
228 				OPTEE_MSG_ATTR_TYPE_FMEM_INPUT;
229 			break;
230 #else /*!CFG_CORE_FFA*/
231 		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
232 		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
233 		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
234 			res = set_tmem_param(&params[n].u.tmem, saved_attr[n],
235 					     &ta_param->u[n].mem);
236 			if (res)
237 				return res;
238 			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
239 				OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
240 			break;
241 #ifdef CFG_CORE_DYN_SHM
242 		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
243 		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
244 		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
245 			res = set_rmem_param(&params[n].u.rmem,
246 					     &ta_param->u[n].mem);
247 			if (res)
248 				return res;
249 			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
250 				OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
251 			break;
252 #endif /*CFG_CORE_DYN_SHM*/
253 #endif /*!CFG_CORE_FFA*/
254 		default:
255 			return TEE_ERROR_BAD_PARAMETERS;
256 		}
257 	}
258 
259 	ta_param->types = TEE_PARAM_TYPES(pt[0], pt[1], pt[2], pt[3]);
260 
261 	return TEE_SUCCESS;
262 }
263 
cleanup_shm_refs(const uint64_t * saved_attr,struct tee_ta_param * param,uint32_t num_params)264 static void cleanup_shm_refs(const uint64_t *saved_attr,
265 			     struct tee_ta_param *param, uint32_t num_params)
266 {
267 	size_t n;
268 
269 	for (n = 0; n < MIN((unsigned int)TEE_NUM_PARAMS, num_params); n++) {
270 		switch (saved_attr[n]) {
271 		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
272 		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
273 		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
274 #ifdef CFG_CORE_DYN_SHM
275 		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
276 		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
277 		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
278 #endif
279 			mobj_put(param->u[n].mem.mobj);
280 			break;
281 		default:
282 			break;
283 		}
284 	}
285 }
286 
copy_out_param(struct tee_ta_param * ta_param,uint32_t num_params,struct optee_msg_param * params,uint64_t * saved_attr)287 static void copy_out_param(struct tee_ta_param *ta_param, uint32_t num_params,
288 			   struct optee_msg_param *params, uint64_t *saved_attr)
289 {
290 	size_t n;
291 
292 	for (n = 0; n < num_params; n++) {
293 		switch (TEE_PARAM_TYPE_GET(ta_param->types, n)) {
294 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
295 		case TEE_PARAM_TYPE_MEMREF_INOUT:
296 			switch (saved_attr[n] & OPTEE_MSG_ATTR_TYPE_MASK) {
297 			case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
298 			case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
299 				params[n].u.tmem.size = ta_param->u[n].mem.size;
300 				break;
301 			case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
302 			case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
303 				params[n].u.rmem.size = ta_param->u[n].mem.size;
304 				break;
305 			default:
306 				break;
307 			}
308 			break;
309 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
310 		case TEE_PARAM_TYPE_VALUE_INOUT:
311 			params[n].u.value.a = ta_param->u[n].val.a;
312 			params[n].u.value.b = ta_param->u[n].val.b;
313 			break;
314 		default:
315 			break;
316 		}
317 	}
318 }
319 
320 /*
321  * Extracts mandatory parameter for open session.
322  *
323  * Returns
324  * false : mandatory parameter wasn't found or malformatted
325  * true  : paramater found and OK
326  */
get_open_session_meta(size_t num_params,struct optee_msg_param * params,size_t * num_meta,TEE_UUID * uuid,TEE_Identity * clnt_id)327 static TEE_Result get_open_session_meta(size_t num_params,
328 					struct optee_msg_param *params,
329 					size_t *num_meta, TEE_UUID *uuid,
330 					TEE_Identity *clnt_id)
331 {
332 	const uint32_t req_attr = OPTEE_MSG_ATTR_META |
333 				  OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
334 
335 	if (num_params < 2)
336 		return TEE_ERROR_BAD_PARAMETERS;
337 
338 	if (params[0].attr != req_attr || params[1].attr != req_attr)
339 		return TEE_ERROR_BAD_PARAMETERS;
340 
341 	tee_uuid_from_octets(uuid, (void *)&params[0].u.value);
342 	clnt_id->login = params[1].u.value.c;
343 	switch (clnt_id->login) {
344 	case TEE_LOGIN_PUBLIC:
345 	case TEE_LOGIN_REE_KERNEL:
346 		memset(&clnt_id->uuid, 0, sizeof(clnt_id->uuid));
347 		break;
348 	case TEE_LOGIN_USER:
349 	case TEE_LOGIN_GROUP:
350 	case TEE_LOGIN_APPLICATION:
351 	case TEE_LOGIN_APPLICATION_USER:
352 	case TEE_LOGIN_APPLICATION_GROUP:
353 		tee_uuid_from_octets(&clnt_id->uuid,
354 				     (void *)&params[1].u.value);
355 		break;
356 	default:
357 		return TEE_ERROR_BAD_PARAMETERS;
358 	}
359 
360 	*num_meta = 2;
361 	return TEE_SUCCESS;
362 }
363 
entry_open_session(struct optee_msg_arg * arg,uint32_t num_params)364 static void entry_open_session(struct optee_msg_arg *arg, uint32_t num_params)
365 {
366 	TEE_Result res = TEE_ERROR_GENERIC;
367 	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
368 	uint32_t sess_id = 0;
369 	TEE_Identity clnt_id = { };
370 	TEE_UUID uuid = { };
371 	struct tee_ta_param param = { };
372 	size_t num_meta = 0;
373 	uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 };
374 
375 	res = get_open_session_meta(num_params, arg->params, &num_meta, &uuid,
376 				    &clnt_id);
377 	if (res != TEE_SUCCESS)
378 		goto out;
379 
380 	res = copy_in_params(arg->params + num_meta, num_params - num_meta,
381 			     &param, saved_attr);
382 	if (res != TEE_SUCCESS)
383 		goto cleanup_shm_refs;
384 
385 	res = tee_ta_open_session(&err_orig, &sess_id, &tee_open_sessions,
386 				  &uuid, &clnt_id, TEE_TIMEOUT_INFINITE,
387 				  &param);
388 	if (res)
389 		sess_id = 0;
390 	copy_out_param(&param, num_params - num_meta, arg->params + num_meta,
391 		       saved_attr);
392 
393 	/*
394 	 * The occurrence of open/close session command is usually
395 	 * un-predictable, using this property to increase randomness
396 	 * of prng
397 	 */
398 	plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
399 				     &session_pnum);
400 
401 cleanup_shm_refs:
402 	cleanup_shm_refs(saved_attr, &param, num_params - num_meta);
403 
404 out:
405 	arg->session = sess_id;
406 	arg->ret = res;
407 	arg->ret_origin = err_orig;
408 }
409 
entry_close_session(struct optee_msg_arg * arg,uint32_t num_params)410 static void entry_close_session(struct optee_msg_arg *arg, uint32_t num_params)
411 {
412 	TEE_Result res = TEE_SUCCESS;
413 
414 	if (num_params) {
415 		res = TEE_ERROR_BAD_PARAMETERS;
416 		goto out;
417 	}
418 
419 	plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
420 				     &session_pnum);
421 
422 	res = tee_ta_close_session(arg->session, &tee_open_sessions,
423 				   NSAPP_IDENTITY);
424 out:
425 	arg->ret = res;
426 	arg->ret_origin = TEE_ORIGIN_TEE;
427 }
428 
entry_invoke_command(struct optee_msg_arg * arg,uint32_t num_params)429 static void entry_invoke_command(struct optee_msg_arg *arg, uint32_t num_params)
430 {
431 	TEE_Result res;
432 	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
433 	struct tee_ta_session *s;
434 	struct tee_ta_param param = { 0 };
435 	uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 };
436 
437 	res = copy_in_params(arg->params, num_params, &param, saved_attr);
438 	if (res != TEE_SUCCESS)
439 		goto out;
440 
441 	s = tee_ta_get_session(arg->session, true, &tee_open_sessions);
442 	if (!s) {
443 		res = TEE_ERROR_BAD_PARAMETERS;
444 		goto out;
445 	}
446 
447 	res = tee_ta_invoke_command(&err_orig, s, NSAPP_IDENTITY,
448 				    TEE_TIMEOUT_INFINITE, arg->func, &param);
449 
450 	tee_ta_put_session(s);
451 
452 	copy_out_param(&param, num_params, arg->params, saved_attr);
453 
454 out:
455 	cleanup_shm_refs(saved_attr, &param, num_params);
456 
457 	arg->ret = res;
458 	arg->ret_origin = err_orig;
459 }
460 
entry_cancel(struct optee_msg_arg * arg,uint32_t num_params)461 static void entry_cancel(struct optee_msg_arg *arg, uint32_t num_params)
462 {
463 	TEE_Result res;
464 	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
465 	struct tee_ta_session *s;
466 
467 	if (num_params) {
468 		res = TEE_ERROR_BAD_PARAMETERS;
469 		goto out;
470 	}
471 
472 	s = tee_ta_get_session(arg->session, false, &tee_open_sessions);
473 	if (!s) {
474 		res = TEE_ERROR_BAD_PARAMETERS;
475 		goto out;
476 	}
477 
478 	res = tee_ta_cancel_command(&err_orig, s, NSAPP_IDENTITY);
479 	tee_ta_put_session(s);
480 
481 out:
482 	arg->ret = res;
483 	arg->ret_origin = err_orig;
484 }
485 
486 #ifndef CFG_CORE_FFA
487 #ifdef CFG_CORE_DYN_SHM
register_shm(struct optee_msg_arg * arg,uint32_t num_params)488 static void register_shm(struct optee_msg_arg *arg, uint32_t num_params)
489 {
490 	struct optee_msg_param_tmem *tmem = NULL;
491 	struct mobj *mobj = NULL;
492 
493 	arg->ret = TEE_ERROR_BAD_PARAMETERS;
494 
495 	if (num_params != 1 ||
496 	    (arg->params[0].attr !=
497 	     (OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT | OPTEE_MSG_ATTR_NONCONTIG)))
498 		return;
499 
500 	tmem = &arg->params[0].u.tmem;
501 	mobj = msg_param_mobj_from_noncontig(tmem->buf_ptr, tmem->size,
502 					     tmem->shm_ref, false);
503 
504 	if (!mobj)
505 		return;
506 
507 	mobj_reg_shm_unguard(mobj);
508 	arg->ret = TEE_SUCCESS;
509 }
510 
unregister_shm(struct optee_msg_arg * arg,uint32_t num_params)511 static void unregister_shm(struct optee_msg_arg *arg, uint32_t num_params)
512 {
513 	if (num_params == 1) {
514 		uint64_t cookie = arg->params[0].u.rmem.shm_ref;
515 		TEE_Result res = mobj_reg_shm_release_by_cookie(cookie);
516 
517 		if (res)
518 			EMSG("Can't find mapping with given cookie");
519 		arg->ret = res;
520 	} else {
521 		arg->ret = TEE_ERROR_BAD_PARAMETERS;
522 		arg->ret_origin = TEE_ORIGIN_TEE;
523 	}
524 }
525 #endif /*CFG_CORE_DYN_SHM*/
526 #endif
527 
lend_protmem(struct optee_msg_arg * arg,uint32_t num_params)528 static void __maybe_unused lend_protmem(struct optee_msg_arg *arg,
529 					uint32_t num_params)
530 {
531 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
532 	struct optee_msg_param_tmem *tmem = NULL;
533 	struct mobj *mobj = NULL;
534 	uint64_t use_case = 0;
535 	uint64_t cookie = 0;
536 	paddr_size_t sz = 0;
537 	paddr_t pa = 0;
538 
539 	if (num_params != 2 ||
540 	    READ_ONCE(arg->params[0].attr) != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT ||
541 	    READ_ONCE(arg->params[1].attr) != OPTEE_MSG_ATTR_TYPE_TMEM_INPUT)
542 		goto out;
543 
544 	use_case = READ_ONCE(arg->params[0].u.value.a);
545 	tmem = &arg->params[1].u.tmem;
546 	cookie = READ_ONCE(tmem->shm_ref);
547 	pa = READ_ONCE(tmem->buf_ptr);
548 	sz = READ_ONCE(tmem->size);
549 
550 	switch (use_case) {
551 	case MOBJ_USE_CASE_SEC_VIDEO_PLAY:
552 	case MOBJ_USE_CASE_TRUSED_UI:
553 		break;
554 	default:
555 		goto out;
556 	}
557 	mobj = mobj_protmem_alloc(pa, sz, cookie, use_case);
558 	if (mobj)
559 		res = TEE_SUCCESS;
560 out:
561 	arg->ret = res;
562 }
563 
assign_protmem(struct optee_msg_arg * arg,uint32_t num_params)564 static void __maybe_unused assign_protmem(struct optee_msg_arg *arg,
565 					  uint32_t num_params)
566 {
567 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
568 	uint64_t use_case = 0;
569 	uint64_t cookie = 0;
570 
571 	if (num_params != 1 ||
572 	    READ_ONCE(arg->params[0].attr) != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
573 		goto out;
574 
575 	cookie = READ_ONCE(arg->params[0].u.value.a);
576 	use_case = READ_ONCE(arg->params[0].u.value.b);
577 	res = mobj_ffa_assign_protmem(cookie, use_case);
578 out:
579 	arg->ret = res;
580 }
581 
reclaim_protmem(struct optee_msg_arg * arg,uint32_t num_params)582 static void __maybe_unused reclaim_protmem(struct optee_msg_arg *arg,
583 					   uint32_t num_params)
584 {
585 	if (num_params == 1 &&
586 	    READ_ONCE(arg->params[0].attr) == OPTEE_MSG_ATTR_TYPE_RMEM_INPUT) {
587 		uint64_t cookie = READ_ONCE(arg->params[0].u.rmem.shm_ref);
588 		TEE_Result res = mobj_protmem_release_by_cookie(cookie);
589 
590 		if (res)
591 			EMSG("Can't find mapping with cookie %#"PRIx64,
592 			     cookie);
593 		arg->ret = res;
594 	} else {
595 		arg->ret = TEE_ERROR_BAD_PARAMETERS;
596 		arg->ret_origin = TEE_ORIGIN_TEE;
597 	}
598 }
599 
get_protmem_config(struct optee_msg_arg * arg,uint32_t num_params)600 static void __maybe_unused get_protmem_config(struct optee_msg_arg *arg,
601 					      uint32_t num_params)
602 {
603 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
604 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
605 					  TEE_PARAM_TYPE_NONE,
606 					  TEE_PARAM_TYPE_NONE);
607 	uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 };
608 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
609 	struct tee_ta_param param = { 0 };
610 	size_t min_mem_align = 0;
611 	size_t min_mem_sz = 0;
612 	uint64_t use_case = 0;
613 	void *buf = NULL;
614 	size_t sz = 0;
615 
616 	arg->ret_origin = TEE_ORIGIN_TEE;
617 
618 	if (num_params != 2)
619 		goto out;
620 	res = copy_in_params(arg->params, num_params, &param, saved_attr);
621 	if (res)
622 		goto out;
623 	if (param.types != exp_pt) {
624 		res = TEE_ERROR_BAD_PARAMETERS;
625 		goto out_cleanup;
626 	}
627 
628 	use_case = param.u[0].val.a;
629 	/* Check that it's not truncated when passed as an enum */
630 	if (use_case >= INT_MAX) {
631 		res = TEE_ERROR_BAD_PARAMETERS;
632 		goto out_cleanup;
633 	}
634 	sz = param.u[1].mem.size;
635 	if (param.u[1].mem.mobj) {
636 		res = mobj_inc_map(param.u[1].mem.mobj);
637 		if (res)
638 			goto out_cleanup;
639 		buf = mobj_get_va(param.u[1].mem.mobj, param.u[1].mem.offs, sz);
640 		if (!buf) {
641 			res = TEE_ERROR_BAD_PARAMETERS;
642 			goto out_dec_map;
643 		}
644 	}
645 
646 	if (IS_ENABLED(CFG_CORE_FFA)) {
647 #ifdef CFG_CORE_FFA
648 		res = thread_spmc_get_protmem_config(use_case, buf, &sz,
649 						     &min_mem_sz,
650 						     &min_mem_align);
651 #else
652 		res = TEE_ERROR_NOT_SUPPORTED;
653 #endif
654 	} else {
655 		res = plat_get_protmem_config(use_case, &min_mem_sz,
656 					      &min_mem_align);
657 	}
658 	if (!res || res == TEE_ERROR_SHORT_BUFFER) {
659 		param.u[1].mem.size = sz;
660 		param.u[0].val.a = min_mem_sz;
661 		param.u[0].val.b = min_mem_align;
662 	}
663 	copy_out_param(&param, num_params, arg->params, saved_attr);
664 	arg->params[0].u.value.c = sizeof(long) * 8;
665 
666 out_dec_map:
667 	mobj_dec_map(param.u[1].mem.mobj);
668 out_cleanup:
669 	cleanup_shm_refs(saved_attr, &param, num_params);
670 out:
671 	arg->ret = res;
672 }
673 
nsec_sessions_list_head(struct tee_ta_session_head ** open_sessions)674 void nsec_sessions_list_head(struct tee_ta_session_head **open_sessions)
675 {
676 	*open_sessions = &tee_open_sessions;
677 }
678 
679 /* Note: this function is weak to let platforms add special handling */
tee_entry_std(struct optee_msg_arg * arg,uint32_t num_params)680 TEE_Result __weak tee_entry_std(struct optee_msg_arg *arg, uint32_t num_params)
681 {
682 	return __tee_entry_std(arg, num_params);
683 }
684 
685 /*
686  * If tee_entry_std() is overridden, it's still supposed to call this
687  * function.
688  */
__tee_entry_std(struct optee_msg_arg * arg,uint32_t num_params)689 TEE_Result __tee_entry_std(struct optee_msg_arg *arg, uint32_t num_params)
690 {
691 	TEE_Result res = TEE_SUCCESS;
692 
693 	/* Enable foreign interrupts for STD calls */
694 	thread_set_foreign_intr(true);
695 	switch (arg->cmd) {
696 	case OPTEE_MSG_CMD_OPEN_SESSION:
697 		entry_open_session(arg, num_params);
698 		break;
699 	case OPTEE_MSG_CMD_CLOSE_SESSION:
700 		entry_close_session(arg, num_params);
701 		break;
702 	case OPTEE_MSG_CMD_INVOKE_COMMAND:
703 		entry_invoke_command(arg, num_params);
704 		break;
705 	case OPTEE_MSG_CMD_CANCEL:
706 		entry_cancel(arg, num_params);
707 		break;
708 #if defined(CFG_CORE_DYN_SHM) && !defined(CFG_CORE_FFA)
709 	case OPTEE_MSG_CMD_REGISTER_SHM:
710 		register_shm(arg, num_params);
711 		break;
712 	case OPTEE_MSG_CMD_UNREGISTER_SHM:
713 		unregister_shm(arg, num_params);
714 		break;
715 #endif
716 	case OPTEE_MSG_CMD_DO_BOTTOM_HALF:
717 		if (IS_ENABLED(CFG_CORE_ASYNC_NOTIF))
718 			notif_deliver_event(NOTIF_EVENT_DO_BOTTOM_HALF);
719 		else
720 			goto err;
721 		break;
722 	case OPTEE_MSG_CMD_STOP_ASYNC_NOTIF:
723 		if (IS_ENABLED(CFG_CORE_ASYNC_NOTIF))
724 			notif_deliver_event(NOTIF_EVENT_STOPPED);
725 		else
726 			goto err;
727 		break;
728 #ifdef CFG_CORE_DYN_PROTMEM
729 	case OPTEE_MSG_CMD_GET_PROTMEM_CONFIG:
730 		get_protmem_config(arg, num_params);
731 		break;
732 #ifdef CFG_CORE_FFA
733 	case OPTEE_MSG_CMD_ASSIGN_PROTMEM:
734 		assign_protmem(arg, num_params);
735 		break;
736 #else
737 	case OPTEE_MSG_CMD_LEND_PROTMEM:
738 		lend_protmem(arg, num_params);
739 		break;
740 	case OPTEE_MSG_CMD_RECLAIM_PROTMEM:
741 		reclaim_protmem(arg, num_params);
742 		break;
743 #endif /*!CFG_CORE_FFA*/
744 #endif /*CFG_CORE_DYN_PROTMEM*/
745 	default:
746 err:
747 		EMSG("Unknown cmd 0x%x", arg->cmd);
748 		res = TEE_ERROR_NOT_IMPLEMENTED;
749 	}
750 
751 	return res;
752 }
753 
default_mobj_init(void)754 static TEE_Result default_mobj_init(void)
755 {
756 #ifdef CFG_CORE_RESERVED_SHM
757 	shm_mobj = mobj_phys_alloc(default_nsec_shm_paddr,
758 				   default_nsec_shm_size, SHM_CACHE_ATTRS,
759 				   CORE_MEM_NSEC_SHM);
760 	if (!shm_mobj)
761 		panic("Failed to register shared memory");
762 #endif
763 
764 #ifdef CFG_SECURE_DATA_PATH
765 	sdp_mem_mobjs = core_sdp_mem_create_mobjs();
766 	if (!sdp_mem_mobjs)
767 		panic("Failed to register SDP memory");
768 #endif
769 
770 	return TEE_SUCCESS;
771 }
772 
773 driver_init_late(default_mobj_init);
774