xref: /optee_os/core/tee/entry_std.c (revision d8158fea038d1facdf879563ab5e56a2fe92aa4f)
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 <bench.h>
9 #include <compiler.h>
10 #include <initcall.h>
11 #include <io.h>
12 #include <kernel/linker.h>
13 #include <kernel/msg_param.h>
14 #include <kernel/notif.h>
15 #include <kernel/panic.h>
16 #include <kernel/tee_misc.h>
17 #include <mm/core_memprot.h>
18 #include <mm/core_mmu.h>
19 #include <mm/mobj.h>
20 #include <optee_msg.h>
21 #include <sm/optee_smc.h>
22 #include <string.h>
23 #include <tee/entry_std.h>
24 #include <tee/tee_cryp_utl.h>
25 #include <tee/uuid.h>
26 #include <util.h>
27 
28 #define SHM_CACHE_ATTRS	\
29 	(uint32_t)(core_mmu_is_shm_cached() ? \
30 		   TEE_MATTR_CACHE_CACHED : TEE_MATTR_CACHE_NONCACHE)
31 
32 /* Sessions opened from normal world */
33 static struct tee_ta_session_head tee_open_sessions =
34 TAILQ_HEAD_INITIALIZER(tee_open_sessions);
35 
36 #ifdef CFG_CORE_RESERVED_SHM
37 static struct mobj *shm_mobj;
38 #endif
39 #ifdef CFG_SECURE_DATA_PATH
40 static struct mobj **sdp_mem_mobjs;
41 #endif
42 
43 static unsigned int session_pnum;
44 
45 static bool __maybe_unused param_mem_from_mobj(struct param_mem *mem,
46 					       struct mobj *mobj,
47 					       const paddr_t pa,
48 					       const size_t sz)
49 {
50 	paddr_t b;
51 
52 	if (mobj_get_pa(mobj, 0, 0, &b) != TEE_SUCCESS)
53 		panic("mobj_get_pa failed");
54 
55 	if (!core_is_buffer_inside(pa, MAX(sz, 1UL), b, mobj->size))
56 		return false;
57 
58 	mem->mobj = mobj_get(mobj);
59 	mem->offs = pa - b;
60 	mem->size = sz;
61 	return true;
62 }
63 
64 #ifdef CFG_CORE_FFA
65 static TEE_Result set_fmem_param(const struct optee_msg_param_fmem *fmem,
66 				 struct param_mem *mem)
67 {
68 	size_t req_size = 0;
69 	uint64_t global_id = READ_ONCE(fmem->global_id);
70 	size_t sz = READ_ONCE(fmem->size);
71 
72 	if (global_id == OPTEE_MSG_FMEM_INVALID_GLOBAL_ID && !sz) {
73 		mem->mobj = NULL;
74 		mem->offs = 0;
75 		mem->size = 0;
76 		return TEE_SUCCESS;
77 	}
78 	mem->mobj = mobj_ffa_get_by_cookie(global_id,
79 					   READ_ONCE(fmem->internal_offs));
80 	if (!mem->mobj)
81 		return TEE_ERROR_BAD_PARAMETERS;
82 
83 	mem->offs = reg_pair_to_64(READ_ONCE(fmem->offs_high),
84 				   READ_ONCE(fmem->offs_low));
85 	mem->size = sz;
86 
87 	/*
88 	 * Check that the supplied offset and size is covered by the
89 	 * previously verified MOBJ.
90 	 */
91 	if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) ||
92 	    mem->mobj->size < req_size)
93 		return TEE_ERROR_SECURITY;
94 
95 	return TEE_SUCCESS;
96 }
97 #else /*!CFG_CORE_FFA*/
98 /* fill 'struct param_mem' structure if buffer matches a valid memory object */
99 static TEE_Result set_tmem_param(const struct optee_msg_param_tmem *tmem,
100 				 uint32_t attr, struct param_mem *mem)
101 {
102 	struct mobj __maybe_unused **mobj;
103 	paddr_t pa = READ_ONCE(tmem->buf_ptr);
104 	size_t sz = READ_ONCE(tmem->size);
105 
106 	/*
107 	 * Handle NULL memory reference
108 	 */
109 	if (!pa) {
110 		mem->mobj = NULL;
111 		mem->offs = 0;
112 		mem->size = 0;
113 		return TEE_SUCCESS;
114 	}
115 
116 	/* Handle non-contiguous reference from a shared memory area */
117 	if (attr & OPTEE_MSG_ATTR_NONCONTIG) {
118 		uint64_t shm_ref = READ_ONCE(tmem->shm_ref);
119 
120 		mem->mobj = msg_param_mobj_from_noncontig(pa, sz, shm_ref,
121 							  false);
122 		if (!mem->mobj)
123 			return TEE_ERROR_BAD_PARAMETERS;
124 		mem->offs = 0;
125 		mem->size = sz;
126 		return TEE_SUCCESS;
127 	}
128 
129 #ifdef CFG_CORE_RESERVED_SHM
130 	/* Handle memory reference in the contiguous shared memory */
131 	if (param_mem_from_mobj(mem, shm_mobj, pa, sz))
132 		return TEE_SUCCESS;
133 #endif
134 
135 #ifdef CFG_SECURE_DATA_PATH
136 	/* Handle memory reference to Secure Data Path memory areas */
137 	for (mobj = sdp_mem_mobjs; *mobj; mobj++)
138 		if (param_mem_from_mobj(mem, *mobj, pa, sz))
139 			return TEE_SUCCESS;
140 #endif
141 
142 	return TEE_ERROR_BAD_PARAMETERS;
143 }
144 
145 #ifdef CFG_CORE_DYN_SHM
146 static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem,
147 				 struct param_mem *mem)
148 {
149 	size_t req_size = 0;
150 	uint64_t shm_ref = READ_ONCE(rmem->shm_ref);
151 	size_t sz = READ_ONCE(rmem->size);
152 
153 	mem->mobj = mobj_reg_shm_get_by_cookie(shm_ref);
154 	if (!mem->mobj)
155 		return TEE_ERROR_BAD_PARAMETERS;
156 
157 	mem->offs = READ_ONCE(rmem->offs);
158 	mem->size = sz;
159 
160 	/*
161 	 * Check that the supplied offset and size is covered by the
162 	 * previously verified MOBJ.
163 	 */
164 	if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) ||
165 	    mem->mobj->size < req_size)
166 		return TEE_ERROR_SECURITY;
167 
168 	return TEE_SUCCESS;
169 }
170 #endif /*CFG_CORE_DYN_SHM*/
171 #endif /*!CFG_CORE_FFA*/
172 
173 static TEE_Result copy_in_params(const struct optee_msg_param *params,
174 				 uint32_t num_params,
175 				 struct tee_ta_param *ta_param,
176 				 uint64_t *saved_attr)
177 {
178 	TEE_Result res;
179 	size_t n;
180 	uint8_t pt[TEE_NUM_PARAMS] = { 0 };
181 
182 	if (num_params > TEE_NUM_PARAMS)
183 		return TEE_ERROR_BAD_PARAMETERS;
184 
185 	memset(ta_param, 0, sizeof(*ta_param));
186 
187 	for (n = 0; n < num_params; n++) {
188 		uint32_t attr;
189 
190 		saved_attr[n] = READ_ONCE(params[n].attr);
191 
192 		if (saved_attr[n] & OPTEE_MSG_ATTR_META)
193 			return TEE_ERROR_BAD_PARAMETERS;
194 
195 		attr = saved_attr[n] & OPTEE_MSG_ATTR_TYPE_MASK;
196 		switch (attr) {
197 		case OPTEE_MSG_ATTR_TYPE_NONE:
198 			pt[n] = TEE_PARAM_TYPE_NONE;
199 			break;
200 		case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
201 		case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
202 		case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
203 			pt[n] = TEE_PARAM_TYPE_VALUE_INPUT + attr -
204 				OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
205 			ta_param->u[n].val.a = READ_ONCE(params[n].u.value.a);
206 			ta_param->u[n].val.b = READ_ONCE(params[n].u.value.b);
207 			break;
208 #ifdef CFG_CORE_FFA
209 		case OPTEE_MSG_ATTR_TYPE_FMEM_INPUT:
210 		case OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT:
211 		case OPTEE_MSG_ATTR_TYPE_FMEM_INOUT:
212 			res = set_fmem_param(&params[n].u.fmem,
213 					     &ta_param->u[n].mem);
214 			if (res)
215 				return res;
216 			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
217 				OPTEE_MSG_ATTR_TYPE_FMEM_INPUT;
218 			break;
219 #else /*!CFG_CORE_FFA*/
220 		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
221 		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
222 		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
223 			res = set_tmem_param(&params[n].u.tmem, saved_attr[n],
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_TMEM_INPUT;
229 			break;
230 #ifdef CFG_CORE_DYN_SHM
231 		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
232 		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
233 		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
234 			res = set_rmem_param(&params[n].u.rmem,
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_RMEM_INPUT;
240 			break;
241 #endif /*CFG_CORE_DYN_SHM*/
242 #endif /*!CFG_CORE_FFA*/
243 		default:
244 			return TEE_ERROR_BAD_PARAMETERS;
245 		}
246 	}
247 
248 	ta_param->types = TEE_PARAM_TYPES(pt[0], pt[1], pt[2], pt[3]);
249 
250 	return TEE_SUCCESS;
251 }
252 
253 static void cleanup_shm_refs(const uint64_t *saved_attr,
254 			     struct tee_ta_param *param, uint32_t num_params)
255 {
256 	size_t n;
257 
258 	for (n = 0; n < num_params; n++) {
259 		switch (saved_attr[n]) {
260 		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
261 		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
262 		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
263 #ifdef CFG_CORE_DYN_SHM
264 		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
265 		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
266 		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
267 #endif
268 			mobj_put(param->u[n].mem.mobj);
269 			break;
270 		default:
271 			break;
272 		}
273 	}
274 }
275 
276 static void copy_out_param(struct tee_ta_param *ta_param, uint32_t num_params,
277 			   struct optee_msg_param *params, uint64_t *saved_attr)
278 {
279 	size_t n;
280 
281 	for (n = 0; n < num_params; n++) {
282 		switch (TEE_PARAM_TYPE_GET(ta_param->types, n)) {
283 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
284 		case TEE_PARAM_TYPE_MEMREF_INOUT:
285 			switch (saved_attr[n] & OPTEE_MSG_ATTR_TYPE_MASK) {
286 			case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
287 			case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
288 				params[n].u.tmem.size = ta_param->u[n].mem.size;
289 				break;
290 			case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
291 			case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
292 				params[n].u.rmem.size = ta_param->u[n].mem.size;
293 				break;
294 			default:
295 				break;
296 			}
297 			break;
298 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
299 		case TEE_PARAM_TYPE_VALUE_INOUT:
300 			params[n].u.value.a = ta_param->u[n].val.a;
301 			params[n].u.value.b = ta_param->u[n].val.b;
302 			break;
303 		default:
304 			break;
305 		}
306 	}
307 }
308 
309 /*
310  * Extracts mandatory parameter for open session.
311  *
312  * Returns
313  * false : mandatory parameter wasn't found or malformatted
314  * true  : paramater found and OK
315  */
316 static TEE_Result get_open_session_meta(size_t num_params,
317 					struct optee_msg_param *params,
318 					size_t *num_meta, TEE_UUID *uuid,
319 					TEE_Identity *clnt_id)
320 {
321 	const uint32_t req_attr = OPTEE_MSG_ATTR_META |
322 				  OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
323 
324 	if (num_params < 2)
325 		return TEE_ERROR_BAD_PARAMETERS;
326 
327 	if (params[0].attr != req_attr || params[1].attr != req_attr)
328 		return TEE_ERROR_BAD_PARAMETERS;
329 
330 	tee_uuid_from_octets(uuid, (void *)&params[0].u.value);
331 	clnt_id->login = params[1].u.value.c;
332 	switch (clnt_id->login) {
333 	case TEE_LOGIN_PUBLIC:
334 	case TEE_LOGIN_REE_KERNEL:
335 		memset(&clnt_id->uuid, 0, sizeof(clnt_id->uuid));
336 		break;
337 	case TEE_LOGIN_USER:
338 	case TEE_LOGIN_GROUP:
339 	case TEE_LOGIN_APPLICATION:
340 	case TEE_LOGIN_APPLICATION_USER:
341 	case TEE_LOGIN_APPLICATION_GROUP:
342 		tee_uuid_from_octets(&clnt_id->uuid,
343 				     (void *)&params[1].u.value);
344 		break;
345 	default:
346 		return TEE_ERROR_BAD_PARAMETERS;
347 	}
348 
349 	*num_meta = 2;
350 	return TEE_SUCCESS;
351 }
352 
353 static void entry_open_session(struct optee_msg_arg *arg, uint32_t num_params)
354 {
355 	TEE_Result res;
356 	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
357 	struct tee_ta_session *s = NULL;
358 	TEE_Identity clnt_id;
359 	TEE_UUID uuid;
360 	struct tee_ta_param param;
361 	size_t num_meta;
362 	uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 };
363 
364 	res = get_open_session_meta(num_params, arg->params, &num_meta, &uuid,
365 				    &clnt_id);
366 	if (res != TEE_SUCCESS)
367 		goto out;
368 
369 	res = copy_in_params(arg->params + num_meta, num_params - num_meta,
370 			     &param, saved_attr);
371 	if (res != TEE_SUCCESS)
372 		goto cleanup_shm_refs;
373 
374 	res = tee_ta_open_session(&err_orig, &s, &tee_open_sessions, &uuid,
375 				  &clnt_id, TEE_TIMEOUT_INFINITE, &param);
376 	if (res != TEE_SUCCESS)
377 		s = NULL;
378 	copy_out_param(&param, num_params - num_meta, arg->params + num_meta,
379 		       saved_attr);
380 
381 	/*
382 	 * The occurrence of open/close session command is usually
383 	 * un-predictable, using this property to increase randomness
384 	 * of prng
385 	 */
386 	plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
387 				     &session_pnum);
388 
389 cleanup_shm_refs:
390 	cleanup_shm_refs(saved_attr, &param, num_params - num_meta);
391 
392 out:
393 	if (s)
394 		arg->session = s->id;
395 	else
396 		arg->session = 0;
397 	arg->ret = res;
398 	arg->ret_origin = err_orig;
399 }
400 
401 static void entry_close_session(struct optee_msg_arg *arg, uint32_t num_params)
402 {
403 	TEE_Result res;
404 	struct tee_ta_session *s;
405 
406 	if (num_params) {
407 		res = TEE_ERROR_BAD_PARAMETERS;
408 		goto out;
409 	}
410 
411 	plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
412 				     &session_pnum);
413 
414 	s = tee_ta_find_session(arg->session, &tee_open_sessions);
415 	res = tee_ta_close_session(s, &tee_open_sessions, NSAPP_IDENTITY);
416 out:
417 	arg->ret = res;
418 	arg->ret_origin = TEE_ORIGIN_TEE;
419 }
420 
421 static void entry_invoke_command(struct optee_msg_arg *arg, uint32_t num_params)
422 {
423 	TEE_Result res;
424 	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
425 	struct tee_ta_session *s;
426 	struct tee_ta_param param = { 0 };
427 	uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 };
428 
429 	bm_timestamp();
430 
431 	res = copy_in_params(arg->params, num_params, &param, saved_attr);
432 	if (res != TEE_SUCCESS)
433 		goto out;
434 
435 	s = tee_ta_get_session(arg->session, true, &tee_open_sessions);
436 	if (!s) {
437 		res = TEE_ERROR_BAD_PARAMETERS;
438 		goto out;
439 	}
440 
441 	res = tee_ta_invoke_command(&err_orig, s, NSAPP_IDENTITY,
442 				    TEE_TIMEOUT_INFINITE, arg->func, &param);
443 
444 	bm_timestamp();
445 
446 	tee_ta_put_session(s);
447 
448 	copy_out_param(&param, num_params, arg->params, saved_attr);
449 
450 out:
451 	cleanup_shm_refs(saved_attr, &param, num_params);
452 
453 	arg->ret = res;
454 	arg->ret_origin = err_orig;
455 }
456 
457 static void entry_cancel(struct optee_msg_arg *arg, uint32_t num_params)
458 {
459 	TEE_Result res;
460 	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
461 	struct tee_ta_session *s;
462 
463 	if (num_params) {
464 		res = TEE_ERROR_BAD_PARAMETERS;
465 		goto out;
466 	}
467 
468 	s = tee_ta_get_session(arg->session, false, &tee_open_sessions);
469 	if (!s) {
470 		res = TEE_ERROR_BAD_PARAMETERS;
471 		goto out;
472 	}
473 
474 	res = tee_ta_cancel_command(&err_orig, s, NSAPP_IDENTITY);
475 	tee_ta_put_session(s);
476 
477 out:
478 	arg->ret = res;
479 	arg->ret_origin = err_orig;
480 }
481 
482 #ifndef CFG_CORE_FFA
483 #ifdef CFG_CORE_DYN_SHM
484 static void register_shm(struct optee_msg_arg *arg, uint32_t num_params)
485 {
486 	struct optee_msg_param_tmem *tmem = NULL;
487 	struct mobj *mobj = NULL;
488 
489 	arg->ret = TEE_ERROR_BAD_PARAMETERS;
490 
491 	if (num_params != 1 ||
492 	    (arg->params[0].attr !=
493 	     (OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT | OPTEE_MSG_ATTR_NONCONTIG)))
494 		return;
495 
496 	tmem = &arg->params[0].u.tmem;
497 	mobj = msg_param_mobj_from_noncontig(tmem->buf_ptr, tmem->size,
498 					     tmem->shm_ref, false);
499 
500 	if (!mobj)
501 		return;
502 
503 	mobj_reg_shm_unguard(mobj);
504 	arg->ret = TEE_SUCCESS;
505 }
506 
507 static void unregister_shm(struct optee_msg_arg *arg, uint32_t num_params)
508 {
509 	if (num_params == 1) {
510 		uint64_t cookie = arg->params[0].u.rmem.shm_ref;
511 		TEE_Result res = mobj_reg_shm_release_by_cookie(cookie);
512 
513 		if (res)
514 			EMSG("Can't find mapping with given cookie");
515 		arg->ret = res;
516 	} else {
517 		arg->ret = TEE_ERROR_BAD_PARAMETERS;
518 		arg->ret_origin = TEE_ORIGIN_TEE;
519 	}
520 }
521 #endif /*CFG_CORE_DYN_SHM*/
522 #endif
523 
524 void nsec_sessions_list_head(struct tee_ta_session_head **open_sessions)
525 {
526 	*open_sessions = &tee_open_sessions;
527 }
528 
529 /* Note: this function is weak to let platforms add special handling */
530 uint32_t __weak tee_entry_std(struct optee_msg_arg *arg, uint32_t num_params)
531 {
532 	return __tee_entry_std(arg, num_params);
533 }
534 
535 /*
536  * If tee_entry_std() is overridden, it's still supposed to call this
537  * function.
538  */
539 uint32_t __tee_entry_std(struct optee_msg_arg *arg, uint32_t num_params)
540 {
541 	uint32_t rv = OPTEE_SMC_RETURN_OK;
542 
543 	/* Enable foreign interrupts for STD calls */
544 	thread_set_foreign_intr(true);
545 	switch (arg->cmd) {
546 	case OPTEE_MSG_CMD_OPEN_SESSION:
547 		entry_open_session(arg, num_params);
548 		break;
549 	case OPTEE_MSG_CMD_CLOSE_SESSION:
550 		entry_close_session(arg, num_params);
551 		break;
552 	case OPTEE_MSG_CMD_INVOKE_COMMAND:
553 		entry_invoke_command(arg, num_params);
554 		break;
555 	case OPTEE_MSG_CMD_CANCEL:
556 		entry_cancel(arg, num_params);
557 		break;
558 #ifndef CFG_CORE_FFA
559 #ifdef CFG_CORE_DYN_SHM
560 	case OPTEE_MSG_CMD_REGISTER_SHM:
561 		register_shm(arg, num_params);
562 		break;
563 	case OPTEE_MSG_CMD_UNREGISTER_SHM:
564 		unregister_shm(arg, num_params);
565 		break;
566 #endif
567 #endif
568 
569 	case OPTEE_MSG_CMD_DO_BOTTOM_HALF:
570 		if (IS_ENABLED(CFG_CORE_ASYNC_NOTIF))
571 			notif_deliver_event(NOTIF_EVENT_DO_BOTTOM_HALF);
572 		else
573 			goto err;
574 		break;
575 	case OPTEE_MSG_CMD_STOP_ASYNC_NOTIF:
576 		if (IS_ENABLED(CFG_CORE_ASYNC_NOTIF))
577 			notif_deliver_event(NOTIF_EVENT_STOPPED);
578 		else
579 			goto err;
580 		break;
581 
582 	default:
583 err:
584 		EMSG("Unknown cmd 0x%x", arg->cmd);
585 		rv = OPTEE_SMC_RETURN_EBADCMD;
586 	}
587 
588 	return rv;
589 }
590 
591 static TEE_Result default_mobj_init(void)
592 {
593 #ifdef CFG_CORE_RESERVED_SHM
594 	shm_mobj = mobj_phys_alloc(default_nsec_shm_paddr,
595 				   default_nsec_shm_size, SHM_CACHE_ATTRS,
596 				   CORE_MEM_NSEC_SHM);
597 	if (!shm_mobj)
598 		panic("Failed to register shared memory");
599 #endif
600 
601 #ifdef CFG_SECURE_DATA_PATH
602 	sdp_mem_mobjs = core_sdp_mem_create_mobjs();
603 	if (!sdp_mem_mobjs)
604 		panic("Failed to register SDP memory");
605 #endif
606 
607 	return TEE_SUCCESS;
608 }
609 
610 driver_init_late(default_mobj_init);
611