summaryrefslogtreecommitdiff
path: root/lume-legacy/src/kernel/trap/handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lume-legacy/src/kernel/trap/handler.cc')
-rw-r--r--lume-legacy/src/kernel/trap/handler.cc217
1 files changed, 217 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