| 1 | #include <console/crash.h> |
| 2 | #include <console/panic.h> |
| 3 | |
| 4 | #define MAKE_HANDLER(handler_name, message) \ |
| 5 | enum irq_result handler_name##_handler(void *ctx, uint8_t vector, \ |
| 6 | struct irq_context *rsp) { \ |
| 7 | (void) ctx; \ |
| 8 | (void) vector; \ |
| 9 | struct crash_regs pregs; \ |
| 10 | irq_context_to_crash_regs(rsp, &pregs); \ |
| 11 | char msg[CRASH_MSG_MAX]; \ |
| 12 | snprintf(msg, sizeof(msg), "CPU %u fault: " message " at %p", \ |
| 13 | (uint32_t) smp_id_raw(), (void *) rsp->rip); \ |
| 14 | crash_full(&(struct crash_context) { \ |
| 15 | .source = CRASH_SOURCE_CPU_EXCEPTION, \ |
| 16 | .formats = CRASH_FMT_DEFAULT, \ |
| 17 | .file = __FILE__, \ |
| 18 | .line = __LINE__, \ |
| 19 | .func = #handler_name "_handler", \ |
| 20 | .msg = msg, \ |
| 21 | .regs = &pregs, \ |
| 22 | }); \ |
| 23 | return IRQ_HANDLED; \ |
| 24 | } |
| 25 | |
| 26 | enum irq_result gpf_handler(void *ctx, uint8_t vector, |
| 27 | struct irq_context *rsp) { |
| 28 | (void) ctx; |
| 29 | (void) vector; |
| 30 | |
| 31 | uint64_t core = smp_id_raw(); |
| 32 | uint64_t ec = rsp->error_code; |
| 33 | |
| 34 | printf(format: "\n=== General Protection Fault ===\n" ); |
| 35 | printf(format: "Core: %u\n" , (uint32_t) core); |
| 36 | printf(format: "RIP: %p\n" , (void *) rsp->rip); |
| 37 | printf(format: "RSP: %p\n" , (void *) rsp->rsp); |
| 38 | printf(format: "RBP: %p\n" , (void *) rsp->rbp); |
| 39 | printf(format: "CS: 0x%04x\n" , (uint16_t) rsp->cs); |
| 40 | printf(format: "SS: 0x%04x\n" , (uint16_t) rsp->ss); |
| 41 | printf(format: "RFLAGS: 0x%016lx\n" , rsp->rflags); |
| 42 | |
| 43 | printf(format: "\nError code: 0x%04lx\n" , ec); |
| 44 | if (ec == 0) { |
| 45 | printf(format: " (no selector; likely a non-canonical access, " |
| 46 | "null deref, or privilege violation)\n" ); |
| 47 | } else { |
| 48 | bool ext = ec & 1; |
| 49 | uint8_t tbl = (ec >> 1) & 0x3; |
| 50 | uint16_t index = (ec >> 3) & 0x1FFF; |
| 51 | |
| 52 | const char *tbl_name; |
| 53 | switch (tbl) { |
| 54 | case 0: tbl_name = "GDT" ; break; |
| 55 | case 1: tbl_name = "IDT" ; break; |
| 56 | case 2: tbl_name = "LDT" ; break; |
| 57 | case 3: tbl_name = "IDT" ; break; |
| 58 | default: tbl_name = "unknown" ; break; |
| 59 | } |
| 60 | |
| 61 | printf(format: " External: %s\n" , ext ? "yes (hardware)" : "no (software)" ); |
| 62 | printf(format: " Table: %s\n" , tbl_name); |
| 63 | printf(format: " Selector: %u (0x%x)\n" , index, index); |
| 64 | } |
| 65 | |
| 66 | struct crash_regs pregs; |
| 67 | irq_context_to_crash_regs(ictx: rsp, out: &pregs); |
| 68 | char msg[CRASH_MSG_MAX]; |
| 69 | snprintf(buffer: msg, buffer_len: sizeof(msg), format: "GPF on core %u at %p (error code 0x%lx)" , |
| 70 | (uint32_t) core, (void *) rsp->rip, ec); |
| 71 | crash_full(ctx: &(struct crash_context) { |
| 72 | .source = CRASH_SOURCE_CPU_EXCEPTION, |
| 73 | .formats = CRASH_FMT_DEFAULT, |
| 74 | .file = __FILE__, |
| 75 | .line = __LINE__, |
| 76 | .func = __func__, |
| 77 | .msg = msg, |
| 78 | .regs = &pregs, |
| 79 | }); |
| 80 | |
| 81 | return IRQ_HANDLED; |
| 82 | } |
| 83 | |
| 84 | MAKE_HANDLER(divbyz, "Division by zero" ); |
| 85 | MAKE_HANDLER(debug, "Debug signal" ); |
| 86 | MAKE_HANDLER(breakpoint, "Breakpoint" ); |
| 87 | MAKE_HANDLER(ss, "STACK SEGMENT FAULT" ); |
| 88 | MAKE_HANDLER(double_fault, "DOUBLE FAULT" ); |
| 89 | |
| 90 | enum irq_result panic_nmi_isr(void *ctx, uint8_t vector, |
| 91 | struct irq_context *rsp) { |
| 92 | (void) ctx, (void) vector, (void) rsp; |
| 93 | if (atomic_load(&global.panicked)) { |
| 94 | if (crash_cpu_is_owner(id: smp_id_raw())) |
| 95 | return IRQ_HANDLED; |
| 96 | |
| 97 | crash_nmi_handoff(p: ctx, ctx: rsp); |
| 98 | } |
| 99 | |
| 100 | return IRQ_NONE; |
| 101 | } |
| 102 | |
| 103 | enum irq_result hw_error_nmi_isr(void *ctx, uint8_t vector, |
| 104 | struct irq_context *ictx) { |
| 105 | (void) ctx; |
| 106 | (void) vector; |
| 107 | (void) ictx; |
| 108 | uint8_t port61 = inb(port: 0x61); |
| 109 | if (port61 & 0xC0) { |
| 110 | char msg[CRASH_MSG_MAX]; |
| 111 | snprintf(buffer: msg, buffer_len: sizeof(msg), |
| 112 | format: "Hardware / Memory Parity NMI Error (Port 0x61 = 0x%02x)" , |
| 113 | port61); |
| 114 | crash_full(ctx: &(struct crash_context) { |
| 115 | .source = CRASH_SOURCE_CPU_EXCEPTION, |
| 116 | .formats = CRASH_FMT_DEFAULT, |
| 117 | .file = __FILE__, |
| 118 | .line = __LINE__, |
| 119 | .func = __func__, |
| 120 | .msg = msg, |
| 121 | }); |
| 122 | } |
| 123 | |
| 124 | return IRQ_NONE; |
| 125 | } |
| 126 | |
| 127 | enum irq_result nop_handler(void *ctx, uint8_t vector, |
| 128 | struct irq_context *rsp) { |
| 129 | (void) ctx, (void) vector, (void) rsp; |
| 130 | return IRQ_HANDLED; |
| 131 | } |
| 132 | |
| 133 | enum irq_result dpc_handler(void *ctx, uint8_t vector, |
| 134 | struct irq_context *rsp) { |
| 135 | scheduler_mark_self_needs_run_dpcs(true); |
| 136 | (void) ctx, (void) vector, (void) rsp; |
| 137 | return IRQ_HANDLED; |
| 138 | } |
| 139 | |