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