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