xref: /optee_os/core/arch/riscv/kernel/arch_scall.c (revision 3db1b3e3179fb98fba226bae3b7d6d1f5723e8ac)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2023 Andes Technology Corporation
4  * Copyright 2022-2023 NXP
5  * Copyright (c) 2014-2022, Linaro Limited
6  * Copyright (c) 2020, Arm Limited
7  */
8 
9 #include <kernel/abort.h>
10 #include <kernel/scall.h>
11 #include <kernel/thread.h>
12 #include <kernel/trace_ta.h>
13 #include <kernel/user_access.h>
14 #include <kernel/user_ta.h>
15 #include <mm/vm.h>
16 #include <riscv.h>
17 #include <types_ext.h>
18 
19 #define TA_CONTEXT_MAX_SIZE	(RISCV_XLEN_BYTES * 32)
20 
21 #ifdef CFG_UNWIND
22 
23 /* Get register values pushed onto the stack by _utee_panic() */
save_panic_regs_rv_ta(struct thread_specific_data * tsd,unsigned long * pushed)24 static void save_panic_regs_rv_ta(struct thread_specific_data *tsd,
25 				  unsigned long *pushed)
26 {
27 	TEE_Result res = TEE_SUCCESS;
28 	unsigned long s0 = 0;
29 	unsigned long epc = 0;
30 #if defined(RV32)
31 	unsigned long *stack_s0 = &pushed[2];
32 	unsigned long *stack_epc = &pushed[3];
33 #elif defined(RV64)
34 	unsigned long *stack_s0 = &pushed[0];
35 	unsigned long *stack_epc = &pushed[1];
36 #endif
37 
38 	res = GET_USER_SCALAR(s0, stack_s0);
39 	if (res)
40 		s0 = 0;
41 
42 	res = GET_USER_SCALAR(epc, stack_epc);
43 	if (res)
44 		epc = 0;
45 
46 	tsd->abort_regs = (struct thread_abort_regs){
47 		.sp = (unsigned long)pushed,
48 		.s0 = s0,
49 		.epc = epc,
50 	};
51 }
52 
scall_save_panic_stack(struct thread_scall_regs * regs)53 void scall_save_panic_stack(struct thread_scall_regs *regs)
54 {
55 	struct thread_specific_data *tsd = thread_get_tsd();
56 	struct ts_session *s = ts_get_current_session();
57 	struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx);
58 
59 	if (vm_check_access_rights(&utc->uctx,
60 				   TEE_MEMORY_ACCESS_READ |
61 				   TEE_MEMORY_ACCESS_WRITE,
62 				   (uaddr_t)regs->a1,
63 				   TA_CONTEXT_MAX_SIZE)) {
64 		TAMSG_RAW("");
65 		TAMSG_RAW("Can't unwind invalid user stack 0x%"PRIxUA,
66 			  (uaddr_t)regs->a1);
67 		return;
68 	}
69 
70 	tsd->abort_type = ABORT_TYPE_USER_MODE_PANIC;
71 	tsd->abort_descr = 0;
72 	tsd->abort_va = 0;
73 
74 	save_panic_regs_rv_ta(tsd, (unsigned long *)regs->a1);
75 }
76 
77 #else /* CFG_UNWIND */
scall_save_panic_stack(struct thread_scall_regs * regs __unused)78 void scall_save_panic_stack(struct thread_scall_regs *regs __unused)
79 {
80 	struct thread_specific_data *tsd = thread_get_tsd();
81 
82 	tsd->abort_type = ABORT_TYPE_USER_MODE_PANIC;
83 }
84 #endif /* CFG_UNWIND */
85