summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2025-12-10 01:19:32 +0800
committerRichard Qin <richard.qin.x@gmail.com>2025-12-10 01:19:32 +0800
commit497e4a1b2f6f9181518e9887991c0464bd8f6bcf (patch)
treeefd498dd66b8995a4bd0e31ca6af454b4ef342d2 /src/kernel
parentc36e1b5e5e069ce1735dcc2a94aa45ba72ea2441 (diff)
downloadlume-497e4a1b2f6f9181518e9887991c0464bd8f6bcf.tar.gz
lume-497e4a1b2f6f9181518e9887991c0464bd8f6bcf.tar.xz
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.
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/main.cc46
-rw-r--r--src/kernel/trap/handler.cc123
-rw-r--r--src/kernel/trap/trap.S87
3 files changed, 240 insertions, 16 deletions
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