summaryrefslogtreecommitdiff
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
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.
-rwxr-xr-xbuild/kernel.elfbin19104 -> 19384 bytes
-rw-r--r--build/src/drivers/uart.obin2688 -> 3640 bytes
-rw-r--r--build/src/kernel/main.obin7752 -> 7568 bytes
-rw-r--r--build/src/kernel/trap/handler.obin0 -> 11952 bytes
-rw-r--r--build/src/kernel/trap/trap.obin0 -> 1344 bytes
-rw-r--r--include/common/types.h4
-rw-r--r--include/drivers/uart.h2
-rw-r--r--include/kernel/trap.h50
-rw-r--r--src/drivers/uart.cc15
-rw-r--r--src/kernel/main.cc46
-rw-r--r--src/kernel/trap/handler.cc123
-rw-r--r--src/kernel/trap/trap.S87
12 files changed, 310 insertions, 17 deletions
diff --git a/build/kernel.elf b/build/kernel.elf
index 6e2868c..9b56c35 100755
--- a/build/kernel.elf
+++ b/build/kernel.elf
Binary files differ
diff --git a/build/src/drivers/uart.o b/build/src/drivers/uart.o
index 6f45d67..035b61d 100644
--- a/build/src/drivers/uart.o
+++ b/build/src/drivers/uart.o
Binary files differ
diff --git a/build/src/kernel/main.o b/build/src/kernel/main.o
index 5188b34..f945e0a 100644
--- a/build/src/kernel/main.o
+++ b/build/src/kernel/main.o
Binary files differ
diff --git a/build/src/kernel/trap/handler.o b/build/src/kernel/trap/handler.o
new file mode 100644
index 0000000..322d37d
--- /dev/null
+++ b/build/src/kernel/trap/handler.o
Binary files differ
diff --git a/build/src/kernel/trap/trap.o b/build/src/kernel/trap/trap.o
new file mode 100644
index 0000000..e7bde6b
--- /dev/null
+++ b/build/src/kernel/trap/trap.o
Binary files 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