add missing fault handlers instead of throwing everything into the GP bin, add more ways to crash in native shell

This commit is contained in:
maksw authored and Maksymilian Wilczynski committed 2026-05-26 14:46:52 +02:00
1 parent e1248f4afe
commit 03bf767ac2
9 files changed
+425 -88

No files matched your search

+69 -18
View File
@@ -76,16 +76,66 @@ __declspec(dllexport) void KePrintConsole(const char* buf, size_t len) {
// can continue running everything else.
// ---------------------------------------------------------------------------
// Return the short exception name for a vector number.
// Return the short exception name for a CPU exception vector.
// Keep this table complete for vectors 0..31 so faults never collapse into
// a vague "general protection" bucket just because the IDT entry existed
// first or the crash printer lacked a name.
static const char* KiFaultVectorName(int vector) {
switch (vector) {
case 0: return "#DE Divide Error";
case 1: return "#DB Debug";
case 2: return "NMI Interrupt";
case 3: return "#BP Breakpoint";
case 4: return "#OF Overflow";
case 5: return "#BR Bound Range Exceeded";
case 6: return "#UD Invalid Opcode";
case 7: return "#NM Device Not Available";
case 8: return "#DF Double Fault";
case 9: return "Coprocessor Segment Overrun";
case 10: return "#TS Invalid TSS";
case 11: return "#NP Segment Not Present";
case 12: return "#SS Stack-Segment Fault";
case 13: return "#GP General Protection";
case 14: return "#PF Page Fault";
case 15: return "Reserved Exception 15";
case 16: return "#MF x87 Floating-Point Exception";
case 17: return "#AC Alignment Check";
case 18: return "#MC Machine Check";
case 19: return "#XM SIMD Floating-Point Exception";
case 20: return "#VE Virtualization Exception";
case 21: return "#CP Control Protection Exception";
case 22: return "Reserved Exception 22";
case 23: return "Reserved Exception 23";
case 24: return "Reserved Exception 24";
case 25: return "Reserved Exception 25";
case 26: return "Reserved Exception 26";
case 27: return "Reserved Exception 27";
case 28: return "#HV Hypervisor Injection Exception";
case 29: return "#VC VMM Communication Exception";
case 30: return "#SX Security Exception";
case 31: return "Reserved Exception 31";
default: return "Unknown Exception";
}
}
static int KiFaultHasErrorCode(int vector) {
switch (vector) {
case 8: // #DF
case 10: // #TS
case 11: // #NP
case 12: // #SS
case 13: // #GP
case 14: // #PF
case 17: // #AC
case 21: // #CP
case 29: // #VC
case 30: // #SX
return 1;
default:
return 0;
}
}
// Walk the process module list to find which image owns an address.
// Returns the module name string, or "unknown" if the address is outside all
// known image ranges. Base/size are optional and are useful for offset dumps.
@@ -391,23 +441,24 @@ __declspec(dllexport) _Noreturn void KeFaultDispatchFrame(const KFAULT_FRAME* fr
}
if ((frame->Cs & 3) == 0) {
switch ((int)frame->Vector) {
case 0:
KePanic("PANIC: #DE Divide Error | RIP: %016llx\n",
(unsigned long long)frame->Rip);
case 13:
KePanic("PANIC: #GP General Protection | RIP: %016llx | Code: %04llx\n",
(unsigned long long)frame->Rip,
(unsigned long long)frame->ErrorCode);
case 14:
KePanic("PANIC: #PF Page Fault | RIP: %016llx | Code: %04llx | CR2: %016llx\n",
(unsigned long long)frame->Rip,
(unsigned long long)frame->ErrorCode,
(unsigned long long)frame->Cr2);
default:
KePanic("PANIC: Exception #%llu | RIP: %016llx\n",
(unsigned long long)frame->Vector,
(unsigned long long)frame->Rip);
int vector = (int)frame->Vector;
const char* name = KiFaultVectorName(vector);
if (vector == 14) {
KePanic("PANIC: %s | RIP: %016llx | Code: %04llx | CR2: %016llx\n",
name,
(unsigned long long)frame->Rip,
(unsigned long long)frame->ErrorCode,
(unsigned long long)frame->Cr2);
} else if (KiFaultHasErrorCode(vector)) {
KePanic("PANIC: %s | RIP: %016llx | Code: %04llx\n",
name,
(unsigned long long)frame->Rip,
(unsigned long long)frame->ErrorCode);
} else {
KePanic("PANIC: %s | RIP: %016llx\n",
name,
(unsigned long long)frame->Rip);
}
}
+47 -3
View File
@@ -41,6 +41,36 @@ extern void KeIrqStub21(void);
extern void KeIrqStub22(void);
extern void KeIrqStub23(void);
extern void KeFaultDB(void);
extern void KeFaultNMI(void);
extern void KeFaultBP(void);
extern void KeFaultOF(void);
extern void KeFaultBR(void);
extern void KeFaultUD(void);
extern void KeFaultNM(void);
extern void KeFaultDF(void);
extern void KeFaultCSO(void);
extern void KeFaultTS(void);
extern void KeFaultNP(void);
extern void KeFaultSS(void);
extern void KeFaultRSV15(void);
extern void KeFaultMF(void);
extern void KeFaultAC(void);
extern void KeFaultMC(void);
extern void KeFaultXM(void);
extern void KeFaultVE(void);
extern void KeFaultCP(void);
extern void KeFaultRSV22(void);
extern void KeFaultRSV23(void);
extern void KeFaultRSV24(void);
extern void KeFaultRSV25(void);
extern void KeFaultRSV26(void);
extern void KeFaultRSV27(void);
extern void KeFaultHV(void);
extern void KeFaultVC(void);
extern void KeFaultSX(void);
extern void KeFaultRSV31(void);
#define NUM_IRQS 24
// ---------------------------------------------------------------------------
@@ -150,9 +180,23 @@ static void KiIdtSetGate(int vec, uintptr_t handler,
void KeInitializeIdt(void) {
memset(gIdt, 0, sizeof(gIdt));
KiIdtSetGate(0, (uintptr_t)KeFaultDE, 0x8E, 0);
KiIdtSetGate(13, (uintptr_t)KeFaultGP, 0x8E, 0);
KiIdtSetGate(14, (uintptr_t)KeFaultPF, 0x8E, 0);
static void* faultStubs[32] = {
(void*)KeFaultDE, (void*)KeFaultDB, (void*)KeFaultNMI,
(void*)KeFaultBP, (void*)KeFaultOF, (void*)KeFaultBR,
(void*)KeFaultUD, (void*)KeFaultNM, (void*)KeFaultDF,
(void*)KeFaultCSO, (void*)KeFaultTS, (void*)KeFaultNP,
(void*)KeFaultSS, (void*)KeFaultGP, (void*)KeFaultPF,
(void*)KeFaultRSV15, (void*)KeFaultMF, (void*)KeFaultAC,
(void*)KeFaultMC, (void*)KeFaultXM, (void*)KeFaultVE,
(void*)KeFaultCP, (void*)KeFaultRSV22, (void*)KeFaultRSV23,
(void*)KeFaultRSV24, (void*)KeFaultRSV25, (void*)KeFaultRSV26,
(void*)KeFaultRSV27, (void*)KeFaultHV, (void*)KeFaultVC,
(void*)KeFaultSX, (void*)KeFaultRSV31,
};
for (int i = 0; i < 32; i++)
KiIdtSetGate(i, (uintptr_t)faultStubs[i], 0x8E, 0);
KiIdtSetGate(0x40, (uintptr_t)KeSyscallEntry, 0xEE, 0);
static void *irqStubs[NUM_IRQS] = {
+35 -34
View File
@@ -1,34 +1,35 @@
#pragma once
// ke_idt.h - IDT, GDT, and TSS setup
#include <stdint.h>
// 64-bit TSS - minimal; we only care about RSP0.
#pragma pack(push, 1)
typedef struct TSS64 {
uint32_t Reserved0;
uint64_t RSP0; // loaded into RSP on ring-0 entry
uint64_t RSP1;
uint64_t RSP2;
uint64_t Reserved1;
uint64_t IST[7];
uint64_t Reserved2;
uint16_t Reserved3;
uint16_t IoMapBase;
} TSS64;
#pragma pack(pop)
extern TSS64* gTss;
void KeInitializeGdt(void);
void KeInitializeIdt(void);
// Called from hal_timer.c after HPET/APIC timer fires.
void KeTimerInterrupt(void);
// Syscall entry - implemented in ke_syscall.asm.
extern void KeSyscallEntry(void);
// Fault stubs installed by KeInitializeIdt.
extern void KeFaultDE(void); // #DE divide error
extern void KeFaultGP(void); // #GP general protection
extern void KeFaultPF(void); // #PF page fault
#pragma once
// ke_idt.h - IDT, GDT, and TSS setup
#include <stdint.h>
// 64-bit TSS - minimal; we only care about RSP0.
#pragma pack(push, 1)
typedef struct TSS64 {
uint32_t Reserved0;
uint64_t RSP0; // loaded into RSP on ring-0 entry
uint64_t RSP1;
uint64_t RSP2;
uint64_t Reserved1;
uint64_t IST[7];
uint64_t Reserved2;
uint16_t Reserved3;
uint16_t IoMapBase;
} TSS64;
#pragma pack(pop)
extern TSS64* gTss;
void KeInitializeGdt(void);
void KeInitializeIdt(void);
// Called from hal_timer.c after HPET/APIC timer fires.
void KeTimerInterrupt(void);
// Syscall entry - implemented in ke_syscall.asm.
extern void KeSyscallEntry(void);
// Fault stubs installed by KeInitializeIdt.
extern void KeFaultDE(void); // #DE divide error
extern void KeFaultGP(void); // #GP general protection
extern void KeFaultPF(void); // #PF page fault
extern void KeFaultUD(void); // #UD invalid opcode
+19
View File
@@ -477,6 +477,24 @@ static void KiRunIrpKernelApcSelfTest(const HAL_API* hal) {
// -------------------------------------------------------------------------
// Virtual memory mapping invariants
// -------------------------------------------------------------------------
static void KiRunMemoryMappingSelfTest(void) {
PHYSICAL_ADDRESS phys = 0;
uint64_t flags = 0;
KSTATUS s = MmQueryPage(0, &phys, &flags);
if (s != STATUS_NOT_FOUND) {
KePanic("MM selftest: virtual page zero is mapped phys=%016llx flags=%016llx status=%u\n",
(unsigned long long)phys,
(unsigned long long)flags,
(unsigned)s);
}
DbgPrint("MM selftest: page zero unmapped\n");
}
// -------------------------------------------------------------------------
// String-view ABI self-test
// -------------------------------------------------------------------------
@@ -732,6 +750,7 @@ static void KiRunTrapFrameSelfTest(void) {
void KiRunKernelSelfTests(const HAL_API* hal) {
DbgPrint("Kernel selftests: begin\n");
KiRunKernelApcSelfTest();
KiRunMemoryMappingSelfTest();
KiRunStringViewSelfTest();
KiRunIrpKernelApcSelfTest(hal);
KiRunAsyncFileIoSelfTest();
+161
View File
@@ -377,6 +377,167 @@ pf_call:
call KeFaultDispatchFrame
KeFaultPF ENDP
; ---------------------------------------------------------
; Generic CPU exception stubs.
; Each vector gets its own IDT entry and vector number so faults like #UD
; do not fall through an absent descriptor and reappear as #GP.
; ---------------------------------------------------------
FAULT_NOERR MACRO StubName, VecNum
LOCAL noerr_kernel_frame, noerr_call
StubName PROC
push rax
push r11
mov r11, rsp
sub rsp, KFAULT_SIZE
mov rax, rsp
mov [rax + KF_R10], r10
mov r10, KFAULT_MAGIC
mov [rax + KF_Magic], r10
mov qword ptr [rax + KF_Vector], VecNum
mov qword ptr [rax + KF_ErrorCode], 0
mov qword ptr [rax + KF_Cr2], 0
mov [rax + KF_Rcx], rcx
mov [rax + KF_Rdx], rdx
mov [rax + KF_Rbx], rbx
mov [rax + KF_Rbp], rbp
mov [rax + KF_Rsi], rsi
mov [rax + KF_Rdi], rdi
mov [rax + KF_R8], r8
mov [rax + KF_R9], r9
mov r10, [r11]
mov [rax + KF_R11], r10
mov r10, [r11+8]
mov [rax + KF_Rax], r10
mov [rax + KF_R12], r12
mov [rax + KF_R13], r13
mov [rax + KF_R14], r14
mov [rax + KF_R15], r15
lea rdx, [r11+16]
mov r10, [rdx]
mov [rax + KF_Rip], r10
mov r10, [rdx+8]
mov [rax + KF_Cs], r10
mov r10, [rdx+16]
mov [rax + KF_Rflags], r10
mov r10, [rax + KF_Cs]
test r10, 3
jz noerr_kernel_frame
mov r10, [rdx+24]
mov [rax + KF_Rsp], r10
mov r10, [rdx+32]
mov [rax + KF_Ss], r10
jmp noerr_call
noerr_kernel_frame:
mov qword ptr [rax + KF_Rsp], 0
mov qword ptr [rax + KF_Ss], 0
noerr_call:
and rsp, -16
sub rsp, FAULT_CALL_SHADOW
mov rcx, rax
call KeFaultDispatchFrame
StubName ENDP
ENDM
FAULT_ERR MACRO StubName, VecNum
LOCAL err_kernel_frame, err_call
StubName PROC
push rax
push r11
mov r11, rsp
sub rsp, KFAULT_SIZE
mov rax, rsp
mov [rax + KF_R10], r10
mov r10, KFAULT_MAGIC
mov [rax + KF_Magic], r10
mov qword ptr [rax + KF_Vector], VecNum
mov qword ptr [rax + KF_Cr2], 0
mov [rax + KF_Rcx], rcx
mov [rax + KF_Rdx], rdx
mov [rax + KF_Rbx], rbx
mov [rax + KF_Rbp], rbp
mov [rax + KF_Rsi], rsi
mov [rax + KF_Rdi], rdi
mov [rax + KF_R8], r8
mov [rax + KF_R9], r9
mov r10, [r11]
mov [rax + KF_R11], r10
mov r10, [r11+8]
mov [rax + KF_Rax], r10
mov [rax + KF_R12], r12
mov [rax + KF_R13], r13
mov [rax + KF_R14], r14
mov [rax + KF_R15], r15
lea rdx, [r11+16]
mov r10, [rdx]
mov [rax + KF_ErrorCode], r10
mov r10, [rdx+8]
mov [rax + KF_Rip], r10
mov r10, [rdx+16]
mov [rax + KF_Cs], r10
mov r10, [rdx+24]
mov [rax + KF_Rflags], r10
mov r10, [rax + KF_Cs]
test r10, 3
jz err_kernel_frame
mov r10, [rdx+32]
mov [rax + KF_Rsp], r10
mov r10, [rdx+40]
mov [rax + KF_Ss], r10
jmp err_call
err_kernel_frame:
mov qword ptr [rax + KF_Rsp], 0
mov qword ptr [rax + KF_Ss], 0
err_call:
and rsp, -16
sub rsp, FAULT_CALL_SHADOW
mov rcx, rax
call KeFaultDispatchFrame
StubName ENDP
ENDM
FAULT_NOERR KeFaultDB, 1
FAULT_NOERR KeFaultNMI, 2
FAULT_NOERR KeFaultBP, 3
FAULT_NOERR KeFaultOF, 4
FAULT_NOERR KeFaultBR, 5
FAULT_NOERR KeFaultUD, 6
FAULT_NOERR KeFaultNM, 7
FAULT_ERR KeFaultDF, 8
FAULT_NOERR KeFaultCSO, 9
FAULT_ERR KeFaultTS, 10
FAULT_ERR KeFaultNP, 11
FAULT_ERR KeFaultSS, 12
FAULT_NOERR KeFaultRSV15, 15
FAULT_NOERR KeFaultMF, 16
FAULT_ERR KeFaultAC, 17
FAULT_NOERR KeFaultMC, 18
FAULT_NOERR KeFaultXM, 19
FAULT_NOERR KeFaultVE, 20
FAULT_ERR KeFaultCP, 21
FAULT_NOERR KeFaultRSV22, 22
FAULT_NOERR KeFaultRSV23, 23
FAULT_NOERR KeFaultRSV24, 24
FAULT_NOERR KeFaultRSV25, 25
FAULT_NOERR KeFaultRSV26, 26
FAULT_NOERR KeFaultRSV27, 27
FAULT_NOERR KeFaultHV, 28
FAULT_ERR KeFaultVC, 29
FAULT_ERR KeFaultSX, 30
FAULT_NOERR KeFaultRSV31, 31
EXTERN KeIrqDispatch:PROC
EXTERN KiEnterInterrupt:PROC
EXTERN KiExitInterrupt:PROC