trap.c 11 KB

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