| 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 | |
| 15 | enum 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 | |
| 79 | MAKE_HANDLER(divbyz, "Division by zero" ); |
| 80 | MAKE_HANDLER(debug, "Debug signal" ); |
| 81 | MAKE_HANDLER(breakpoint, "Breakpoint" ); |
| 82 | MAKE_HANDLER(ss, "STACK SEGMENT FAULT" ); |
| 83 | MAKE_HANDLER(double_fault, "DOUBLE FAULT" ); |
| 84 | |
| 85 | enum 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 | |
| 95 | enum 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 | |