1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-12-08 RT-Thread first version
9 */
10
11 #include <rthw.h>
12 #include <rtthread.h>
13 #include <stdint.h>
14
15 #include <mm_fault.h>
16 #include <mmu.h>
17 #include <encoding.h>
18 #include <stack.h>
19 #include <sbi.h>
20 #include <riscv.h>
21 #include <interrupt.h>
22 #include <plic.h>
23 #include <tick.h>
24
25 #ifdef RT_USING_SMART
26 #include <lwp_arch.h>
27 #endif
28
29 #define DBG_TAG "libcpu.trap"
30 #define DBG_LVL DBG_INFO
31 #include <rtdbg.h>
32
dump_regs(struct rt_hw_stack_frame * regs)33 void dump_regs(struct rt_hw_stack_frame *regs)
34 {
35 rt_kprintf("--------------Dump Registers-----------------\n");
36
37 rt_kprintf("Function Registers:\n");
38 rt_kprintf("\tra(x1) = %p\tuser_sp = %p\n", regs->ra,
39 regs->user_sp_exc_stack);
40 rt_kprintf("\tgp(x3) = %p\ttp(x4) = %p\n", regs->gp, regs->tp);
41 rt_kprintf("Temporary Registers:\n");
42 rt_kprintf("\tt0(x5) = %p\tt1(x6) = %p\n", regs->t0, regs->t1);
43 rt_kprintf("\tt2(x7) = %p\n", regs->t2);
44 rt_kprintf("\tt3(x28) = %p\tt4(x29) = %p\n", regs->t3, regs->t4);
45 rt_kprintf("\tt5(x30) = %p\tt6(x31) = %p\n", regs->t5, regs->t6);
46 rt_kprintf("Saved Registers:\n");
47 rt_kprintf("\ts0/fp(x8) = %p\ts1(x9) = %p\n", regs->s0_fp, regs->s1);
48 rt_kprintf("\ts2(x18) = %p\ts3(x19) = %p\n", regs->s2, regs->s3);
49 rt_kprintf("\ts4(x20) = %p\ts5(x21) = %p\n", regs->s4, regs->s5);
50 rt_kprintf("\ts6(x22) = %p\ts7(x23) = %p\n", regs->s6, regs->s7);
51 rt_kprintf("\ts8(x24) = %p\ts9(x25) = %p\n", regs->s8, regs->s9);
52 rt_kprintf("\ts10(x26) = %p\ts11(x27) = %p\n", regs->s10, regs->s11);
53 rt_kprintf("Function Arguments Registers:\n");
54 rt_kprintf("\ta0(x10) = %p\ta1(x11) = %p\n", regs->a0, regs->a1);
55 rt_kprintf("\ta2(x12) = %p\ta3(x13) = %p\n", regs->a2, regs->a3);
56 rt_kprintf("\ta4(x14) = %p\ta5(x15) = %p\n", regs->a4, regs->a5);
57 rt_kprintf("\ta6(x16) = %p\ta7(x17) = %p\n", regs->a6, regs->a7);
58 rt_kprintf("sstatus = %p\n", regs->sstatus);
59 rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SIE)
60 ? "Supervisor Interrupt Enabled"
61 : "Supervisor Interrupt Disabled");
62 rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPIE)
63 ? "Last Time Supervisor Interrupt Enabled"
64 : "Last Time Supervisor Interrupt Disabled");
65 rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPP)
66 ? "Last Privilege is Supervisor Mode"
67 : "Last Privilege is User Mode");
68 rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SUM)
69 ? "Permit to Access User Page"
70 : "Not Permit to Access User Page");
71 rt_kprintf("\t%s\n", (regs->sstatus & (1 << 19))
72 ? "Permit to Read Executable-only Page"
73 : "Not Permit to Read Executable-only Page");
74 rt_ubase_t satp_v = read_csr(satp);
75 rt_kprintf("satp = %p\n", satp_v);
76 rt_kprintf("\tCurrent Page Table(Physical) = %p\n",
77 __MASKVALUE(satp_v, __MASK(44)) << PAGE_OFFSET_BIT);
78 rt_kprintf("\tCurrent ASID = %p\n", __MASKVALUE(satp_v >> 44, __MASK(16))
79 << PAGE_OFFSET_BIT);
80 const char *mode_str = "Unknown Address Translation/Protection Mode";
81
82 switch (__MASKVALUE(satp_v >> 60, __MASK(4)))
83 {
84 case 0:
85 mode_str = "No Address Translation/Protection Mode";
86 break;
87
88 case 8:
89 mode_str = "Page-based 39-bit Virtual Addressing Mode";
90 break;
91
92 case 9:
93 mode_str = "Page-based 48-bit Virtual Addressing Mode";
94 break;
95 }
96
97 rt_kprintf("\tMode = %s\n", mode_str);
98 rt_kprintf("-----------------Dump OK---------------------\n");
99 }
100
101 static const char *Exception_Name[] = {"Instruction Address Misaligned",
102 "Instruction Access Fault",
103 "Illegal Instruction",
104 "Breakpoint",
105 "Load Address Misaligned",
106 "Load Access Fault",
107 "Store/AMO Address Misaligned",
108 "Store/AMO Access Fault",
109 "Environment call from U-mode",
110 "Environment call from S-mode",
111 "Reserved-10",
112 "Reserved-11",
113 "Instruction Page Fault",
114 "Load Page Fault",
115 "Reserved-14",
116 "Store/AMO Page Fault"};
117
118 static const char *Interrupt_Name[] = {
119 "User Software Interrupt",
120 "Supervisor Software Interrupt",
121 "Reversed-2",
122 "Reversed-3",
123 "User Timer Interrupt",
124 "Supervisor Timer Interrupt",
125 "Reversed-6",
126 "Reversed-7",
127 "User External Interrupt",
128 "Supervisor External Interrupt",
129 "Reserved-10",
130 "Reserved-11",
131 };
132
133 #ifndef RT_USING_SMP
134 static volatile int nested = 0;
135 #define ENTER_TRAP nested += 1
136 #define EXIT_TRAP nested -= 1
137 #define CHECK_NESTED_PANIC(cause, tval, epc, eframe) \
138 if (nested != 1) handle_nested_trap_panic(cause, tval, epc, eframe)
139 #endif /* RT_USING_SMP */
140
get_exception_msg(int id)141 static const char *get_exception_msg(int id)
142 {
143 const char *msg;
144 if (id < sizeof(Exception_Name) / sizeof(const char *))
145 {
146 msg = Exception_Name[id];
147 }
148 else
149 {
150 msg = "Unknown Exception";
151 }
152 return msg;
153 }
154
155 #ifdef RT_USING_SMART
156 #include "lwp.h"
handle_user(rt_ubase_t scause,rt_ubase_t stval,rt_ubase_t sepc,struct rt_hw_stack_frame * sp)157 void handle_user(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc,
158 struct rt_hw_stack_frame *sp)
159 {
160 rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL));
161 struct rt_lwp *lwp;
162
163 /* user page fault */
164 enum rt_mm_fault_op fault_op;
165 enum rt_mm_fault_type fault_type;
166 switch (id)
167 {
168 case EP_LOAD_PAGE_FAULT:
169 fault_op = MM_FAULT_OP_READ;
170 fault_type = MM_FAULT_TYPE_GENERIC_MMU;
171 break;
172 case EP_LOAD_ACCESS_FAULT:
173 fault_op = MM_FAULT_OP_READ;
174 fault_type = MM_FAULT_TYPE_BUS_ERROR;
175 break;
176 case EP_LOAD_ADDRESS_MISALIGNED:
177 fault_op = MM_FAULT_OP_READ;
178 fault_type = MM_FAULT_TYPE_BUS_ERROR;
179 break;
180 case EP_STORE_PAGE_FAULT:
181 fault_op = MM_FAULT_OP_WRITE;
182 fault_type = MM_FAULT_TYPE_GENERIC_MMU;
183 break;
184 case EP_STORE_ACCESS_FAULT:
185 fault_op = MM_FAULT_OP_WRITE;
186 fault_type = MM_FAULT_TYPE_BUS_ERROR;
187 break;
188 case EP_STORE_ADDRESS_MISALIGNED:
189 fault_op = MM_FAULT_OP_WRITE;
190 fault_type = MM_FAULT_TYPE_BUS_ERROR;
191 break;
192 case EP_INSTRUCTION_PAGE_FAULT:
193 fault_op = MM_FAULT_OP_EXECUTE;
194 fault_type = MM_FAULT_TYPE_GENERIC_MMU;
195 break;
196 case EP_INSTRUCTION_ACCESS_FAULT:
197 fault_op = MM_FAULT_OP_EXECUTE;
198 fault_type = MM_FAULT_TYPE_BUS_ERROR;
199 break;
200 case EP_INSTRUCTION_ADDRESS_MISALIGNED:
201 fault_op = MM_FAULT_OP_EXECUTE;
202 fault_type = MM_FAULT_TYPE_BUS_ERROR;
203 break;
204 default:
205 fault_op = 0;
206 }
207
208 if (fault_op)
209 {
210 rt_base_t saved_stat;
211 lwp = lwp_self();
212 struct rt_aspace_fault_msg msg = {
213 .fault_op = fault_op,
214 .fault_type = fault_type,
215 .fault_vaddr = (void *)stval,
216 };
217
218 __asm__ volatile("csrrsi %0, sstatus, 2" : "=r"(saved_stat));
219 if (lwp && rt_aspace_fault_try_fix(lwp->aspace, &msg))
220 {
221 __asm__ volatile("csrw sstatus, %0" ::"r"(saved_stat));
222 return;
223 }
224 __asm__ volatile("csrw sstatus, %0" ::"r"(saved_stat));
225 }
226 LOG_E("[FATAL ERROR] Exception %ld:%s\n", id, get_exception_msg(id));
227 LOG_E("scause:%p,stval:%p,sepc:%p\n", scause, stval, sepc);
228 dump_regs(sp);
229
230 rt_thread_t cur_thr = rt_thread_self();
231 struct rt_hw_backtrace_frame frame = {.fp = sp->s0_fp, .pc = sepc};
232 rt_kprintf("fp = %p\n", frame.fp);
233 lwp_backtrace_frame(cur_thr, &frame);
234
235 LOG_E("User Fault, killing thread: %s", cur_thr->parent.name);
236
237 EXIT_TRAP;
238 sys_exit_group(-1);
239 }
240 #endif
241
242 #ifdef ARCH_RISCV_VECTOR
vector_enable(struct rt_hw_stack_frame * sp)243 static void vector_enable(struct rt_hw_stack_frame *sp)
244 {
245 sp->sstatus |= SSTATUS_VS_INITIAL;
246 }
247
248 /**
249 * detect V/D support, and do not distinguish V/D instruction
250 */
illegal_inst_recoverable(rt_ubase_t stval,struct rt_hw_stack_frame * sp)251 static int illegal_inst_recoverable(rt_ubase_t stval,
252 struct rt_hw_stack_frame *sp)
253 {
254 // first 7 bits is opcode
255 int opcode = stval & 0x7f;
256 int csr = (stval & 0xFFF00000) >> 20;
257 // ref riscv-v-spec-1.0, [Vector Instruction Formats]
258 int width = ((stval & 0x7000) >> 12) - 1;
259 int flag = 0;
260
261 switch (opcode)
262 {
263 case 0x57: // V
264 case 0x27: // scalar FLOAT
265 case 0x07:
266 case 0x73: // CSR
267 flag = 1;
268 break;
269 }
270
271 if (flag)
272 {
273 vector_enable(sp);
274 }
275
276 return flag;
277 }
278 #endif
279
handle_nested_trap_panic(rt_ubase_t cause,rt_ubase_t tval,rt_ubase_t epc,struct rt_hw_stack_frame * eframe)280 static void handle_nested_trap_panic(rt_ubase_t cause, rt_ubase_t tval,
281 rt_ubase_t epc,
282 struct rt_hw_stack_frame *eframe)
283 {
284 LOG_E("\n-------- [SEVER ERROR] --------");
285 LOG_E("Nested trap detected");
286 LOG_E("scause:%p,stval:%p,sepc:%p\n", cause, tval, epc);
287 dump_regs(eframe);
288 rt_hw_cpu_shutdown();
289 }
290
291 #define IN_USER_SPACE (stval >= USER_VADDR_START && stval < USER_VADDR_TOP)
292 #define PAGE_FAULT (id == EP_LOAD_PAGE_FAULT || id == EP_STORE_PAGE_FAULT)
293
294 /* Trap entry */
handle_trap(rt_ubase_t scause,rt_ubase_t stval,rt_ubase_t sepc,struct rt_hw_stack_frame * sp)295 void handle_trap(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc,
296 struct rt_hw_stack_frame *sp)
297 {
298 ENTER_TRAP;
299 rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL));
300 const char *msg;
301
302 /* supervisor external interrupt */
303 if ((SCAUSE_INTERRUPT & scause) &&
304 SCAUSE_S_EXTERNAL_INTR == (scause & 0xff))
305 {
306 rt_interrupt_enter();
307 plic_handle_irq();
308 rt_interrupt_leave();
309 }
310 else if ((SCAUSE_INTERRUPT | SCAUSE_S_TIMER_INTR) == scause)
311 {
312 /* supervisor timer */
313 rt_interrupt_enter();
314 tick_isr();
315 rt_interrupt_leave();
316 }
317 else
318 {
319 if (SCAUSE_INTERRUPT & scause)
320 {
321 if (id < sizeof(Interrupt_Name) / sizeof(const char *))
322 {
323 msg = Interrupt_Name[id];
324 }
325 else
326 {
327 msg = "Unknown Interrupt";
328 }
329
330 LOG_E("Unhandled Interrupt %ld:%s\n", id, msg);
331 }
332 else
333 {
334 #ifdef ARCH_RISCV_VECTOR
335 if (scause == 0x2)
336 {
337 if (!(sp->sstatus & SSTATUS_VS) &&
338 illegal_inst_recoverable(stval, sp))
339 goto _exit;
340 }
341 #endif /* ARCH_RISCV_VECTOR */
342 #ifdef RT_USING_SMART
343 if (!(sp->sstatus & 0x100) || (PAGE_FAULT && IN_USER_SPACE))
344 {
345 handle_user(scause, stval, sepc, sp);
346 // if handle_user() return here, jump to u mode then
347 goto _exit;
348 }
349 #endif
350
351 // handle kernel exception:
352 rt_kprintf("Unhandled Exception %ld:%s\n", id,
353 get_exception_msg(id));
354 }
355
356 // trap cannot nested when handling another trap / interrupt
357 CHECK_NESTED_PANIC(scause, stval, sepc, sp);
358
359 rt_kprintf("scause:%p,stval:%p,sepc:%p\n", scause, stval, sepc);
360 dump_regs(sp);
361
362 rt_thread_t cur_thr = rt_thread_self();
363 rt_kprintf("--------------Thread list--------------\n");
364 rt_kprintf("current thread: %s\n", cur_thr->parent.name);
365
366 rt_kprintf("--------------Backtrace--------------\n");
367 struct rt_hw_backtrace_frame frame = {.fp = sp->s0_fp, .pc = sepc};
368
369 #ifdef RT_USING_SMART
370 if (!(sp->sstatus & 0x100))
371 {
372 lwp_backtrace_frame(cur_thr, &frame);
373 }
374 else
375 #endif
376 {
377 rt_backtrace_frame(cur_thr, &frame);
378 }
379
380 while (1)
381 ;
382 }
383 _exit:
384 EXIT_TRAP;
385 return;
386 }
387