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

Binary file not shown.
+54 -30
View File
@@ -745,36 +745,60 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
EFI_MEMORY_DESCRIPTOR* efiMap = AllocatePool(mapSize); EFI_MEMORY_DESCRIPTOR* efiMap = AllocatePool(mapSize);
gBS->GetMemoryMap(&mapSize, efiMap, &mapKey, &descSz, &descVer); gBS->GetMemoryMap(&mapSize, efiMap, &mapKey, &descSz, &descVer);
{ {
UINT64 idHoles[4]; UINT64 idHoles[8];
UINT64 winHoles[4]; UINT64 winHoles[8];
UINTN holeCount = 0; UINTN idHoleCount = 0;
if (fbBytes) { UINTN winHoleCount = 0;
idHoles[holeCount * 2 + 0] = fbBase;
idHoles[holeCount * 2 + 1] = fbBase + fbBytes;
winHoles[holeCount * 2 + 0] = PHYS_MAP_BASE + fbBase;
winHoles[holeCount * 2 + 1] = PHYS_MAP_BASE + fbBase + fbBytes;
holeCount++;
}
idHoles[holeCount * 2 + 0] = 0xFEC00000ULL;
idHoles[holeCount * 2 + 1] = 0xFEE01000ULL;
winHoles[holeCount * 2 + 0] = PHYS_MAP_BASE + 0xFEC00000ULL;
winHoles[holeCount * 2 + 1] = PHYS_MAP_BASE + 0xFEE01000ULL;
holeCount++;
if (holeCount == 2) { // Leave virtual page zero genuinely unmapped. Mapping it supervisor/NX
if (idHoles[2] < idHoles[0]) { // still hides null pointer bugs from the page-fault path and makes
UINT64 t0 = idHoles[0], t1 = idHoles[1]; // diagnostics worse. The physical-window alias for frame zero remains
idHoles[0] = idHoles[2]; // available at PHYS_MAP_BASE if low physical memory is ever needed.
idHoles[1] = idHoles[3]; idHoles[idHoleCount * 2 + 0] = 0;
idHoles[2] = t0; idHoles[idHoleCount * 2 + 1] = PAGE_SIZE;
idHoles[3] = t1; idHoleCount++;
if (fbBytes) {
idHoles[idHoleCount * 2 + 0] = fbBase;
idHoles[idHoleCount * 2 + 1] = fbBase + fbBytes;
idHoleCount++;
winHoles[winHoleCount * 2 + 0] = PHYS_MAP_BASE + fbBase;
winHoles[winHoleCount * 2 + 1] = PHYS_MAP_BASE + fbBase + fbBytes;
winHoleCount++;
}
idHoles[idHoleCount * 2 + 0] = 0xFEC00000ULL;
idHoles[idHoleCount * 2 + 1] = 0xFEE01000ULL;
idHoleCount++;
winHoles[winHoleCount * 2 + 0] = PHYS_MAP_BASE + 0xFEC00000ULL;
winHoles[winHoleCount * 2 + 1] = PHYS_MAP_BASE + 0xFEE01000ULL;
winHoleCount++;
for (UINTN pass = 0; pass < idHoleCount; pass++) {
for (UINTN i = 1; i < idHoleCount; i++) {
if (idHoles[i * 2] < idHoles[(i - 1) * 2]) {
UINT64 s0 = idHoles[(i - 1) * 2 + 0];
UINT64 e0 = idHoles[(i - 1) * 2 + 1];
idHoles[(i - 1) * 2 + 0] = idHoles[i * 2 + 0];
idHoles[(i - 1) * 2 + 1] = idHoles[i * 2 + 1];
idHoles[i * 2 + 0] = s0;
idHoles[i * 2 + 1] = e0;
}
} }
if (winHoles[2] < winHoles[0]) { }
UINT64 t0 = winHoles[0], t1 = winHoles[1];
winHoles[0] = winHoles[2]; for (UINTN pass = 0; pass < winHoleCount; pass++) {
winHoles[1] = winHoles[3]; for (UINTN i = 1; i < winHoleCount; i++) {
winHoles[2] = t0; if (winHoles[i * 2] < winHoles[(i - 1) * 2]) {
winHoles[3] = t1; UINT64 s0 = winHoles[(i - 1) * 2 + 0];
UINT64 e0 = winHoles[(i - 1) * 2 + 1];
winHoles[(i - 1) * 2 + 0] = winHoles[i * 2 + 0];
winHoles[(i - 1) * 2 + 1] = winHoles[i * 2 + 1];
winHoles[i * 2 + 0] = s0;
winHoles[i * 2 + 1] = e0;
}
} }
} }
@@ -791,8 +815,8 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
// memory because of buggy UEFI size reporting. // memory because of buggy UEFI size reporting.
end += 2 * PAGE_SIZE; end += 2 * PAGE_SIZE;
MapRangeSkipping(start, start, end - start, 0x03, idHoles, holeCount); MapRangeSkipping(start, start, end - start, 0x03, idHoles, idHoleCount);
MapRangeSkipping(PHYS_MAP_BASE + start, start, end - start, 0x03, winHoles, holeCount); MapRangeSkipping(PHYS_MAP_BASE + start, start, end - start, 0x03, winHoles, winHoleCount);
} }
} }
} }
+69 -18
View File
@@ -76,16 +76,66 @@ __declspec(dllexport) void KePrintConsole(const char* buf, size_t len) {
// can continue running everything else. // 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) { static const char* KiFaultVectorName(int vector) {
switch (vector) { switch (vector) {
case 0: return "#DE Divide Error"; 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 13: return "#GP General Protection";
case 14: return "#PF Page Fault"; 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"; 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. // 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 // 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. // 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) { if ((frame->Cs & 3) == 0) {
switch ((int)frame->Vector) { int vector = (int)frame->Vector;
case 0: const char* name = KiFaultVectorName(vector);
KePanic("PANIC: #DE Divide Error | RIP: %016llx\n",
(unsigned long long)frame->Rip); if (vector == 14) {
case 13: KePanic("PANIC: %s | RIP: %016llx | Code: %04llx | CR2: %016llx\n",
KePanic("PANIC: #GP General Protection | RIP: %016llx | Code: %04llx\n", name,
(unsigned long long)frame->Rip, (unsigned long long)frame->Rip,
(unsigned long long)frame->ErrorCode); (unsigned long long)frame->ErrorCode,
case 14: (unsigned long long)frame->Cr2);
KePanic("PANIC: #PF Page Fault | RIP: %016llx | Code: %04llx | CR2: %016llx\n", } else if (KiFaultHasErrorCode(vector)) {
(unsigned long long)frame->Rip, KePanic("PANIC: %s | RIP: %016llx | Code: %04llx\n",
(unsigned long long)frame->ErrorCode, name,
(unsigned long long)frame->Cr2); (unsigned long long)frame->Rip,
default: (unsigned long long)frame->ErrorCode);
KePanic("PANIC: Exception #%llu | RIP: %016llx\n", } else {
(unsigned long long)frame->Vector, KePanic("PANIC: %s | RIP: %016llx\n",
(unsigned long long)frame->Rip); name,
(unsigned long long)frame->Rip);
} }
} }
+47 -3
View File
@@ -41,6 +41,36 @@ extern void KeIrqStub21(void);
extern void KeIrqStub22(void); extern void KeIrqStub22(void);
extern void KeIrqStub23(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 #define NUM_IRQS 24
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -150,9 +180,23 @@ static void KiIdtSetGate(int vec, uintptr_t handler,
void KeInitializeIdt(void) { void KeInitializeIdt(void) {
memset(gIdt, 0, sizeof(gIdt)); memset(gIdt, 0, sizeof(gIdt));
KiIdtSetGate(0, (uintptr_t)KeFaultDE, 0x8E, 0); static void* faultStubs[32] = {
KiIdtSetGate(13, (uintptr_t)KeFaultGP, 0x8E, 0); (void*)KeFaultDE, (void*)KeFaultDB, (void*)KeFaultNMI,
KiIdtSetGate(14, (uintptr_t)KeFaultPF, 0x8E, 0); (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); KiIdtSetGate(0x40, (uintptr_t)KeSyscallEntry, 0xEE, 0);
static void *irqStubs[NUM_IRQS] = { static void *irqStubs[NUM_IRQS] = {
+35 -34
View File
@@ -1,34 +1,35 @@
#pragma once #pragma once
// ke_idt.h - IDT, GDT, and TSS setup // ke_idt.h - IDT, GDT, and TSS setup
#include <stdint.h> #include <stdint.h>
// 64-bit TSS - minimal; we only care about RSP0. // 64-bit TSS - minimal; we only care about RSP0.
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct TSS64 { typedef struct TSS64 {
uint32_t Reserved0; uint32_t Reserved0;
uint64_t RSP0; // loaded into RSP on ring-0 entry uint64_t RSP0; // loaded into RSP on ring-0 entry
uint64_t RSP1; uint64_t RSP1;
uint64_t RSP2; uint64_t RSP2;
uint64_t Reserved1; uint64_t Reserved1;
uint64_t IST[7]; uint64_t IST[7];
uint64_t Reserved2; uint64_t Reserved2;
uint16_t Reserved3; uint16_t Reserved3;
uint16_t IoMapBase; uint16_t IoMapBase;
} TSS64; } TSS64;
#pragma pack(pop) #pragma pack(pop)
extern TSS64* gTss; extern TSS64* gTss;
void KeInitializeGdt(void); void KeInitializeGdt(void);
void KeInitializeIdt(void); void KeInitializeIdt(void);
// Called from hal_timer.c after HPET/APIC timer fires. // Called from hal_timer.c after HPET/APIC timer fires.
void KeTimerInterrupt(void); void KeTimerInterrupt(void);
// Syscall entry - implemented in ke_syscall.asm. // Syscall entry - implemented in ke_syscall.asm.
extern void KeSyscallEntry(void); extern void KeSyscallEntry(void);
// Fault stubs installed by KeInitializeIdt. // Fault stubs installed by KeInitializeIdt.
extern void KeFaultDE(void); // #DE divide error extern void KeFaultDE(void); // #DE divide error
extern void KeFaultGP(void); // #GP general protection extern void KeFaultGP(void); // #GP general protection
extern void KeFaultPF(void); // #PF page fault 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 // String-view ABI self-test
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@@ -732,6 +750,7 @@ static void KiRunTrapFrameSelfTest(void) {
void KiRunKernelSelfTests(const HAL_API* hal) { void KiRunKernelSelfTests(const HAL_API* hal) {
DbgPrint("Kernel selftests: begin\n"); DbgPrint("Kernel selftests: begin\n");
KiRunKernelApcSelfTest(); KiRunKernelApcSelfTest();
KiRunMemoryMappingSelfTest();
KiRunStringViewSelfTest(); KiRunStringViewSelfTest();
KiRunIrpKernelApcSelfTest(hal); KiRunIrpKernelApcSelfTest(hal);
KiRunAsyncFileIoSelfTest(); KiRunAsyncFileIoSelfTest();
+161
View File
@@ -377,6 +377,167 @@ pf_call:
call KeFaultDispatchFrame call KeFaultDispatchFrame
KeFaultPF ENDP 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 KeIrqDispatch:PROC
EXTERN KiEnterInterrupt:PROC EXTERN KiEnterInterrupt:PROC
EXTERN KiExitInterrupt:PROC EXTERN KiExitInterrupt:PROC
+38 -1
View File
@@ -209,7 +209,44 @@ static int runCommand(const char* cmd) {
if (strcmp(cmd, "exit") == 0) return 1; if (strcmp(cmd, "exit") == 0) return 1;
if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; } if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; }
if (strcmp(cmd, "clear") == 0) { SysScreenClear(0); return 0; } if (strcmp(cmd, "clear") == 0) { SysScreenClear(0); return 0; }
if (strcmp(cmd, "crash") == 0) { *(int*)0 = 42; return 0; } if (strncmp(cmd, "crash", 5) == 0) {
// Check the sub-option trailing "crash " (offset 6)
if (strcmp(cmd + 6, "void") == 0) {
// Jumping into the void
void (*invalid_func)(void) = NULL;
invalid_func();
return 0;
}
else if (strcmp(cmd + 6, "noncanonical") == 0) {
// Non-canonical pointer dereference
volatile int *ptr = (volatile int*)0x4242424242424242ULL;
*ptr = 1337;
return 0;
}
else if (strcmp(cmd + 6, "ud2") == 0) {
__ud2();
return 0;
}
else if (strcmp(cmd + 6, "nx") == 0) {
// NX / DEP Violation
unsigned char code[] = { 0xC3 };
void (*execute_stack)(void) = (void (*)(void))code;
execute_stack();
return 0;
}
else if (strcmp(cmd + 6, "divzero") == 0) {
// Division by zero
volatile int zero = 0;
volatile int result = 1 / zero;
(void)result;
return 0;
}
else {
// Default fallback if just "crash" or an unknown sub-option is passed
*(volatile int*)0 = 42;
return 0;
}
}
if (strcmp(cmd, "mem") == 0) { cmd_mem(); return 0; } if (strcmp(cmd, "mem") == 0) { cmd_mem(); return 0; }
if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; } if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; }
if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; } if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; }
+2 -2
View File
@@ -10,7 +10,7 @@ NT-Lite is a 64-bit operating system kernel written from scratch. It has a UEFI
It boots into a shell, launches user processes, survives application crashes, and can run things it probably should not be able to run yet. It boots into a shell, launches user processes, survives application crashes, and can run things it probably should not be able to run yet.
The codebase is still small enough to understand, but large enough to hurt your feelings. The kernel is just 7k lines of code and the entire project is about 15k lines. The codebase is still small enough to understand, but large enough to hurt your feelings. The kernel is just 10k lines of code and the entire project is about 20k lines.
## features ## features
@@ -295,7 +295,7 @@ Q: How often does it crash?
A: Like Windows 11. A: Like Windows 11.
Q: Can it recover from a crash? Q: Can it recover from a crash?
A: Yes. Unless the kernel faulted. A: Works on my machine.
Q: Is this finished? Q: Is this finished?
A: No. And it never will be. A: No. And it never will be.