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:
1 parent
e1248f4afe
commit
03bf767ac2
9 files changed
+425
-88
No files matched your search
+69
-18
@@ -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
@@ -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
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user