summaryrefslogtreecommitdiff
path: root/lume-legacy/src/kernel/trap
diff options
context:
space:
mode:
Diffstat (limited to 'lume-legacy/src/kernel/trap')
-rw-r--r--lume-legacy/src/kernel/trap/handler.cc217
-rw-r--r--lume-legacy/src/kernel/trap/trampoline.S101
-rw-r--r--lume-legacy/src/kernel/trap/trap.S90
3 files changed, 408 insertions, 0 deletions
diff --git a/lume-legacy/src/kernel/trap/handler.cc b/lume-legacy/src/kernel/trap/handler.cc
new file mode 100644
index 0000000..b7bd5f0
--- /dev/null
+++ b/lume-legacy/src/kernel/trap/handler.cc
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Richard QIn
+ */
+#include "kernel/trap.h"
+#include "kernel/riscv.h"
+#include "kernel/proc.h"
+#include "drivers/uart.h"
+#include "kernel/syscall.h"
+#include "kernel/mm.h"
+#include "kernel/timer.h"
+#include "drivers/plic.h"
+#include "drivers/virtio.h"
+#include "kernel/fdt.h"
+#include "lib/string.h"
+
+
+extern "C" void kernelvec();
+
+// Handle Function
+
+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)
+ ;
+}
+
+// Trap Implementation
+
+namespace Trap
+{
+ void init()
+ {
+ Drivers::uart_puts("[Trap] Global init done.\n");
+ }
+
+ // Each CPU core needs to call this function when starting to set its own stvec
+ void inithart()
+ {
+ w_stvec((uint64)kernelvec);
+
+ // Ensure that the S-Mode interrupt enable bit (SIE) is cleared during initialization
+ // Interrupt enabling will be done by the scheduler when the first process runs
+ w_sstatus(r_sstatus() & ~SSTATUS_SIE);
+
+ // Enable the external interrupt, clock interrupt, and software interrupt bits in S-Mode (in SIE register)
+ uint64 sie = r_sie();
+ sie |= SIE_SEIE | SIE_STIE | SIE_SSIE;
+ w_sie(sie);
+
+ Drivers::uart_puts("[Trap] Hart initialized (stvec set).\n");
+ }
+
+ // Device Interrupt Check
+ int devintr()
+ {
+ uint64 scause = r_scause();
+
+ bool is_interrupt = (scause & 0x8000000000000000L) != 0;
+ uint64 code = scause & 0xff;
+
+ if (is_interrupt && code == 9)
+ {
+ // Supervisor External Interrupt (IRQ 9)
+ int irq = PLIC::claim();
+
+ if (irq == (int)g_devices.uart.irq)
+ {
+ Drivers::uart_intr();
+ }
+ else
+ {
+ // Check if it's a VirtIO IRQ
+ bool handled = false;
+ for (int i = 0; i < g_devices.virtio_count; i++)
+ {
+ if (irq == (int)g_devices.virtio[i].irq)
+ {
+ VirtIO::intr();
+ handled = true;
+ break;
+ }
+ }
+ }
+
+ if (irq > 0)
+ {
+ PLIC::complete(irq);
+ }
+
+ return 1;
+ }
+ else if (is_interrupt && code == 5)
+ {
+ // Supervisor Timer Interrupt (IRQ 5)
+ // Timer::set_next_trigger();
+ Timer::tick();
+ // w_sip(r_sip() & ~2);
+ return 2;
+ }
+
+ return 0;
+ }
+}
+
+// Exception Handling Entry
+
+extern "C" void kerneltrap(struct Trapframe *tf)
+{
+ uint64 sepc = r_sepc();
+ uint64 sstatus = r_sstatus();
+ uint64 scause = r_scause();
+
+ if ((sstatus & SSTATUS_SPP) == 0)
+ panic("kerneltrap: not from supervisor mode");
+
+ if (intr_get() != 0)
+ panic("kerneltrap: interrupts enabled");
+
+ if (Trap::devintr() == 0)
+ {
+ Drivers::uart_puts("\n--- KERNEL EXCEPTION ---\n");
+ Drivers::uart_puts("scause: ");
+ Drivers::print_hex(scause);
+ Drivers::uart_puts("\n");
+ Drivers::uart_puts("sepc: ");
+ Drivers::print_hex(sepc);
+ Drivers::uart_puts("\n");
+ Drivers::uart_puts("stval: ");
+ Drivers::print_hex(r_stval());
+ Drivers::uart_puts("\n");
+ panic("kerneltrap exception");
+ }
+
+ w_sepc(sepc);
+ w_sstatus(sstatus);
+}
+
+extern "C" void usertrap()
+{
+ // Drivers::uart_puts("[Debug] Entered usertrap!\n");
+ int which_dev = 0;
+
+ if ((r_sstatus() & SSTATUS_SPP) != 0)
+ panic("usertrap: not from user mode");
+
+ w_stvec((uint64)kernelvec);
+
+ struct Proc *p = myproc();
+ if (!p)
+ panic("usertrap: no process");
+
+ p->tf->epc = r_sepc();
+
+ uint64 scause = r_scause();
+ uint64 stval = r_stval();
+
+ if (scause == 8) // Syscall
+ {
+ if (p->state == ZOMBIE)
+ ProcManager::exit(-1);
+ p->tf->epc += 4;
+ intr_on();
+ syscall();
+ intr_off();
+ }
+ else if (scause == 15) // Store Page Fault
+ {
+ if (VM::handle_cow_fault(p->pagetable, PGROUNDDOWN(stval)) != 0)
+ {
+ uint64 pa = VM::walkaddr(p->pagetable, stval);
+
+ if (pa == 0)
+ {
+ Drivers::uart_puts("usertrap: Segmentation Fault (unmapped) at ");
+ }
+ else
+ {
+ Drivers::uart_puts("usertrap: Protection Fault (or OOM) at ");
+ }
+
+ Drivers::print_hex(stval);
+ Drivers::uart_puts("\n");
+ p->state = ZOMBIE;
+ ProcManager::exit(-1);
+ }
+ }
+ else if ((which_dev = Trap::devintr()) != 0)
+ {
+ if (which_dev == 2)
+ {
+ ProcManager::yield();
+ }
+ }
+ else
+ {
+ Drivers::uart_puts("\nusertrap(): unexpected scause ");
+ Drivers::print_hex(scause);
+ Drivers::uart_puts(" pid=");
+ Drivers::uart_put_int(p->pid);
+ Drivers::uart_puts(" sepc=");
+ Drivers::print_hex(p->tf->epc);
+ Drivers::uart_puts(" stval=");
+ Drivers::print_hex(stval);
+ Drivers::uart_puts("\n");
+ p->state = ZOMBIE;
+ ProcManager::exit(-1);
+ }
+
+ if (p->state == ZOMBIE)
+ ProcManager::exit(-1);
+
+ usertrapret();
+} \ No newline at end of file
diff --git a/lume-legacy/src/kernel/trap/trampoline.S b/lume-legacy/src/kernel/trap/trampoline.S
new file mode 100644
index 0000000..57d6f25
--- /dev/null
+++ b/lume-legacy/src/kernel/trap/trampoline.S
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2026 Richard Qin
+
+.section .text
+.globl trampoline
+.globl uservec
+.globl userret
+
+.align 12
+trampoline:
+.align 4
+uservec:
+
+ csrrw a0, sscratch, a0
+
+ sd ra, 40(a0)
+ sd sp, 48(a0)
+ sd gp, 56(a0)
+ sd tp, 64(a0)
+ sd t0, 72(a0)
+ sd t1, 80(a0)
+ sd t2, 88(a0)
+ sd s0, 96(a0)
+ sd s1, 104(a0)
+ sd a1, 120(a0)
+ sd a2, 128(a0)
+ sd a3, 136(a0)
+ sd a4, 144(a0)
+ sd a5, 152(a0)
+ sd a6, 160(a0)
+ sd a7, 168(a0)
+ sd s2, 176(a0)
+ sd s3, 184(a0)
+ sd s4, 192(a0)
+ sd s5, 200(a0)
+ sd s6, 208(a0)
+ sd s7, 216(a0)
+ sd s8, 224(a0)
+ sd s9, 232(a0)
+ sd s10, 240(a0)
+ sd s11, 248(a0)
+ sd t3, 256(a0)
+ sd t4, 264(a0)
+ sd t5, 272(a0)
+ sd t6, 280(a0)
+
+ csrr t0, sscratch
+ sd t0, 112(a0)
+
+ ld sp, 8(a0)
+ ld tp, 32(a0)
+ ld t0, 16(a0)
+ ld t1, 0(a0)
+
+ csrw satp, t1
+ sfence.vma zero, zero
+
+ jr t0
+
+.align 4
+userret:
+
+ csrw satp, a1
+ sfence.vma zero, zero
+
+ csrw sscratch, a0
+
+ ld ra, 40(a0)
+ ld sp, 48(a0)
+ ld gp, 56(a0)
+ ld tp, 64(a0)
+ ld t0, 72(a0)
+ ld t1, 80(a0)
+ ld t2, 88(a0)
+ ld s0, 96(a0)
+ ld s1, 104(a0)
+ ld a1, 120(a0)
+ ld a2, 128(a0)
+ ld a3, 136(a0)
+ ld a4, 144(a0)
+ ld a5, 152(a0)
+ ld a6, 160(a0)
+ ld a7, 168(a0)
+ ld s2, 176(a0)
+ ld s3, 184(a0)
+ ld s4, 192(a0)
+ ld s5, 200(a0)
+ ld s6, 208(a0)
+ ld s7, 216(a0)
+ ld s8, 224(a0)
+ ld s9, 232(a0)
+ ld s10, 240(a0)
+ ld s11, 248(a0)
+ ld t3, 256(a0)
+ ld t4, 264(a0)
+ ld t5, 272(a0)
+ ld t6, 280(a0)
+
+ ld a0, 112(a0)
+
+ sret \ No newline at end of file
diff --git a/lume-legacy/src/kernel/trap/trap.S b/lume-legacy/src/kernel/trap/trap.S
new file mode 100644
index 0000000..8bce53d
--- /dev/null
+++ b/lume-legacy/src/kernel/trap/trap.S
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2026 Richard Qin
+
+.section .text
+.global kernelvec
+.global uservec
+.global userret
+.align 12
+
+kernelvec:
+ addi sp, sp, -288
+
+ 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, 288
+ sret \ No newline at end of file