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. --- build/kernel.elf | Bin 19104 -> 19384 bytes build/src/drivers/uart.o | Bin 2688 -> 3640 bytes build/src/kernel/main.o | Bin 7752 -> 7568 bytes build/src/kernel/trap/handler.o | Bin 0 -> 11952 bytes build/src/kernel/trap/trap.o | Bin 0 -> 1344 bytes include/common/types.h | 4 +- include/drivers/uart.h | 2 + include/kernel/trap.h | 50 ++++++++++++++++ src/drivers/uart.cc | 15 +++++ src/kernel/main.cc | 46 +++++++++------ src/kernel/trap/handler.cc | 123 ++++++++++++++++++++++++++++++++++++++++ src/kernel/trap/trap.S | 87 ++++++++++++++++++++++++++++ 12 files changed, 310 insertions(+), 17 deletions(-) create mode 100644 build/src/kernel/trap/handler.o create mode 100644 build/src/kernel/trap/trap.o create mode 100644 include/kernel/trap.h create mode 100644 src/kernel/trap/handler.cc create mode 100644 src/kernel/trap/trap.S diff --git a/build/kernel.elf b/build/kernel.elf index 6e2868c..9b56c35 100755 Binary files a/build/kernel.elf and b/build/kernel.elf differ diff --git a/build/src/drivers/uart.o b/build/src/drivers/uart.o index 6f45d67..035b61d 100644 Binary files a/build/src/drivers/uart.o and b/build/src/drivers/uart.o differ diff --git a/build/src/kernel/main.o b/build/src/kernel/main.o index 5188b34..f945e0a 100644 Binary files a/build/src/kernel/main.o and b/build/src/kernel/main.o differ diff --git a/build/src/kernel/trap/handler.o b/build/src/kernel/trap/handler.o new file mode 100644 index 0000000..322d37d Binary files /dev/null and b/build/src/kernel/trap/handler.o differ diff --git a/build/src/kernel/trap/trap.o b/build/src/kernel/trap/trap.o new file mode 100644 index 0000000..e7bde6b Binary files /dev/null and b/build/src/kernel/trap/trap.o differ diff --git a/include/common/types.h b/include/common/types.h index 56500c5..4a22791 100644 --- a/include/common/types.h +++ b/include/common/types.h @@ -11,4 +11,6 @@ typedef signed int int32_t; typedef signed long long int64_t; typedef uint64_t size_t; -typedef uint64_t uintptr_t; \ No newline at end of file +typedef uint64_t uintptr_t; + +typedef uint64_t uint64; \ No newline at end of file diff --git a/include/drivers/uart.h b/include/drivers/uart.h index 8bf4560..4d00d94 100644 --- a/include/drivers/uart.h +++ b/include/drivers/uart.h @@ -1,7 +1,9 @@ #pragma once +typedef unsigned long long uint64_t; namespace Drivers { void uart_init(); void uart_putc(char c); void uart_puts(const char* s); + void print_hex(uint64_t val); } \ No newline at end of file diff --git a/include/kernel/trap.h b/include/kernel/trap.h new file mode 100644 index 0000000..fd51ef6 --- /dev/null +++ b/include/kernel/trap.h @@ -0,0 +1,50 @@ +#pragma once +#include "common/types.h" + +struct Trapframe +{ + /* 0 */ uint64 kernel_satp; + /* 8 */ uint64 kernel_sp; + /* 16 */ uint64 kernel_trap; + /* 24 */ uint64 epc; + /* 32 */ uint64 kernel_hartid; + + /* 40 */ uint64 ra; // x1 + /* 48 */ uint64 sp; // x2 + /* 56 */ uint64 gp; // x3 + /* 64 */ uint64 tp; // x4 + /* 72 */ uint64 t0; // x5 + /* 80 */ uint64 t1; // x6 + /* 88 */ uint64 t2; // x7 + /* 96 */ uint64 s0; // x8 (Frame Pointer) + /* 104 */ uint64 s1; // x9 + /* 112 */ uint64 a0; // x10 + /* 120 */ uint64 a1; // x11 + /* 128 */ uint64 a2; // x12 + /* 136 */ uint64 a3; // x13 + /* 144 */ uint64 a4; // x14 + /* 152 */ uint64 a5; // x15 + /* 160 */ uint64 a6; // x16 + /* 168 */ uint64 a7; // x17 + /* 176 */ uint64 s2; // x18 + /* 184 */ uint64 s3; // x19 + /* 192 */ uint64 s4; // x20 + /* 200 */ uint64 s5; // x21 + /* 208 */ uint64 s6; // x22 + /* 216 */ uint64 s7; // x23 + /* 224 */ uint64 s8; // x24 + /* 232 */ uint64 s9; // x25 + /* 240 */ uint64 s10; // x26 + /* 248 */ uint64 s11; // x27 + /* 256 */ uint64 t3; // x28 + /* 264 */ uint64 t4; // x29 + /* 272 */ uint64 t5; // x30 + /* 280 */ uint64 t6; // x31 +}; + +namespace Trap +{ + void init(); + extern "C" void kernelvec(); + extern "C" void kerneltrap(struct Trapframe *tf); +} \ No newline at end of file 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