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