xref: /optee_os/core/arch/arm/kernel/arch_scall.c (revision 124bf0900e3a789c5e94ecf5ab1d02a75c596ecd)
1a0ea786eSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2a0ea786eSJens Wiklander /*
3a0ea786eSJens Wiklander  * Copyright (c) 2014-2022, Linaro Limited
4a0ea786eSJens Wiklander  * Copyright (c) 2020, Arm Limited
5a0ea786eSJens Wiklander  */
6a0ea786eSJens Wiklander 
7a0ea786eSJens Wiklander #include <kernel/abort.h>
8fc82e622SJens Wiklander #include <kernel/scall.h>
9a0ea786eSJens Wiklander #include <kernel/thread.h>
10a0ea786eSJens Wiklander #include <kernel/trace_ta.h>
11*124bf090SSeonghyun Park #include <kernel/user_access.h>
12a0ea786eSJens Wiklander #include <kernel/user_ta.h>
13a0ea786eSJens Wiklander #include <mm/vm.h>
14a0ea786eSJens Wiklander #include <types_ext.h>
15a0ea786eSJens Wiklander 
16a0ea786eSJens Wiklander #define TA32_CONTEXT_MAX_SIZE		(14 * sizeof(uint32_t))
17a0ea786eSJens Wiklander #define TA64_CONTEXT_MAX_SIZE		(2 * sizeof(uint64_t))
18a0ea786eSJens Wiklander 
19a0ea786eSJens Wiklander #ifdef CFG_UNWIND
20a0ea786eSJens Wiklander #ifdef ARM32
21a0ea786eSJens Wiklander /* Get register values pushed onto the stack by _utee_panic() */
save_panic_regs_a32_ta(struct thread_specific_data * tsd,uint32_t * pushed)22a0ea786eSJens Wiklander static void save_panic_regs_a32_ta(struct thread_specific_data *tsd,
23a0ea786eSJens Wiklander 				   uint32_t *pushed)
24a0ea786eSJens Wiklander {
25a0ea786eSJens Wiklander 	tsd->abort_regs = (struct thread_abort_regs){
26a0ea786eSJens Wiklander 		.elr = pushed[0],
27a0ea786eSJens Wiklander 		.r0 = pushed[1],
28a0ea786eSJens Wiklander 		.r1 = pushed[2],
29a0ea786eSJens Wiklander 		.r2 = pushed[3],
30a0ea786eSJens Wiklander 		.r3 = pushed[4],
31a0ea786eSJens Wiklander 		.r4 = pushed[5],
32a0ea786eSJens Wiklander 		.r5 = pushed[6],
33a0ea786eSJens Wiklander 		.r6 = pushed[7],
34a0ea786eSJens Wiklander 		.r7 = pushed[8],
35a0ea786eSJens Wiklander 		.r8 = pushed[9],
36a0ea786eSJens Wiklander 		.r9 = pushed[10],
37a0ea786eSJens Wiklander 		.r10 = pushed[11],
38a0ea786eSJens Wiklander 		.r11 = pushed[12],
39a0ea786eSJens Wiklander 		.usr_sp = (uint32_t)pushed,
40a0ea786eSJens Wiklander 		.usr_lr = pushed[13],
41a0ea786eSJens Wiklander 		.spsr = read_spsr(),
42a0ea786eSJens Wiklander 	};
43a0ea786eSJens Wiklander }
44a0ea786eSJens Wiklander 
scall_save_panic_stack(struct thread_scall_regs * regs)45a0ea786eSJens Wiklander void scall_save_panic_stack(struct thread_scall_regs *regs)
46a0ea786eSJens Wiklander {
47a0ea786eSJens Wiklander 	struct thread_specific_data *tsd = thread_get_tsd();
48a0ea786eSJens Wiklander 	struct ts_session *s = ts_get_current_session();
49a0ea786eSJens Wiklander 	struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx);
50a0ea786eSJens Wiklander 
51a0ea786eSJens Wiklander 	tsd->abort_type = ABORT_TYPE_USER_MODE_PANIC;
52a0ea786eSJens Wiklander 	tsd->abort_descr = 0;
53a0ea786eSJens Wiklander 	tsd->abort_va = 0;
54a0ea786eSJens Wiklander 
55a0ea786eSJens Wiklander 	if (vm_check_access_rights(&utc->uctx,
56a0ea786eSJens Wiklander 				   TEE_MEMORY_ACCESS_READ |
57a0ea786eSJens Wiklander 				   TEE_MEMORY_ACCESS_WRITE,
58a0ea786eSJens Wiklander 				   (uaddr_t)regs->r1, TA32_CONTEXT_MAX_SIZE)) {
59a0ea786eSJens Wiklander 		TAMSG_RAW("");
60a0ea786eSJens Wiklander 		TAMSG_RAW("Can't unwind invalid user stack 0x%"PRIxUA,
61a0ea786eSJens Wiklander 			  (uaddr_t)regs->r1);
62a0ea786eSJens Wiklander 		return;
63a0ea786eSJens Wiklander 	}
64a0ea786eSJens Wiklander 
65a0ea786eSJens Wiklander 	save_panic_regs_a32_ta(tsd, (uint32_t *)regs->r1);
66a0ea786eSJens Wiklander }
67a0ea786eSJens Wiklander #endif /*ARM32*/
68a0ea786eSJens Wiklander 
69a0ea786eSJens Wiklander #ifdef ARM64
70a0ea786eSJens Wiklander /* Get register values pushed onto the stack by _utee_panic() (32-bit TA) */
save_panic_regs_a32_ta(struct thread_specific_data * tsd,uint32_t * pushed)71a0ea786eSJens Wiklander static void save_panic_regs_a32_ta(struct thread_specific_data *tsd,
72a0ea786eSJens Wiklander 				   uint32_t *pushed)
73a0ea786eSJens Wiklander {
74a0ea786eSJens Wiklander 	tsd->abort_regs = (struct thread_abort_regs){
75a0ea786eSJens Wiklander 		.elr = pushed[0],
76a0ea786eSJens Wiklander 		.x0 = pushed[1],
77a0ea786eSJens Wiklander 		.x1 = pushed[2],
78a0ea786eSJens Wiklander 		.x2 = pushed[3],
79a0ea786eSJens Wiklander 		.x3 = pushed[4],
80a0ea786eSJens Wiklander 		.x4 = pushed[5],
81a0ea786eSJens Wiklander 		.x5 = pushed[6],
82a0ea786eSJens Wiklander 		.x6 = pushed[7],
83a0ea786eSJens Wiklander 		.x7 = pushed[8],
84a0ea786eSJens Wiklander 		.x8 = pushed[9],
85a0ea786eSJens Wiklander 		.x9 = pushed[10],
86a0ea786eSJens Wiklander 		.x10 = pushed[11],
87a0ea786eSJens Wiklander 		.x11 = pushed[12],
88a0ea786eSJens Wiklander 		.x13 = (uint64_t)pushed,
89a0ea786eSJens Wiklander 		.x14 = pushed[13],
90a0ea786eSJens Wiklander 		.spsr = (SPSR_MODE_RW_32 << SPSR_MODE_RW_SHIFT),
91a0ea786eSJens Wiklander 	};
92a0ea786eSJens Wiklander }
93a0ea786eSJens Wiklander 
94a0ea786eSJens Wiklander /* Get register values pushed onto the stack by _utee_panic() (64-bit TA) */
save_panic_regs_a64_ta(struct thread_specific_data * tsd,uint64_t * pushed)95a0ea786eSJens Wiklander static void save_panic_regs_a64_ta(struct thread_specific_data *tsd,
96a0ea786eSJens Wiklander 				   uint64_t *pushed)
97a0ea786eSJens Wiklander {
98*124bf090SSeonghyun Park 	TEE_Result res = TEE_SUCCESS;
99*124bf090SSeonghyun Park 	uint64_t x29 = 0;
100*124bf090SSeonghyun Park 	uint64_t elr = 0;
101*124bf090SSeonghyun Park 
102*124bf090SSeonghyun Park 	res = GET_USER_SCALAR(x29, &pushed[0]);
103*124bf090SSeonghyun Park 	if (res)
104*124bf090SSeonghyun Park 		x29 = 0;
105*124bf090SSeonghyun Park 
106*124bf090SSeonghyun Park 	res = GET_USER_SCALAR(elr, &pushed[1]);
107*124bf090SSeonghyun Park 	if (res)
108*124bf090SSeonghyun Park 		elr = 0;
109*124bf090SSeonghyun Park 
110a0ea786eSJens Wiklander 	tsd->abort_regs = (struct thread_abort_regs){
111*124bf090SSeonghyun Park 		.x29 = x29,
112*124bf090SSeonghyun Park 		.elr = elr,
113a0ea786eSJens Wiklander 		.spsr = (SPSR_64_MODE_EL0 << SPSR_64_MODE_EL_SHIFT),
114a0ea786eSJens Wiklander 	};
115a0ea786eSJens Wiklander }
116a0ea786eSJens Wiklander 
scall_save_panic_stack(struct thread_scall_regs * regs)117a0ea786eSJens Wiklander void scall_save_panic_stack(struct thread_scall_regs *regs)
118a0ea786eSJens Wiklander {
119a0ea786eSJens Wiklander 	struct thread_specific_data *tsd = thread_get_tsd();
120a0ea786eSJens Wiklander 	struct ts_session *s = ts_get_current_session();
121a0ea786eSJens Wiklander 	struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx);
122a0ea786eSJens Wiklander 
123a0ea786eSJens Wiklander 	if (vm_check_access_rights(&utc->uctx,
124a0ea786eSJens Wiklander 				   TEE_MEMORY_ACCESS_READ |
125a0ea786eSJens Wiklander 				   TEE_MEMORY_ACCESS_WRITE,
126a0ea786eSJens Wiklander 				   (uaddr_t)regs->x1,
127a0ea786eSJens Wiklander 				   utc->uctx.is_32bit ?
128a0ea786eSJens Wiklander 				   TA32_CONTEXT_MAX_SIZE :
129a0ea786eSJens Wiklander 				   TA64_CONTEXT_MAX_SIZE)) {
130a0ea786eSJens Wiklander 		TAMSG_RAW("");
131a0ea786eSJens Wiklander 		TAMSG_RAW("Can't unwind invalid user stack 0x%"PRIxUA,
132a0ea786eSJens Wiklander 			  (uaddr_t)regs->x1);
133a0ea786eSJens Wiklander 		return;
134a0ea786eSJens Wiklander 	}
135a0ea786eSJens Wiklander 
136a0ea786eSJens Wiklander 	tsd->abort_type = ABORT_TYPE_USER_MODE_PANIC;
137a0ea786eSJens Wiklander 	tsd->abort_descr = 0;
138a0ea786eSJens Wiklander 	tsd->abort_va = 0;
139a0ea786eSJens Wiklander 
140a0ea786eSJens Wiklander 	if (utc->uctx.is_32bit)
141a0ea786eSJens Wiklander 		save_panic_regs_a32_ta(tsd, (uint32_t *)regs->x1);
142a0ea786eSJens Wiklander 	else
143a0ea786eSJens Wiklander 		save_panic_regs_a64_ta(tsd, (uint64_t *)regs->x1);
144a0ea786eSJens Wiklander }
145a0ea786eSJens Wiklander #endif /*ARM64*/
146a0ea786eSJens Wiklander 
147a0ea786eSJens Wiklander #else /* CFG_UNWIND */
scall_save_panic_stack(struct thread_scall_regs * regs __unused)148a0ea786eSJens Wiklander void scall_save_panic_stack(struct thread_scall_regs *regs __unused)
149a0ea786eSJens Wiklander {
150a0ea786eSJens Wiklander 	struct thread_specific_data *tsd = thread_get_tsd();
151a0ea786eSJens Wiklander 
152a0ea786eSJens Wiklander 	tsd->abort_type = ABORT_TYPE_USER_MODE_PANIC;
153a0ea786eSJens Wiklander }
154a0ea786eSJens Wiklander #endif /* CFG_UNWIND */
155