interrupt.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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-07-14 JasonHu first version
  9. */
  10. #include <rtthread.h>
  11. #include <rthw.h>
  12. #include <rtdbg.h>
  13. #include <rtconfig.h>
  14. #include <interrupt.h>
  15. #include <stackframe.h>
  16. #include <backtrace.h>
  17. #include <pic.h>
  18. #include <lwp_arch.h>
  19. #ifdef RT_USING_SIGNALS
  20. #include <lwp_signal.h>
  21. #endif /* RT_USING_SIGNALS */
  22. enum HW_EXCEPTION_TYPE
  23. {
  24. HW_EXCEPT_DIVIDE = 0, /* Division error: DIV and IDIV instructions */
  25. HW_EXCEPT_DEBUG, /* Debugging exceptions: access to any code and data */
  26. HW_EXCEPT_INTERRUPT, /* Unshielded interrupt: Unshielded external interrupt */
  27. HW_EXCEPT_BREAKPOINT, /* Debug breakpoint: instruction INT3 */
  28. HW_EXCEPT_OVERFLOW, /* Overflow: instruction INTO */
  29. HW_EXCEPT_BOUND_RANGE, /* Out of bounds: command BOUND */
  30. HW_EXCEPT_INVALID_OPCODE, /* Invalid (undefined) opcode:
  31. instruction UD2 or invalid instruction */
  32. HW_EXCEPT_DEVICE_NOT_AVAILABLE, /* Device unavailable (no math processor):
  33. floating point or WAIT/FWAIT instructions */
  34. HW_EXCEPT_DOUBLE_FAULT, /* Double error: all instructions that can generate an exception
  35. or NMI or INTR */
  36. HW_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN, /* Assist the processor segment to cross the boundary:
  37. floating-point instructions (IA32 processors after 386
  38. no longer generate such exceptions) */
  39. HW_EXCEPT_INVALID_TSS, /* Invalid TSS: When switching tasks or accessing TSS */
  40. HW_EXCEPT_SEGMENT_NOT_PRESENT, /* Segment does not exist: when loading segment registers
  41. or accessing system segments */
  42. HW_EXCEPT_STACK_FAULT, /* Stack segmentation error: stack operation or loading SS */
  43. HW_EXCEPT_GENERAL_PROTECTION, /* General protection error: memory or other protection check */
  44. HW_EXCEPT_PAGE_FAULT, /* Page fault: memory access */
  45. HW_EXCEPT_RESERVED, /* INTEL reserved, not used */
  46. HW_EXCEPT_X87_FLOAT_POINT, /* X87FPU floating point error (math error):
  47. X87FPU floating point instruction or WAIT/FWAIIT instruction */
  48. HW_EXCEPT_ALIGNMENT_CHECK, /* Alignment check: data access in memory (supported from 486) */
  49. HW_EXCEPT_MACHINE_CHECK, /* Machine Check: The error code (if any) and source
  50. depend on the specific mode (Pentium CPU starts to support) */
  51. HW_EXCEPT_SIMD_FLOAT_POINT, /* SIMD floating-point exceptions: SSE and SSE2 floating-point
  52. instructions (supported by Pentium III) */
  53. };
  54. typedef void (*rt_hw_intr_handler_t)(rt_hw_stack_frame_t *);
  55. static rt_hw_intr_handler_t interrupt_handlers[MAX_INTR_NR] = {0};
  56. static struct rt_irq_desc irq_desc[MAX_IRQ_NR] = {0};
  57. static char *hw_exception_names[] = {
  58. "#DE Divide Error",
  59. "#DB Debug Exception",
  60. "NMI Interrupt",
  61. "#BP Breakpoint Exception",
  62. "#OF Overflow Exception",
  63. "#BR BOUND Range Exceeded Exception",
  64. "#UD Invalid Opcode Exception",
  65. "#NM Device Not Available Exception",
  66. "#DF Double Fault Exception",
  67. "Coprocessor Segment Overrun",
  68. "#TS Invalid TSS Exception",
  69. "#NP Segment Not Present",
  70. "#SS Stack Fault Exception",
  71. "#GP General Protection Exception",
  72. "#PF Page-Fault Exception",
  73. "Reserved",
  74. "#MF x87 FPU Floating-Point Error",
  75. "#AC Alignment Check Exception",
  76. "#MC Machine-Check Exception",
  77. "#XF SIMD Floating-Point Exception",
  78. "Unknown Exception"
  79. };
  80. static void exception_frame_dump(rt_hw_stack_frame_t *frame);
  81. static void rt_hw_interrupt_handle(int vector, void *param)
  82. {
  83. rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
  84. }
  85. static void hw_general_handler(rt_hw_stack_frame_t *frame)
  86. {
  87. rt_kprintf("general intr %d handled\n", frame->vec_no);
  88. }
  89. static void hw_external_handler(rt_hw_stack_frame_t *frame)
  90. {
  91. int irqno = frame->vec_no - IRQ_INTR_BASE;
  92. if (irqno < 0 || irqno >= MAX_IRQ_NR)
  93. {
  94. dbg_log(DBG_ERROR, "unknown IRQ %d occurred!!\n", irqno);
  95. return;
  96. }
  97. irq_desc[irqno].handler(irqno, irq_desc[irqno].param);
  98. rt_hw_pic_ack(irqno);
  99. }
  100. #ifdef RT_USING_LWP
  101. static int check_user_stack(rt_hw_stack_frame_t *frame)
  102. {
  103. if (frame->vec_no == EXCEPTION_PAGE_FAULT)
  104. {
  105. void *fault_addr = (void *)read_cr2(); // get page fault addr
  106. rt_interrupt_leave();
  107. if (arch_expand_user_stack(fault_addr))
  108. {
  109. rt_interrupt_enter();
  110. return 1;
  111. }
  112. rt_interrupt_enter();
  113. }
  114. return 0;
  115. }
  116. #endif /* RT_USING_LWP */
  117. static void hw_exception_handler(rt_hw_stack_frame_t *frame)
  118. {
  119. #ifdef RT_USING_LWP
  120. if (check_user_stack(frame))
  121. return;
  122. #endif /* RT_USING_LWP */
  123. rt_thread_t cur = rt_thread_self();
  124. rt_kprintf("thread name: %s\n", cur->name);
  125. #ifdef RT_USING_LWP
  126. if (cur->lwp)
  127. {
  128. struct rt_lwp *lwp = cur->lwp;
  129. rt_kprintf("thread id:%d\n", lwp->pid);
  130. }
  131. #endif /* RT_USING_LWP */
  132. exception_frame_dump(frame);
  133. rt_hw_print_backtrace();
  134. #ifdef RT_USING_SIGNALS
  135. dbg_log(DBG_ERROR, "[exception] send signal to thread %s\n", rt_thread_self()->name);
  136. /* send signal to thread */
  137. switch (frame->vec_no)
  138. {
  139. case HW_EXCEPT_DIVIDE:
  140. case HW_EXCEPT_INVALID_OPCODE:
  141. lwp_thread_kill(rt_thread_self(), SIGILL);
  142. return;
  143. case HW_EXCEPT_DEVICE_NOT_AVAILABLE:
  144. lwp_thread_kill(rt_thread_self(), SIGIO);
  145. return;
  146. case HW_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN:
  147. case HW_EXCEPT_X87_FLOAT_POINT:
  148. case HW_EXCEPT_SIMD_FLOAT_POINT:
  149. lwp_thread_kill(rt_thread_self(), SIGFPE);
  150. return;
  151. case HW_EXCEPT_OVERFLOW:
  152. case HW_EXCEPT_BOUND_RANGE:
  153. case HW_EXCEPT_INVALID_TSS:
  154. case HW_EXCEPT_ALIGNMENT_CHECK:
  155. lwp_thread_kill(rt_thread_self(), SIGBUS);
  156. return;
  157. case HW_EXCEPT_SEGMENT_NOT_PRESENT:
  158. case HW_EXCEPT_GENERAL_PROTECTION:
  159. lwp_thread_kill(rt_thread_self(), SIGSEGV);
  160. return;
  161. case HW_EXCEPT_STACK_FAULT:
  162. lwp_thread_kill(rt_thread_self(), SIGSTKFLT);
  163. return;
  164. case HW_EXCEPT_MACHINE_CHECK:
  165. case HW_EXCEPT_INTERRUPT:
  166. lwp_thread_kill(rt_thread_self(), SIGINT);
  167. return;
  168. case HW_EXCEPT_DOUBLE_FAULT:
  169. lwp_thread_kill(rt_thread_self(), SIGKILL);
  170. return;
  171. case HW_EXCEPT_DEBUG:
  172. case HW_EXCEPT_BREAKPOINT:
  173. lwp_thread_kill(rt_thread_self(), SIGTRAP);
  174. return;
  175. default:
  176. break;
  177. }
  178. #endif
  179. /* unhandled exception */
  180. rt_hw_interrupt_disable();
  181. for (;;)
  182. {
  183. }
  184. }
  185. rt_base_t rt_hw_interrupt_disable(void)
  186. {
  187. rt_base_t level;
  188. __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (level): :"memory");
  189. return level;
  190. }
  191. void rt_hw_interrupt_enable(rt_base_t level)
  192. {
  193. __asm__ __volatile__("pushl %0 ; popfl": :"g" (level):"memory", "cc");
  194. }
  195. void rt_hw_interrupt_dispatch(rt_hw_stack_frame_t *frame)
  196. {
  197. rt_ubase_t vec_no = frame->vec_no;
  198. if (vec_no < 0 || vec_no >= MAX_INTR_NR)
  199. {
  200. dbg_log(DBG_ERROR, "unknown intr vector %x!\n", frame->vec_no);
  201. return;
  202. }
  203. interrupt_handlers[vec_no](frame);
  204. }
  205. void rt_hw_stack_frame_dump(rt_hw_stack_frame_t *frame)
  206. {
  207. rt_kprintf("edi:%x\nesi:%x\nebp:%x\nesp dummy:%x\nebx:%x\nedx:%x\necx:%x\neax:%x\n",
  208. frame->edi, frame->esi, frame->ebp, frame->esp_dummy,
  209. frame->ebx, frame->edx, frame->ecx, frame->eax);
  210. rt_kprintf("gs:%x\nfs:%x\nes:%x\nds:%x\nerror code:%x\neip:%x\ncs:%x\neflags:%x\nesp:%x\nss:%x\n",
  211. frame->gs, frame->fs, frame->es, frame->ds, frame->error_code,
  212. frame->eip, frame->cs, frame->eflags, frame->esp, frame->ss);
  213. }
  214. static void exception_frame_dump(rt_hw_stack_frame_t *frame)
  215. {
  216. rt_kprintf("\n!!! Stack frame: exception name %s\n", hw_exception_names[frame->vec_no]);
  217. if (frame->vec_no == 14)
  218. {
  219. rt_kprintf("page fault addr: %p\n", read_cr2());
  220. }
  221. rt_hw_stack_frame_dump(frame);
  222. if (frame->error_code != 0xFFFFFFFF)
  223. {
  224. if (frame->error_code & 1)
  225. {
  226. rt_kprintf(" External Event: NMI,hard interruption,ect.\n");
  227. }
  228. else
  229. {
  230. rt_kprintf(" Not External Event: inside.\n");
  231. }
  232. if (frame->error_code & (1 << 1))
  233. {
  234. rt_kprintf(" IDT: selector in idt.\n");
  235. }
  236. else
  237. {
  238. rt_kprintf(" IDT: selector in gdt or ldt.\n");
  239. }
  240. if(frame->error_code & (1 <<2 ))
  241. {
  242. rt_kprintf(" TI: selector in ldt.\n");
  243. }
  244. else
  245. {
  246. rt_kprintf(" TI: selector in gdt.\n");
  247. }
  248. rt_kprintf(" Selector: idx %d\n", (frame->error_code&0xfff8)>>3);
  249. }
  250. }
  251. /**
  252. * This function will mask a interrupt.
  253. * @param vector the interrupt number
  254. */
  255. void rt_hw_interrupt_mask(int vector)
  256. {
  257. rt_hw_pic_disable(vector);
  258. }
  259. /**
  260. * This function will un-mask a interrupt.
  261. * @param vector the interrupt number
  262. */
  263. void rt_hw_interrupt_umask(int vector)
  264. {
  265. rt_hw_pic_enable(vector);
  266. }
  267. /**
  268. * This function will install a interrupt service routine to a interrupt.
  269. * @param vector the interrupt number
  270. * @param new_handler the interrupt service routine to be installed
  271. * @param old_handler the old interrupt service routine
  272. */
  273. rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
  274. void *param, const char *name)
  275. {
  276. rt_isr_handler_t old_handler = RT_NULL;
  277. if(vector < MAX_IRQ_NR)
  278. {
  279. old_handler = irq_desc[vector].handler;
  280. if (handler != RT_NULL)
  281. {
  282. irq_desc[vector].handler = (rt_isr_handler_t)handler;
  283. irq_desc[vector].param = param;
  284. #ifdef RT_USING_INTERRUPT_INFO
  285. rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
  286. irq_desc[vector].counter = 0;
  287. #endif
  288. }
  289. }
  290. return old_handler;
  291. }
  292. extern volatile rt_ubase_t rt_interrupt_from_thread;
  293. extern volatile rt_ubase_t rt_interrupt_to_thread;
  294. extern volatile rt_ubase_t rt_thread_switch_interrupt_flag;
  295. /**
  296. * This function will initialize hardware interrupt
  297. */
  298. void rt_hw_interrupt_init(void)
  299. {
  300. rt_interrupt_from_thread = 0;
  301. rt_interrupt_to_thread = 0;
  302. rt_thread_switch_interrupt_flag = 0;
  303. int i;
  304. for (i = 0; i < MAX_INTR_NR; i++)
  305. {
  306. if (i < IRQ_INTR_BASE)
  307. {
  308. interrupt_handlers[i] = hw_exception_handler;
  309. }
  310. else if (i >= IRQ_INTR_BASE && i < IRQ_INTR_BASE + MAX_IRQ_NR)
  311. {
  312. interrupt_handlers[i] = hw_external_handler;
  313. }
  314. else
  315. {
  316. interrupt_handlers[i] = hw_general_handler;
  317. }
  318. }
  319. for (i = 0; i < MAX_IRQ_NR; i++)
  320. {
  321. irq_desc[i].handler = rt_hw_interrupt_handle;
  322. irq_desc[i].param = RT_NULL;
  323. #ifdef RT_USING_INTERRUPT_INFO
  324. rt_snprintf(irq_desc[i].name, RT_NAME_MAX - 1, "default");
  325. irq_desc[i].counter = 0;
  326. #endif
  327. }
  328. /* init intr controller */
  329. rt_hw_pic_init();
  330. }