From 497e4a1b2f6f9181518e9887991c0464bd8f6bcf Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Wed, 10 Dec 2025 01:19:32 +0800 Subject: feat: Add initial Supervisor Mode Trap Handler Implement the initial mechanism for handling traps and exceptions in Supervisor Mode. Set up the stvec Control and Status Register (CSR) to direct all S-Mode Traps (Interrupts and Exceptions) to a unified assembly entry point. Implemented assembly code for saving and restoring the Trap Context (register state). Provides the foundational framework necessary for future Timer Interrupts and System Calls. --- src/drivers/uart.cc | 15 ++++++ src/kernel/main.cc | 46 +++++++++++------ src/kernel/trap/handler.cc | 123 +++++++++++++++++++++++++++++++++++++++++++++ src/kernel/trap/trap.S | 87 ++++++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+), 16 deletions(-) create mode 100644 src/kernel/trap/handler.cc create mode 100644 src/kernel/trap/trap.S (limited to 'src') diff --git a/src/drivers/uart.cc b/src/drivers/uart.cc index 758abd9..a81ba3f 100644 --- a/src/drivers/uart.cc +++ b/src/drivers/uart.cc @@ -54,4 +54,19 @@ namespace Drivers{ uart_putc(*s++); } } + + void print_hex(uint64_t val) + { + char buf[20]; + const char *digits = "0123456789ABCDEF"; + buf[0] = '0'; + buf[1] = 'x'; + for (int i = 0; i < 16; i++) + { + buf[17 - i] = digits[val & 0xF]; + val >>= 4; + } + buf[18] = 0; + Drivers::uart_puts(buf); + } } \ No newline at end of file diff --git a/src/kernel/main.cc b/src/kernel/main.cc index beda9dc..2fa10a2 100644 --- a/src/kernel/main.cc +++ b/src/kernel/main.cc @@ -1,20 +1,21 @@ #include "drivers/uart.h" #include "kernel/pmm.h" #include "kernel/mm.h" +#include "kernel/trap.h" -void print_hex(uint64_t val) -{ - char buf[17]; - buf[16] = 0; - const char *digits = "0123456789ABCDEF"; - for (int i = 15; i >= 0; i--) - { - buf[i] = digits[val & 0xf]; - val >>= 4; - } - Drivers::uart_puts("0x"); - Drivers::uart_puts(buf); -} +// void print_hex(uint64_t val) +// { +// char buf[17]; +// buf[16] = 0; +// const char *digits = "0123456789ABCDEF"; +// for (int i = 15; i >= 0; i--) +// { +// buf[i] = digits[val & 0xf]; +// val >>= 4; +// } +// Drivers::uart_puts("0x"); +// Drivers::uart_puts(buf); +// } extern "C" void kernel_main() { @@ -33,11 +34,11 @@ extern "C" void kernel_main() void *p2 = PMM::alloc_page(); Drivers::uart_puts("Allocated Page 1: "); - print_hex((uint64_t)p1); + Drivers::print_hex((uint64_t)p1); Drivers::uart_puts("\n"); Drivers::uart_puts("Allocated Page 2: "); - print_hex((uint64_t)p2); + Drivers::print_hex((uint64_t)p2); Drivers::uart_puts("\n"); Drivers::uart_puts("[Kernel] Freeing Page 1...\n"); @@ -45,7 +46,7 @@ extern "C" void kernel_main() void *p3 = PMM::alloc_page(); Drivers::uart_puts("Allocated Page 3: "); - print_hex((uint64_t)p3); + Drivers::print_hex((uint64_t)p3); Drivers::uart_puts("\n"); if (p3 == p1) @@ -63,6 +64,19 @@ extern "C" void kernel_main() VM::kvminithart(); Drivers::uart_puts("[Boot] MMU ENABLED! We are now using virtual addresses.\n"); + Trap::init(); + Drivers::uart_puts("[Boot] Trap Handler Installed.\n"); + + Drivers::uart_puts("\n[Test] Triggering Page Fault by reading 0x0...\n"); + volatile int *p = (int *)0x0; + int crash = *p; + (void)crash; + + Drivers::uart_puts("[Test Failed] Shuold not reach here.\n"); + + Drivers::uart_puts("\n[Test] Triggering Store Fault on Text Segment...\n"); + *(int*)0x80000000 = 1234; + while (1) { diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc new file mode 100644 index 0000000..9cc19d1 --- /dev/null +++ b/src/kernel/trap/handler.cc @@ -0,0 +1,123 @@ +#include "kernel/trap.h" +#include "common/types.h" +#include "drivers/uart.h" + +void panic(const char *s) +{ + Drivers::uart_puts("\n\n!!! KERNEL PANIC !!!\n"); + Drivers::uart_puts(s); + Drivers::uart_puts("\nSystem Halted.\n"); + while (1) + ; +} + +namespace Trap +{ + void init() + { + uint64 stvec_val = (uint64)kernelvec; + asm volatile("csrw stvec, %0" : : "r"(stvec_val)); + + uint64 sstatus; + asm volatile("csrr %0, sstatus" : "=r"(sstatus)); + sstatus &= ~(1L << 1); + asm volatile("csrw sstatus, %0" : : "r"(sstatus)); + + Drivers::uart_puts("[Trap] Initialized stvec to: "); + Drivers::print_hex(stvec_val); + Drivers::uart_puts("\n"); + } + + extern "C" void kerneltrap(struct Trapframe *tf) + { + uint64 scause, stval, sepc; + + asm volatile("csrr %0, scause" : "=r"(scause)); + asm volatile("csrr %0, stval" : "=r"(stval)); + asm volatile("csrr %0, sepc" : "=r"(sepc)); + + if (scause & (1L << 63)) + { + uint64 cause_code = scause & 0x7FFFFFFFFFFFFFFFL; + switch (cause_code) + { + case 1: + Drivers::uart_puts("[IRQ] Software Interrupt\n"); + asm volatile("csrc sip, %0" : : "r"(1 << 1)); + break; + + case 5: + Drivers::uart_puts("[IRQ] Timer Interrupt\n"); + + break; + + case 9: + Drivers::uart_puts("[IRQ] External Interrupt\n"); + break; + + default: + Drivers::uart_puts("[IRQ] Unknown Interrupt: "); + Drivers::print_hex(cause_code); + Drivers::uart_puts("\n"); + break; + } + } + else + { + switch (scause) + { + case 8: + Drivers::uart_puts("[Syscall] ecall for User Mode\n"); + tf->epc += 4; + break; + + case 12: + case 13: + case 15: + Drivers::uart_puts("\n--- PAGE FAULT ---\n"); + Drivers::uart_puts("Cause Code: "); + Drivers::print_hex(scause); + Drivers::uart_puts("\n"); + Drivers::uart_puts("Fault Addr (stval): "); + Drivers::print_hex(stval); + Drivers::uart_puts("\n"); + Drivers::uart_puts("Instruction (sepc): "); + Drivers::print_hex(sepc); + Drivers::uart_puts("\n"); + + if (stval == 0) + { + panic("Null Pointer Dereference!"); + } + else if (stval < 0x80000000) + { + panic("Invalid Low Memory Access!"); + } + else + { + panic("Segmentation Fault (Unmapped Area)"); + } + break; + + case 2: + Drivers::uart_puts("\n--- ILLEGAL INSTRUCTION ---\n"); + Drivers::uart_puts("Instruction (sepc): "); + Drivers::print_hex(sepc); + Drivers::uart_puts("\n"); + panic("CPU encountered an unknown opcode"); + break; + + default: + Drivers::uart_puts("\n--- UNHANDLED EXCEPTION ---\n"); + Drivers::uart_puts("Cause: "); + Drivers::print_hex(scause); + Drivers::uart_puts("\n"); + Drivers::uart_puts("sepc: "); + Drivers::print_hex(sepc); + Drivers::uart_puts("\n"); + panic("System Halt"); + break; + } + } + } +} \ No newline at end of file diff --git a/src/kernel/trap/trap.S b/src/kernel/trap/trap.S new file mode 100644 index 0000000..ffce52a --- /dev/null +++ b/src/kernel/trap/trap.S @@ -0,0 +1,87 @@ +.section .text +.global kernelvec +.align 4 + +kernelvec: + + addi sp, sp, -256 + + sd ra, 40(sp) + sd sp, 48(sp) + sd gp, 56(sp) + sd tp, 64(sp) + sd t0, 72(sp) + sd t1, 80(sp) + sd t2, 88(sp) + sd s0, 96(sp) + sd s1, 104(sp) + sd a0, 112(sp) + sd a1, 120(sp) + sd a2, 128(sp) + sd a3, 136(sp) + sd a4, 144(sp) + sd a5, 152(sp) + sd a6, 160(sp) + sd a7, 168(sp) + sd s2, 176(sp) + sd s3, 184(sp) + sd s4, 192(sp) + sd s5, 200(sp) + sd s6, 208(sp) + sd s7, 216(sp) + sd s8, 224(sp) + sd s9, 232(sp) + sd s10, 240(sp) + sd s11, 248(sp) + sd t3, 256(sp) + sd t4, 264(sp) + sd t5, 272(sp) + sd t6, 280(sp) + + csrr t0, sepc + csrr t1, sstatus + sd t0, 24(sp) # Trapframe.epc + sd t1, 32(sp) # Trapframe.kernel_hartid + + mv a0, sp + call kerneltrap + + ld t0, 24(sp) + ld t1, 32(sp) + csrw sepc, t0 + csrw sstatus, t1 + + ld ra, 40(sp) + ld gp, 56(sp) + ld tp, 64(sp) + ld t0, 72(sp) + ld t1, 80(sp) + ld t2, 88(sp) + ld s0, 96(sp) + ld s1, 104(sp) + ld a0, 112(sp) + ld a1, 120(sp) + ld a2, 128(sp) + ld a3, 136(sp) + ld a4, 144(sp) + ld a5, 152(sp) + ld a6, 160(sp) + ld a7, 168(sp) + ld s2, 176(sp) + ld s3, 184(sp) + ld s4, 192(sp) + ld s5, 200(sp) + ld s6, 208(sp) + ld s7, 216(sp) + ld s8, 224(sp) + ld s9, 232(sp) + ld s10, 240(sp) + ld s11, 248(sp) + ld t3, 256(sp) + ld t4, 264(sp) + ld t5, 272(sp) + ld t6, 280(sp) + + addi sp, sp, 256 + + sret \ No newline at end of file -- cgit v1.2.3