trap.c 13 KB

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