1#define MAKE_HANDLER(handler_name, message) \
2 enum irq_result handler_name##_handler(void *ctx, uint8_t vector, \
3 struct irq_context *rsp) { \
4 (void) ctx, (void) vector, (void) rsp; \
5 uint64_t core = smp_core_id(); \
6 printf("\n=== " #handler_name " fault! ===\n"); \
7 printf("Message -> %s\n", message); \
8 panic("Core %u faulted at %p", core, rsp->rip); \
9 while (true) { \
10 wait_for_interrupt(); \
11 } \
12 return IRQ_HANDLED; \
13 }
14
15enum irq_result gpf_handler(void *ctx, uint8_t vector,
16 struct irq_context *rsp) {
17 (void) ctx;
18 (void) vector;
19
20 uint64_t core = smp_core_id();
21 uint64_t ec = rsp->error_code;
22
23 printf(format: "\n=== General Protection Fault ===\n");
24 printf(format: "Core: %u\n", core);
25 printf(format: "RIP: %p\n", rsp->rip);
26 printf(format: "RSP: %p\n", rsp->rsp);
27 printf(format: "RBP: %p\n", rsp->rbp);
28 printf(format: "CS: 0x%04x\n", rsp->cs);
29 printf(format: "SS: 0x%04x\n", rsp->ss);
30 printf(format: "RFLAGS: 0x%016lx\n", rsp->rflags);
31
32 printf(format: "\nError code: 0x%04lx\n", ec);
33 if (ec == 0) {
34 printf(format: " (no selector; likely a non-canonical access, "
35 "null deref, or privilege violation)\n");
36 } else {
37 bool ext = ec & 1;
38 uint8_t tbl = (ec >> 1) & 0x3;
39 uint16_t index = (ec >> 3) & 0x1FFF;
40
41 const char *tbl_name;
42 switch (tbl) {
43 case 0: tbl_name = "GDT"; break;
44 case 1: tbl_name = "IDT"; break;
45 case 2: tbl_name = "LDT"; break;
46 case 3: tbl_name = "IDT"; break;
47 default: tbl_name = "unknown"; break;
48 }
49
50 printf(format: " External: %s\n", ext ? "yes (hardware)" : "no (software)");
51 printf(format: " Table: %s\n", tbl_name);
52 printf(format: " Selector: %u (0x%x)\n", index, index);
53 }
54
55 printf(format: "\nRegister dump:\n");
56 printf(format: " RAX=%016lx RBX=%016lx\n", rsp->rax, rsp->rbx);
57 printf(format: " RCX=%016lx RDX=%016lx\n", rsp->rcx, rsp->rdx);
58 printf(format: " RDI=%016lx RSI=%016lx\n", rsp->rdi, rsp->rsi);
59 printf(format: " R8 =%016lx R9 =%016lx\n", rsp->r8, rsp->r9);
60 printf(format: " R10=%016lx R11=%016lx\n", rsp->r10, rsp->r11);
61 printf(format: " R12=%016lx R13=%016lx\n", rsp->r12, rsp->r13);
62 printf(format: " R14=%016lx R15=%016lx\n", rsp->r14, rsp->r15);
63
64 uint64_t cr2, cr3;
65 __asm__ volatile("mov %%cr2, %0" : "=r"(cr2));
66 __asm__ volatile("mov %%cr3, %0" : "=r"(cr3));
67 printf(format: "\n CR2=%016lx CR3=%016lx\n", cr2, cr3);
68 printf(format: "\n--- Stack at fault RSP ---\n");
69 debug_print_stack_from(start: (uint64_t *) rsp->rsp, max_scan: 0);
70
71 panic("GPF on core %u at %p (error code 0x%lx)", core, rsp->rip, ec);
72
73 while (true)
74 wait_for_interrupt();
75
76 return IRQ_HANDLED;
77}
78
79MAKE_HANDLER(divbyz, "Division by zero");
80MAKE_HANDLER(debug, "Debug signal");
81MAKE_HANDLER(breakpoint, "Breakpoint");
82MAKE_HANDLER(ss, "STACK SEGMENT FAULT");
83MAKE_HANDLER(double_fault, "DOUBLE FAULT");
84
85enum irq_result nmi_isr(void *ctx, uint8_t vector, struct irq_context *rsp) {
86 (void) ctx, (void) vector, (void) rsp;
87 if (atomic_load(&global.panicked)) {
88 disable_interrupts();
89 while (true)
90 wait_for_interrupt();
91 }
92 return IRQ_HANDLED;
93}
94
95enum irq_result nop_handler(void *ctx, uint8_t vector,
96 struct irq_context *rsp) {
97 (void) ctx, (void) vector, (void) rsp;
98 return IRQ_HANDLED;
99}
100