xref: /optee_os/core/arch/arm/kernel/secure_partition.c (revision a8d59198fdc30b2d06667ea0129b983a89d35b02)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2020, Arm Limited. All rights reserved.
4  * Copyright (c) 2019, Linaro Limited
5  */
6 
7 #include <crypto/crypto.h>
8 #include <ffa.h>
9 #include <kernel/abort.h>
10 #include <kernel/secure_partition.h>
11 #include <kernel/user_mode_ctx.h>
12 #include <mm/fobj.h>
13 #include <mm/mobj.h>
14 #include <mm/tee_mmu.h>
15 #include <pta_stmm.h>
16 #include <tee_api_defines_extensions.h>
17 #include <tee/tee_pobj.h>
18 #include <tee/tee_svc.h>
19 #include <tee/tee_svc_storage.h>
20 #include <zlib.h>
21 
22 #include "thread_private.h"
23 
24 static const TEE_UUID stmm_uuid = PTA_STMM_UUID;
25 
26 /*
27  * Once a complete FFA spec is added, these will become discoverable.
28  * Until then these are considered part of the internal ABI between
29  * OP-TEE and StMM.
30  */
31 static const uint16_t stmm_id = 1U;
32 static const uint16_t stmm_pta_id = 2U;
33 static const uint16_t mem_mgr_id = 3U;
34 static const uint16_t ffa_storage_id = 4U;
35 
36 static const unsigned int stmm_stack_size = 4 * SMALL_PAGE_SIZE;
37 static const unsigned int stmm_heap_size = 398 * SMALL_PAGE_SIZE;
38 static const unsigned int stmm_sec_buf_size = SMALL_PAGE_SIZE;
39 static const unsigned int stmm_ns_comm_buf_size = SMALL_PAGE_SIZE;
40 
41 extern unsigned char stmm_image[];
42 extern const unsigned int stmm_image_size;
43 extern const unsigned int stmm_image_uncompressed_size;
44 
45 static struct sec_part_ctx *sec_part_alloc_ctx(const TEE_UUID *uuid)
46 {
47 	TEE_Result res = TEE_SUCCESS;
48 	struct sec_part_ctx *spc = NULL;
49 
50 	spc = calloc(1, sizeof(*spc));
51 	if (!spc)
52 		return NULL;
53 
54 	spc->uctx.ctx.ops = &secure_partition_ops;
55 	spc->uctx.ctx.uuid = *uuid;
56 	spc->uctx.ctx.flags = TA_FLAG_SINGLE_INSTANCE |
57 			      TA_FLAG_INSTANCE_KEEP_ALIVE;
58 
59 	res = vm_info_init(&spc->uctx);
60 	if (res) {
61 		free(spc);
62 		return NULL;
63 	}
64 
65 	spc->uctx.ctx.ref_count = 1;
66 	condvar_init(&spc->uctx.ctx.busy_cv);
67 
68 	return spc;
69 }
70 
71 static void clear_vfp_state(struct sec_part_ctx *spc __maybe_unused)
72 {
73 	if (IS_ENABLED(CFG_WITH_VFP))
74 		thread_user_clear_vfp(&spc->uctx.vfp);
75 }
76 
77 static TEE_Result sec_part_enter_user_mode(struct sec_part_ctx *spc)
78 {
79 	uint32_t exceptions = 0;
80 	uint32_t panic_code = 0;
81 	uint32_t panicked = 0;
82 	uint64_t cntkctl = 0;
83 
84 	exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
85 	cntkctl = read_cntkctl();
86 	write_cntkctl(cntkctl | CNTKCTL_PL0PCTEN);
87 	__thread_enter_user_mode(&spc->regs, &panicked, &panic_code);
88 	write_cntkctl(cntkctl);
89 	thread_unmask_exceptions(exceptions);
90 
91 	clear_vfp_state(spc);
92 
93 	if (panicked) {
94 		abort_print_current_ta();
95 		DMSG("sec_part panicked with code %#"PRIx32, panic_code);
96 		return TEE_ERROR_TARGET_DEAD;
97 	}
98 
99 	return TEE_SUCCESS;
100 }
101 
102 static void init_stmm_regs(struct sec_part_ctx *spc, unsigned long a0,
103 			   unsigned long a1, unsigned long sp, unsigned long pc)
104 {
105 	spc->regs.x[0] = a0;
106 	spc->regs.x[1] = a1;
107 	spc->regs.sp = sp;
108 	spc->regs.pc = pc;
109 }
110 
111 static TEE_Result alloc_and_map_sp_fobj(struct sec_part_ctx *spc, size_t sz,
112 					uint32_t prot, vaddr_t *va)
113 {
114 	size_t num_pgs = ROUNDUP(sz, SMALL_PAGE_SIZE) / SMALL_PAGE_SIZE;
115 	struct fobj *fobj = fobj_ta_mem_alloc(num_pgs);
116 	struct mobj *mobj = mobj_with_fobj_alloc(fobj, NULL);
117 	TEE_Result res = TEE_SUCCESS;
118 
119 	fobj_put(fobj);
120 	if (!mobj)
121 		return TEE_ERROR_OUT_OF_MEMORY;
122 
123 	res = vm_map(&spc->uctx, va, num_pgs * SMALL_PAGE_SIZE,
124 		     prot, 0, mobj, 0);
125 	if (res)
126 		mobj_put(mobj);
127 
128 	return TEE_SUCCESS;
129 }
130 
131 static void *zalloc(void *opaque __unused, unsigned int items,
132 		    unsigned int size)
133 {
134 	return malloc(items * size);
135 }
136 
137 static void zfree(void *opaque __unused, void *address)
138 {
139 	free(address);
140 }
141 
142 static void uncompress_image(void *dst, size_t dst_size, void *src,
143 			     size_t src_size)
144 {
145 	z_stream strm = {
146 		.next_in = src,
147 		.avail_in = src_size,
148 		.next_out = dst,
149 		.avail_out = dst_size,
150 		.zalloc = zalloc,
151 		.zfree = zfree,
152 	};
153 
154 	if (inflateInit(&strm) != Z_OK)
155 		panic("inflateInit");
156 
157 	if (inflate(&strm, Z_SYNC_FLUSH) != Z_STREAM_END)
158 		panic("inflate");
159 
160 	if (inflateEnd(&strm) != Z_OK)
161 		panic("inflateEnd");
162 }
163 
164 static TEE_Result load_stmm(struct sec_part_ctx *spc)
165 {
166 	struct secure_partition_boot_info *boot_info = NULL;
167 	struct secure_partition_mp_info *mp_info = NULL;
168 	TEE_Result res = TEE_SUCCESS;
169 	vaddr_t sp_addr = 0;
170 	vaddr_t image_addr = 0;
171 	vaddr_t heap_addr = 0;
172 	vaddr_t stack_addr = 0;
173 	vaddr_t sec_buf_addr = 0;
174 	vaddr_t comm_buf_addr = 0;
175 	unsigned int sp_size = 0;
176 	unsigned int uncompressed_size_roundup = 0;
177 
178 	uncompressed_size_roundup = ROUNDUP(stmm_image_uncompressed_size,
179 					    SMALL_PAGE_SIZE);
180 	sp_size = uncompressed_size_roundup + stmm_stack_size +
181 		  stmm_heap_size + stmm_sec_buf_size;
182 	res = alloc_and_map_sp_fobj(spc, sp_size,
183 				    TEE_MATTR_PRW, &sp_addr);
184 	if (res)
185 		return res;
186 
187 	res = alloc_and_map_sp_fobj(spc, stmm_ns_comm_buf_size,
188 				    TEE_MATTR_URW | TEE_MATTR_PRW,
189 				    &comm_buf_addr);
190 	/*
191 	 * We don't need to free the previous instance here, they'll all be
192 	 * handled during the destruction call (sec_part_ctx_destroy())
193 	 */
194 	if (res)
195 		return res;
196 
197 	image_addr = sp_addr;
198 	heap_addr = image_addr + uncompressed_size_roundup;
199 	stack_addr = heap_addr + stmm_heap_size;
200 	sec_buf_addr = stack_addr + stmm_stack_size;
201 
202 	tee_mmu_set_ctx(&spc->uctx.ctx);
203 	uncompress_image((void *)image_addr, stmm_image_uncompressed_size,
204 			 stmm_image, stmm_image_size);
205 
206 	res = vm_set_prot(&spc->uctx, image_addr, uncompressed_size_roundup,
207 			  TEE_MATTR_URX | TEE_MATTR_PR);
208 	if (res)
209 		return res;
210 
211 	res = vm_set_prot(&spc->uctx, heap_addr, stmm_heap_size,
212 			  TEE_MATTR_URW | TEE_MATTR_PRW);
213 	if (res)
214 		return res;
215 
216 	res = vm_set_prot(&spc->uctx, stack_addr, stmm_stack_size,
217 			  TEE_MATTR_URW | TEE_MATTR_PRW);
218 	if (res)
219 		return res;
220 
221 	res = vm_set_prot(&spc->uctx, sec_buf_addr, stmm_sec_buf_size,
222 			  TEE_MATTR_URW | TEE_MATTR_PRW);
223 	if (res)
224 		return res;
225 
226 	DMSG("stmm load address %#"PRIxVA, image_addr);
227 
228 	boot_info = (struct secure_partition_boot_info *)sec_buf_addr;
229 	mp_info = (struct secure_partition_mp_info *)(boot_info + 1);
230 	*boot_info = (struct secure_partition_boot_info){
231 		.h.type = SP_PARAM_SP_IMAGE_BOOT_INFO,
232 		.h.version = SP_PARAM_VERSION_1,
233 		.h.size = sizeof(struct secure_partition_boot_info),
234 		.h.attr = 0,
235 		.sp_mem_base = sp_addr,
236 		.sp_mem_limit = sp_addr + sp_size,
237 		.sp_image_base = image_addr,
238 		.sp_stack_base = stack_addr,
239 		.sp_heap_base = heap_addr,
240 		.sp_ns_comm_buf_base = comm_buf_addr,
241 		.sp_shared_buf_base = sec_buf_addr,
242 		.sp_image_size = stmm_image_size,
243 		.sp_pcpu_stack_size = stmm_stack_size,
244 		.sp_heap_size = stmm_heap_size,
245 		.sp_ns_comm_buf_size = stmm_ns_comm_buf_size,
246 		.sp_shared_buf_size = stmm_sec_buf_size,
247 		.num_sp_mem_regions = 6,
248 		.num_cpus = 1,
249 		.mp_info = mp_info,
250 	};
251 	mp_info->mpidr = read_mpidr_el1();
252 	mp_info->linear_id = 0;
253 	mp_info->flags = MP_INFO_FLAG_PRIMARY_CPU;
254 	spc->ns_comm_buf_addr = comm_buf_addr;
255 	spc->ns_comm_buf_size = stmm_ns_comm_buf_size;
256 
257 	init_stmm_regs(spc, sec_buf_addr,
258 		       (vaddr_t)(mp_info + 1) - sec_buf_addr,
259 		       stack_addr + stmm_stack_size, image_addr);
260 
261 	return sec_part_enter_user_mode(spc);
262 }
263 
264 TEE_Result sec_part_init_session(const TEE_UUID *uuid,
265 				 struct tee_ta_session *sess)
266 {
267 	struct sec_part_ctx *spc = NULL;
268 	TEE_Result res = TEE_SUCCESS;
269 
270 	if (memcmp(uuid, &stmm_uuid, sizeof(*uuid)))
271 		return TEE_ERROR_ITEM_NOT_FOUND;
272 
273 	spc = sec_part_alloc_ctx(uuid);
274 	if (!spc)
275 		return TEE_ERROR_OUT_OF_MEMORY;
276 
277 	spc->is_initializing = true;
278 
279 	mutex_lock(&tee_ta_mutex);
280 	sess->ctx = &spc->uctx.ctx;
281 	mutex_unlock(&tee_ta_mutex);
282 
283 	tee_ta_push_current_session(sess);
284 	res = load_stmm(spc);
285 	tee_ta_pop_current_session();
286 	tee_mmu_set_ctx(NULL);
287 	if (res) {
288 		sess->ctx = NULL;
289 		spc->uctx.ctx.ops->destroy(&spc->uctx.ctx);
290 
291 		return res;
292 	}
293 
294 	mutex_lock(&tee_ta_mutex);
295 	spc->is_initializing = false;
296 	TAILQ_INSERT_TAIL(&tee_ctxes, &spc->uctx.ctx, link);
297 	mutex_unlock(&tee_ta_mutex);
298 
299 	return TEE_SUCCESS;
300 }
301 
302 static TEE_Result stmm_enter_open_session(struct tee_ta_session *s,
303 					  struct tee_ta_param *param,
304 					  TEE_ErrorOrigin *eo)
305 {
306 	struct sec_part_ctx *spc = to_sec_part_ctx(s->ctx);
307 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
308 						TEE_PARAM_TYPE_NONE,
309 						TEE_PARAM_TYPE_NONE,
310 						TEE_PARAM_TYPE_NONE);
311 
312 	if (param->types != exp_pt)
313 		return TEE_ERROR_BAD_PARAMETERS;
314 
315 	if (spc->is_initializing) {
316 		/* StMM is initialized in sec_part_init_session() */
317 		*eo = TEE_ORIGIN_TEE;
318 		return TEE_ERROR_BAD_STATE;
319 	}
320 
321 	return TEE_SUCCESS;
322 }
323 
324 static TEE_Result stmm_enter_invoke_cmd(struct tee_ta_session *s,
325 					uint32_t cmd,
326 					struct tee_ta_param *param,
327 					TEE_ErrorOrigin *eo __unused)
328 {
329 	struct sec_part_ctx *spc = to_sec_part_ctx(s->ctx);
330 	TEE_Result res = TEE_SUCCESS;
331 	TEE_Result __maybe_unused tmp_res = TEE_SUCCESS;
332 	unsigned int ns_buf_size = 0;
333 	struct param_mem *mem = NULL;
334 	void *va = NULL;
335 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
336 						TEE_PARAM_TYPE_VALUE_OUTPUT,
337 						TEE_PARAM_TYPE_NONE,
338 						TEE_PARAM_TYPE_NONE);
339 
340 	if (cmd != PTA_STMM_CMD_COMMUNICATE)
341 		return TEE_ERROR_BAD_PARAMETERS;
342 
343 	if (param->types != exp_pt)
344 		return TEE_ERROR_BAD_PARAMETERS;
345 
346 	mem = &param->u[0].mem;
347 	ns_buf_size = mem->size;
348 	if (ns_buf_size > spc->ns_comm_buf_size) {
349 		mem->size = spc->ns_comm_buf_size;
350 		return TEE_ERROR_EXCESS_DATA;
351 	}
352 
353 	res = mobj_inc_map(mem->mobj);
354 	if (res)
355 		return res;
356 
357 	va = mobj_get_va(mem->mobj, mem->offs);
358 	if (!va) {
359 		EMSG("Can't get a valid VA for NS buffer");
360 		res = TEE_ERROR_BAD_PARAMETERS;
361 		goto out_va;
362 	}
363 
364 	spc->regs.x[0] = FFA_MSG_SEND_DIRECT_REQ_64;
365 	spc->regs.x[1] = (stmm_pta_id << 16) | stmm_id;
366 	spc->regs.x[2] = FFA_PARAM_MBZ;
367 	spc->regs.x[3] = spc->ns_comm_buf_addr;
368 	spc->regs.x[4] = ns_buf_size;
369 	spc->regs.x[5] = 0;
370 	spc->regs.x[6] = 0;
371 	spc->regs.x[7] = 0;
372 
373 	tee_ta_push_current_session(s);
374 
375 	memcpy((void *)spc->ns_comm_buf_addr, va, ns_buf_size);
376 
377 	res = sec_part_enter_user_mode(spc);
378 	if (res)
379 		goto out_session;
380 	/*
381 	 * Copy the SPM response from secure partition back to the non-secure
382 	 * buffer of the client that called us.
383 	 */
384 	param->u[1].val.a = spc->regs.x[4];
385 
386 	memcpy(va, (void *)spc->ns_comm_buf_addr, ns_buf_size);
387 
388 out_session:
389 	tee_ta_pop_current_session();
390 out_va:
391 	tmp_res = mobj_dec_map(mem->mobj);
392 	assert(!tmp_res);
393 
394 	return res;
395 }
396 
397 static void stmm_enter_close_session(struct tee_ta_session *s __unused)
398 {
399 }
400 
401 static void sec_part_dump_state(struct tee_ta_ctx *ctx)
402 {
403 	user_mode_ctx_print_mappings(to_user_mode_ctx(ctx));
404 }
405 
406 static uint32_t sec_part_get_instance_id(struct tee_ta_ctx *ctx)
407 {
408 	return to_sec_part_ctx(ctx)->uctx.vm_info.asid;
409 }
410 
411 static void sec_part_ctx_destroy(struct tee_ta_ctx *ctx)
412 {
413 	struct sec_part_ctx *spc = to_sec_part_ctx(ctx);
414 
415 	tee_pager_rem_um_areas(&spc->uctx);
416 	vm_info_final(&spc->uctx);
417 	free(spc);
418 }
419 
420 static uint32_t sp_svc_get_mem_attr(vaddr_t va)
421 {
422 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
423 	struct tee_ta_session *sess = NULL;
424 	struct sec_part_ctx *spc = NULL;
425 	uint16_t attrs = 0;
426 	uint16_t perm = 0;
427 
428 	if (!va)
429 		goto err;
430 
431 	res = tee_ta_get_current_session(&sess);
432 	if (res != TEE_SUCCESS)
433 		goto err;
434 
435 	spc = to_sec_part_ctx(sess->ctx);
436 
437 	res = vm_get_prot(&spc->uctx, va, SMALL_PAGE_SIZE, &attrs);
438 	if (res)
439 		goto err;
440 
441 	if (attrs & TEE_MATTR_UR)
442 		perm |= SP_MEM_ATTR_ACCESS_RO;
443 	else if (attrs & TEE_MATTR_UW)
444 		perm |= SP_MEM_ATTR_ACCESS_RW;
445 
446 	if (attrs & TEE_MATTR_UX)
447 		perm |= SP_MEM_ATTR_EXEC;
448 
449 	return perm;
450 err:
451 	return SP_RET_DENIED;
452 }
453 
454 static int sp_svc_set_mem_attr(vaddr_t va, unsigned int nr_pages, uint32_t perm)
455 {
456 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
457 	struct tee_ta_session *sess = NULL;
458 	struct sec_part_ctx *spc = NULL;
459 	size_t sz = 0;
460 	uint32_t prot = 0;
461 
462 	if (!va || !nr_pages || MUL_OVERFLOW(nr_pages, SMALL_PAGE_SIZE, &sz))
463 		return SP_RET_INVALID_PARAM;
464 
465 	if (perm & ~SP_MEM_ATTR_ALL)
466 		return SP_RET_INVALID_PARAM;
467 
468 	res = tee_ta_get_current_session(&sess);
469 	if (res != TEE_SUCCESS)
470 		return SP_RET_DENIED;
471 
472 	spc = to_sec_part_ctx(sess->ctx);
473 
474 	if ((perm & SP_MEM_ATTR_ACCESS_MASK) == SP_MEM_ATTR_ACCESS_RO)
475 		prot |= TEE_MATTR_UR;
476 	else if ((perm & SP_MEM_ATTR_ACCESS_MASK) == SP_MEM_ATTR_ACCESS_RW)
477 		prot |= TEE_MATTR_URW;
478 
479 	if ((perm & SP_MEM_ATTR_EXEC_NEVER) == SP_MEM_ATTR_EXEC)
480 		prot |= TEE_MATTR_UX;
481 
482 	res = vm_set_prot(&spc->uctx, va, sz, prot);
483 	if (res)
484 		return SP_RET_DENIED;
485 
486 	return SP_RET_SUCCESS;
487 }
488 
489 static bool return_helper(bool panic, uint32_t panic_code,
490 			  struct thread_svc_regs *svc_regs)
491 {
492 	if (!panic) {
493 		struct tee_ta_session *sess = NULL;
494 		struct sec_part_ctx *spc = NULL;
495 		size_t n = 0;
496 
497 		tee_ta_get_current_session(&sess);
498 		spc = to_sec_part_ctx(sess->ctx);
499 
500 		/* Save the return values from StMM */
501 		for (n = 0; n <= 7; n++)
502 			spc->regs.x[n] = *(&svc_regs->x0 + n);
503 
504 		spc->regs.sp = svc_regs->sp_el0;
505 		spc->regs.pc = svc_regs->elr;
506 		spc->regs.cpsr = svc_regs->spsr;
507 	}
508 
509 	svc_regs->x0 = 0;
510 	svc_regs->x1 = panic;
511 	svc_regs->x2 = panic_code;
512 
513 	return false;
514 }
515 
516 static void service_compose_direct_resp(struct thread_svc_regs *regs,
517 					uint32_t ret_val)
518 {
519 	uint16_t src_id = 0;
520 	uint16_t dst_id = 0;
521 
522 	/* extract from request */
523 	src_id = (regs->x1 >> 16) & UINT16_MAX;
524 	dst_id = regs->x1 & UINT16_MAX;
525 
526 	/* compose message */
527 	regs->x0 = FFA_MSG_SEND_DIRECT_RESP_64;
528 	/* swap endpoint ids */
529 	regs->x1 = SHIFT_U32(dst_id, 16) | src_id;
530 	regs->x2 = FFA_PARAM_MBZ;
531 	regs->x3 = ret_val;
532 	regs->x4 = 0;
533 	regs->x5 = 0;
534 	regs->x6 = 0;
535 	regs->x7 = 0;
536 }
537 
538 /*
539  * Combined read from secure partition, this will open, read and
540  * close the file object.
541  */
542 static TEE_Result sec_storage_obj_read(unsigned long storage_id, char *obj_id,
543 				       unsigned long obj_id_len, void *data,
544 				       unsigned long len, unsigned long offset,
545 				       unsigned long flags)
546 {
547 	const struct tee_file_operations *fops = NULL;
548 	TEE_Result res = TEE_ERROR_BAD_STATE;
549 	struct tee_ta_session *sess = NULL;
550 	struct tee_file_handle *fh = NULL;
551 	struct sec_part_ctx *spc = NULL;
552 	struct tee_pobj *po = NULL;
553 	size_t file_size = 0;
554 	size_t read_len = 0;
555 
556 	fops = tee_svc_storage_file_ops(storage_id);
557 	if (!fops)
558 		return TEE_ERROR_ITEM_NOT_FOUND;
559 
560 	if (obj_id_len > TEE_OBJECT_ID_MAX_LEN)
561 		return TEE_ERROR_BAD_PARAMETERS;
562 
563 	res = tee_ta_get_current_session(&sess);
564 	if (res != TEE_SUCCESS)
565 		return res;
566 
567 	spc = to_sec_part_ctx(sess->ctx);
568 	res = tee_mmu_check_access_rights(&spc->uctx,
569 					  TEE_MEMORY_ACCESS_WRITE |
570 					  TEE_MEMORY_ACCESS_ANY_OWNER,
571 					  (uaddr_t)data, len);
572 	if (res != TEE_SUCCESS)
573 		return res;
574 
575 	res = tee_pobj_get(&sess->ctx->uuid, obj_id, obj_id_len, flags,
576 			   false, fops, &po);
577 	if (res != TEE_SUCCESS)
578 		return res;
579 
580 	res = po->fops->open(po, &file_size, &fh);
581 	if (res != TEE_SUCCESS)
582 		goto out;
583 
584 	read_len = len;
585 	res = po->fops->read(fh, offset, data, &read_len);
586 	if (res == TEE_ERROR_CORRUPT_OBJECT) {
587 		EMSG("Object corrupt");
588 		po->fops->remove(po);
589 	} else if (res == TEE_SUCCESS && len != read_len) {
590 		res = TEE_ERROR_CORRUPT_OBJECT;
591 	}
592 
593 	po->fops->close(&fh);
594 
595 out:
596 	tee_pobj_release(po);
597 
598 	return res;
599 }
600 
601 /*
602  * Combined write from secure partition, this will create/open, write and
603  * close the file object.
604  */
605 static TEE_Result sec_storage_obj_write(unsigned long storage_id, char *obj_id,
606 					unsigned long obj_id_len, void *data,
607 					unsigned long len, unsigned long offset,
608 					unsigned long flags)
609 
610 {
611 	const struct tee_file_operations *fops = NULL;
612 	struct tee_ta_session *sess = NULL;
613 	struct tee_file_handle *fh = NULL;
614 	struct sec_part_ctx *spc = NULL;
615 	TEE_Result res = TEE_SUCCESS;
616 	struct tee_pobj *po = NULL;
617 
618 	fops = tee_svc_storage_file_ops(storage_id);
619 	if (!fops)
620 		return TEE_ERROR_ITEM_NOT_FOUND;
621 
622 	if (obj_id_len > TEE_OBJECT_ID_MAX_LEN)
623 		return TEE_ERROR_BAD_PARAMETERS;
624 
625 	res = tee_ta_get_current_session(&sess);
626 	if (res != TEE_SUCCESS)
627 		return res;
628 
629 	spc = to_sec_part_ctx(sess->ctx);
630 	res = tee_mmu_check_access_rights(&spc->uctx,
631 					  TEE_MEMORY_ACCESS_READ |
632 					  TEE_MEMORY_ACCESS_ANY_OWNER,
633 					  (uaddr_t)data, len);
634 	if (res != TEE_SUCCESS)
635 		return res;
636 
637 	res = tee_pobj_get(&sess->ctx->uuid, obj_id, obj_id_len, flags,
638 			   false, fops, &po);
639 	if (res != TEE_SUCCESS)
640 		return res;
641 
642 	res = po->fops->open(po, NULL, &fh);
643 	if (res == TEE_ERROR_ITEM_NOT_FOUND)
644 		res = po->fops->create(po, false, NULL, 0, NULL, 0, NULL, 0,
645 				       &fh);
646 	if (res == TEE_SUCCESS) {
647 		res = po->fops->write(fh, offset, data, len);
648 		po->fops->close(&fh);
649 	}
650 
651 	tee_pobj_release(po);
652 
653 	return res;
654 }
655 
656 static bool stmm_handle_mem_mgr_service(struct thread_svc_regs *regs)
657 {
658 	uint32_t action = regs->x3;
659 	uintptr_t va = regs->x4;
660 	uint32_t nr_pages = regs->x5;
661 	uint32_t perm = regs->x6;
662 
663 	switch (action) {
664 	case FFA_SVC_MEMORY_ATTRIBUTES_GET_64:
665 		service_compose_direct_resp(regs, sp_svc_get_mem_attr(va));
666 		return true;
667 	case FFA_SVC_MEMORY_ATTRIBUTES_SET_64:
668 		service_compose_direct_resp(regs,
669 					    sp_svc_set_mem_attr(va, nr_pages,
670 								perm));
671 		return true;
672 	default:
673 		EMSG("Undefined service id %#"PRIx32, action);
674 		service_compose_direct_resp(regs, SP_RET_INVALID_PARAM);
675 		return true;
676 	}
677 }
678 
679 #define FILENAME "EFI_VARS"
680 static bool stmm_handle_storage_service(struct thread_svc_regs *regs)
681 {
682 	uint32_t flags = TEE_DATA_FLAG_ACCESS_READ |
683 			 TEE_DATA_FLAG_ACCESS_WRITE |
684 			 TEE_DATA_FLAG_SHARE_READ |
685 			 TEE_DATA_FLAG_SHARE_WRITE;
686 	uint32_t action = regs->x3;
687 	void *va = (void *)regs->x4;
688 	unsigned long len = regs->x5;
689 	unsigned long offset = regs->x6;
690 	char obj_id[] = FILENAME;
691 	size_t obj_id_len = strlen(obj_id);
692 	TEE_Result res = TEE_SUCCESS;
693 
694 	switch (action) {
695 	case FFA_SVC_RPMB_READ:
696 		res = sec_storage_obj_read(TEE_STORAGE_PRIVATE_RPMB, obj_id,
697 					   obj_id_len, va, len, offset, flags);
698 		service_compose_direct_resp(regs, res);
699 
700 		return true;
701 	case FFA_SVC_RPMB_WRITE:
702 		res = sec_storage_obj_write(TEE_STORAGE_PRIVATE_RPMB, obj_id,
703 					    obj_id_len, va, len, offset, flags);
704 		service_compose_direct_resp(regs, res);
705 
706 		return true;
707 	default:
708 		EMSG("Undefined service id %#"PRIx32, action);
709 		service_compose_direct_resp(regs, SP_RET_INVALID_PARAM);
710 		return true;
711 	}
712 }
713 
714 static bool spm_eret_error(int32_t error_code, struct thread_svc_regs *regs)
715 {
716 	regs->x0 = FFA_ERROR;
717 	regs->x1 = FFA_PARAM_MBZ;
718 	regs->x2 = error_code;
719 	regs->x3 = FFA_PARAM_MBZ;
720 	regs->x4 = FFA_PARAM_MBZ;
721 	regs->x5 = FFA_PARAM_MBZ;
722 	regs->x6 = FFA_PARAM_MBZ;
723 	regs->x7 = FFA_PARAM_MBZ;
724 	return true;
725 }
726 
727 static bool spm_handle_direct_req(struct thread_svc_regs *regs)
728 {
729 	uint16_t dst_id = regs->x1 & UINT16_MAX;
730 
731 	/* Look-up of destination endpoint */
732 	if (dst_id == mem_mgr_id)
733 		return stmm_handle_mem_mgr_service(regs);
734 	else if (dst_id == ffa_storage_id)
735 		return stmm_handle_storage_service(regs);
736 
737 	EMSG("Undefined endpoint id %#"PRIx16, dst_id);
738 	return spm_eret_error(SP_RET_INVALID_PARAM, regs);
739 }
740 
741 static bool spm_handle_svc(struct thread_svc_regs *regs)
742 {
743 	switch (regs->x0) {
744 	case FFA_VERSION:
745 		DMSG("Received FFA version");
746 		regs->x0 = MAKE_FFA_VERSION(FFA_VERSION_MAJOR,
747 					    FFA_VERSION_MINOR);
748 		return true;
749 	case FFA_MSG_SEND_DIRECT_RESP_64:
750 		DMSG("Received FFA direct response");
751 		return return_helper(false, 0, regs);
752 	case FFA_MSG_SEND_DIRECT_REQ_64:
753 		DMSG("Received FFA direct request");
754 		return spm_handle_direct_req(regs);
755 	default:
756 		EMSG("Undefined syscall %#"PRIx32, (uint32_t)regs->x0);
757 		return return_helper(true /*panic*/, 0xabcd, regs);
758 	}
759 }
760 
761 const struct tee_ta_ops secure_partition_ops __rodata_unpaged = {
762 	.enter_open_session = stmm_enter_open_session,
763 	.enter_invoke_cmd = stmm_enter_invoke_cmd,
764 	.enter_close_session = stmm_enter_close_session,
765 	.dump_state = sec_part_dump_state,
766 	.destroy = sec_part_ctx_destroy,
767 	.get_instance_id = sec_part_get_instance_id,
768 	.handle_svc = spm_handle_svc,
769 };
770