From 4bc3382abb1fe0d6895f3c0c44d0ab1b23f814c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kube=C4=8Dek?= Date: Fri, 29 May 2026 11:42:20 +0200 Subject: [PATCH] Got decent exception handling --- TODO | 7 +- kernel/include/exceptions.h | 24 ++++++ kernel/include/paging.h | 1 + kernel/src/exceptions.c | 152 ++++++++++++++++++++++++++++++++++++ kernel/src/isr.c | 51 ++---------- 5 files changed, 186 insertions(+), 49 deletions(-) create mode 100644 kernel/include/exceptions.h create mode 100644 kernel/src/exceptions.c diff --git a/TODO b/TODO index e9acaa5..64bc727 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,7 @@ TODO Architectural Milestones [-] 64-bit rewrite [x] Limine (Bootloader) -[ ] Decent build system (Makefile/CMake with cross-compiler) +[ ] Decent build system (feat. cross-compiler) [x] kernel.h rewrite & header cleanup [x] debugf() cleanup, kprintf() & pr_*() (Standardized logging levels) [x] errno.h errors and "errno-in-pointer" macros @@ -13,7 +13,7 @@ Low-Level Hardware & Interrupts [x] GDT [x] IDT [x] Basic IRQs (Internal/Legacy) -[ ] Proper fault handling (Exceptions, Page Faults, #GP) +[x] Proper fault handling (Exceptions, Page Faults, #GP) [ ] Check for features with CPUID (NX-bit, SSE, AVX) [ ] APIC driver (Local APIC & I/O APIC) [ ] ACPI driver (Parsing RSDP/MADT for multi-core/APIC) @@ -55,7 +55,8 @@ Drivers & IO [ ] Storage driver (SATA/AHCI or VirtIO) The Final TODOs -[ ] Run DOOM (Requires: VFS, Input, Timer, LibC, and Graphics) +[ ] Gaming???!!?? +[ ] Run DOOM [-] Finish all the TODOs Legend diff --git a/kernel/include/exceptions.h b/kernel/include/exceptions.h new file mode 100644 index 0000000..901e82c --- /dev/null +++ b/kernel/include/exceptions.h @@ -0,0 +1,24 @@ +#ifndef _EXCEPTIONS_H +#define _EXCEPTIONS_H + +#include "isr.h" + +#define EXCEPTION_DE 0 +#define EXCEPTION_BP 3 +#define EXCEPTION_OF 4 +#define EXCEPTION_BR 5 +#define EXCEPTION_UD 6 +#define EXCEPTION_NM 7 +#define EXCEPTION_DF 8 +#define EXCEPTION_GP 13 +#define EXCEPTION_PF 14 +#define EXCEPTION_AC 17 + +typedef void (*exception_handler_ptr)(struct isr_int_frame* iframe, bool user); + +const extern char* exception_strings[]; + +int exception_init(void); +void exception_handle(struct isr_int_frame* iframe); + +#endif diff --git a/kernel/include/paging.h b/kernel/include/paging.h index dbe739c..51dce74 100644 --- a/kernel/include/paging.h +++ b/kernel/include/paging.h @@ -9,6 +9,7 @@ #define PTE_FLAG_USER (1UL << 2) // User-mode (DPL3) access allowed #define PTE_FLAG_PWT (1UL << 3) // Page write-thru #define PTE_FLAG_NOCACHE (1UL << 4) // Cache disable +#define PTE_FLAG_FETCH (1UL << 4) // Fetch #define PTE_FLAG_ACCESSED (1UL << 5) // Indicates whether page was read/written #define PTE_FLAG_DIRTY (1UL << 6) // Indicates whether page was written to (valid for PT only) #define PTE_FLAG_PAT (1UL << 7) // Page Attribute Table (valid for PT only) diff --git a/kernel/src/exceptions.c b/kernel/src/exceptions.c new file mode 100644 index 0000000..04393f7 --- /dev/null +++ b/kernel/src/exceptions.c @@ -0,0 +1,152 @@ +#include "paging.h" +#include +#include +#include +#include +#include + +exception_handler_ptr exception_handlers[EXCEPTION_COUNT]; + +const char* exception_strings[] = { + "Division Error", + "Debug", + "Non-maskable Interrupt", + "Breakpoint", + "Overflow", + "Bound Range Exceeded", + "Invalid Opcode", + "Device Not Available", + "Double Fault", + "Coprocessor Segment Overrun", + "Invalid TSS", + "Segment Not Present", + "Stack-Segment Fault", + "General Protection Fault", + "Page Fault", + "Reserved", + "x87 Floating-Point Exception", + "Alignment Check", + "Machine Check", + "SIMD Floating-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Hypervisor Injection Exception", + "VMM Communication Exception", + "Security Exception", + "Reserved", +}; + +void exception_handle(struct isr_int_frame* iframe) { + bool user = (iframe->cs & 3) == 3; + + if (exception_handlers[iframe->interrupt]) { + exception_handlers[iframe->interrupt](iframe, user); + } else { + panic(iframe, "Unhandled %s exception, err 0x%lx", exception_strings[iframe->interrupt], iframe->error); + } +} + +void handle_division_error(struct isr_int_frame* iframe, bool user) { + if (user) { + // TODO: Kill process + } else panic(iframe, "Division by 0 @ %p", (void*)iframe->rip); + + +} + +void handle_invalid_opcode(struct isr_int_frame* iframe, bool user) { + if (user) { + pr_error("Userspace #UD @ %p\n", (void*)iframe->rip); + // TODO: Kill process + } else { + panic(iframe, "Kernel #UD"); + } +} + +void handle_device_not_available(struct isr_int_frame* iframe, bool user) { + (void)iframe; + (void)user; + + __asm__ volatile("clts"); + + // TODO: + // if (last_fpu_user != current) { + // if (last_fpu_user) { + // __asm__ volatile("fxsaveq %0" : "=m"(last_fpu_user->fpu_state)); + // } + // __asm__ volatile("fxrstorq %0" : : "m"(current->fpu_state)); + // set_last_fpu_owner(current); + // } + + pr_notice("FPU/SSE initialized lazily for current thread.\n"); +} + +// Do not attempt to log gracefully using complex structures or locks +// The kernel stack might be completely shredded +void handle_double_fault(struct isr_int_frame* iframe, bool user) { + (void)user; + + pr_emerg( + "Beware human. This thing is beyond comprehension. Beyond this corporeal realm.\n" + "Oh may the those unlucky enough to encouter it be spared of their pain.\n" + "Through it you pass into the city of woe.\n" + "Through it you pass into eternal pain.\n" + "To rear it was the task of power divine.\n" + "Supremes wisdom, and primeval love.\n" + "Before it things create were none, save things.\n" + "Eternal, and eternal It endures.\n" + "Abandon all hope, all ye who enter here.\n\n" + ); + panic(iframe, "[ D O U B L E F A U L T ]"); +} + +void handle_general_protection_fault(struct isr_int_frame* iframe, bool user) { + if (user) { + pr_error("Userspace #GP @ %p (err: 0x%lx)\n", (void*)iframe->rip, iframe->error); + // TODO: Kill process + } +} + +void handle_page_fault(struct isr_int_frame* iframe, bool user) { + uint64_t fault_addr; + __asm__ volatile("mov %%cr2, %0" : "=r"(fault_addr)); + + uint64_t err = iframe->error; + bool present = err & 0x1; + bool write = err & 0x2; + bool usersp = err & 0x4; + bool fetch = err & 0xA; + + if (user) { + pr_error("Userspace #PF: Segfault @ %p, tried to access %p\n", (void*)iframe->rip, (void*)fault_addr); + pr_error("\x1b[9m Reason: Retard\x1b[m\n"); // reference + pr_error(" Reason: %s %s in %s mode %s\n", + present ? "Protection violation" : "Non-present page", + write ? "during WRITE" : "during READ", + usersp ? "user" : "supervisor", + fetch ? "during instruction fetch" : "" + ); + // TODO: Kill process + } else { + panic(iframe, "Kernel: Segmentation fault @ %p, tried to access %p (err: 0x%lx)", (void*)iframe->rip, (void*)fault_addr, err); + } +} + +int exception_init(void) { + memset(exception_handlers, 0, sizeof(exception_handlers)); + + exception_handlers[EXCEPTION_DE] = handle_division_error; + exception_handlers[EXCEPTION_UD] = handle_invalid_opcode; + exception_handlers[EXCEPTION_NM] = handle_device_not_available; + exception_handlers[EXCEPTION_DF] = handle_double_fault; + exception_handlers[EXCEPTION_PF] = handle_page_fault; + + return SUCCESS; +} + diff --git a/kernel/src/isr.c b/kernel/src/isr.c index 41864df..f63f4e4 100644 --- a/kernel/src/isr.c +++ b/kernel/src/isr.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,44 +6,8 @@ #include #include -isr_handler_ptr exception_handlers[EXCEPTION_COUNT]; isr_handler_ptr irq_handlers[ISR_COUNT]; -const char* exceptions[] = { - "Division By Zero", - "Debug", - "Non Maskable Interrupt", - "Breakpoint", - "Into Detected Overflow", - "Out of Bounds", - "Invalid Opcode", - "No Coprocessor", - "Double Fault", - "Coprocessor Segment Overrun", - "Bad TSS", - "Segment Not Present", - "Stack Fault", - "General Protection Fault", - "Page Fault", - "Unknown Interrupt", - "Coprocessor Fault", - "Alignment Check", - "Machine Check", - "SIMD Floating-Point", - "Virtualization", - "Control Protection", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved" -}; - void pic_disable(void) { outb(0x21, 0xFF); iowait(); outb(0xA1, 0xFF); iowait(); @@ -63,7 +28,7 @@ void pic_remap(void) { } int isr_init(void) { - memset(exception_handlers, 0, sizeof(exception_handlers)); + exception_init(); memset(irq_handlers, 0, sizeof(irq_handlers)); idt_init(); @@ -99,18 +64,12 @@ void isr_send_eoi(uint8_t irq) { void isr_handle_interrupt(size_t rsp) { struct isr_int_frame* iframe = (void*)rsp; - if (iframe->interrupt < 32) { - if (exception_handlers[iframe->interrupt]) { - exception_handlers[iframe->interrupt](iframe); - return; - } - - panic(iframe, "Unhandled %s exception, err 0x%lx", exceptions[iframe->interrupt], iframe->error); - } else if (iframe->interrupt >= 32 && iframe->interrupt < 48) { + if (iframe->interrupt < 32) exception_handle(iframe); + else if (iframe->interrupt >= 32 && iframe->interrupt < 48) { uint8_t irq = iframe->interrupt - 32; if (irq_handlers[irq]) irq_handlers[irq](iframe); - else pr_warn("Unhandled IRQ #%d\n", irq); + // else pr_debug("Unhandled IRQ #%d\n", irq); isr_send_eoi(irq); } else if (iframe->interrupt == 0x80) {