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