Got decent exception handling

This commit is contained in:
Tomáš Kubeček
2026-05-29 11:42:20 +02:00
parent 22852599df
commit 4bc3382abb
5 changed files with 186 additions and 49 deletions
+4 -3
View File
@@ -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
+24
View File
@@ -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
+1
View File
@@ -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)
+152
View File
@@ -0,0 +1,152 @@
#include "paging.h"
#include <exceptions.h>
#include <kernel.h>
#include <string.h>
#include <errno.h>
#include <isr.h>
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;
}
+5 -46
View File
@@ -1,3 +1,4 @@
#include <exceptions.h>
#include <kernel.h>
#include <string.h>
#include <system.h>
@@ -5,44 +6,8 @@
#include <idt.h>
#include <isr.h>
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) {