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
26enum 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
84MAKE_HANDLER(divbyz, "Division by zero");
85MAKE_HANDLER(debug, "Debug signal");
86MAKE_HANDLER(breakpoint, "Breakpoint");
87MAKE_HANDLER(ss, "STACK SEGMENT FAULT");
88MAKE_HANDLER(double_fault, "DOUBLE FAULT");
89
90enum 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
103enum 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
127enum 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
133enum 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