summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-05-13 16:05:16 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-05-13 16:05:16 +0800
commit884615ed7887cbcd9d566056138c809f807fbf79 (patch)
tree2ada5aa58120a942fdc112b888bb72929196bd39
parent73773984eee26ea92b2777b40a9dc608e1b010aa (diff)
downloadlume-884615ed7887cbcd9d566056138c809f807fbf79.tar.gz
lume-884615ed7887cbcd9d566056138c809f807fbf79.tar.xz
feat: implement machine-independent trap handling with dispatcher and statistics
-rw-r--r--na/kernel/trap.cc194
1 files changed, 194 insertions, 0 deletions
diff --git a/na/kernel/trap.cc b/na/kernel/trap.cc
new file mode 100644
index 0000000..7dcfa1b
--- /dev/null
+++ b/na/kernel/trap.cc
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+/*
+ * Trap MI Layer — Machine-Independent Semantic Dispatcher
+ *
+ * Receives a translated TrapCause from the MD layer and routes to
+ * the appropriate handler.
+ *
+ * *** MI INVARIANT: This file contains ZERO inline assembly,
+ * ZERO arch-specific constants (no CSR reads, no scause codes). ***
+ * arch/trapframe.h is included because TrapFrame is the cross-layer
+ * data contract defined in docs/specs/arch_abstraction.md §3.2.
+ *
+ * Reference: docs/specs/trap.md §4
+ */
+
+#include <lume/trap.h>
+#include <lume/irq.h>
+#include <lume/console.h>
+#include <lume/kprintf.h>
+#include <lume/errno.h>
+#include <lume/sched.h>
+#include <lume/timer.h>
+#include <lume/klog.h>
+#include <lume/syscall.h>
+#include <lume/task.h>
+#include <lume/vmm.h>
+#include <lume/signal.h>
+#include <arch/trapframe.h> /* TrapFrame: cross-layer data contract */
+
+/* ========================================================================
+ * trap_handle() — MI-layer dispatcher for traps
+ *
+ * Called by MD layer after scause → TrapInfo translation.
+ * ======================================================================== */
+
+static TrapStats g_trap_stats = {};
+
+static uint32 trap_cause_index(TrapCause cause)
+{
+ switch (cause) {
+ case TrapCause::PageFaultLoad: return 0;
+ case TrapCause::PageFaultStore: return 1;
+ case TrapCause::PageFaultExec: return 2;
+ case TrapCause::Syscall: return 3;
+ case TrapCause::IllegalInst: return 4;
+ case TrapCause::Breakpoint: return 5;
+ case TrapCause::AccessFault: return 6;
+ case TrapCause::AlignFault: return 7;
+ case TrapCause::IrqTimer: return 8;
+ case TrapCause::IrqSoftware: return 9;
+ case TrapCause::IrqExternal: return 10;
+ case TrapCause::Unknown:
+ default:
+ return 11;
+ }
+}
+
+static void trap_record(const TrapInfo& info)
+{
+ uint32 idx = trap_cause_index(info.cause);
+ __atomic_fetch_add(&g_trap_stats.total, 1, __ATOMIC_RELAXED);
+ __atomic_fetch_add(&g_trap_stats.by_cause[idx], 1, __ATOMIC_RELAXED);
+ g_trap_stats.last_cause = info.cause;
+ g_trap_stats.last_class = info.cls;
+ g_trap_stats.last_origin = info.origin;
+ g_trap_stats.last_val = info.val;
+ g_trap_stats.last_epc = info.epc;
+ g_trap_stats.last_scause = info.scause;
+}
+
+static VmFaultCause vm_fault_cause_from_trap(TrapCause cause)
+{
+ switch (cause) {
+ case TrapCause::PageFaultStore:
+ return VmFaultCause::Write;
+ case TrapCause::PageFaultExec:
+ return VmFaultCause::Exec;
+ case TrapCause::PageFaultLoad:
+ default:
+ return VmFaultCause::Read;
+ }
+}
+
+void trap_stats_get(TrapStats* out)
+{
+ if (!out) {
+ return;
+ }
+ *out = g_trap_stats;
+}
+
+void trap_stats_reset()
+{
+ g_trap_stats = {};
+}
+
+void trap_handle(arch::TrapFrame* tf, const TrapInfo& info)
+{
+ trap_record(info);
+
+ if (info.origin == TrapOrigin::FromKernel &&
+ info.cls != TrapClass::Interrupt) {
+ kprintf("[trap] kernel exception\n");
+ kernel_panic("kernel exception");
+ }
+
+ switch (info.cause) {
+ /* ---- Page Faults ---- */
+ case TrapCause::PageFaultLoad:
+ case TrapCause::PageFaultStore:
+ case TrapCause::PageFaultExec:
+ if (info.origin == TrapOrigin::FromUser) {
+ TaskControlBlock* curr = current_task();
+ if (!curr || !curr->mm) {
+ kernel_panic("user page fault with no current mm");
+ }
+
+ int ret = vmm_handle_page_fault(curr->mm, info.val,
+ vm_fault_cause_from_trap(info.cause));
+ if (ret == -EFAULT) {
+ task_kill_current(SIGSEGV);
+ } else if (ret == -ENOMEM) {
+ task_kill_current(SIGKILL);
+ } else if (ret < 0) {
+ task_kill_current(SIGSEGV);
+ }
+ break;
+ }
+
+ kprintf("[trap] kernel page fault\n");
+ kernel_panic("unhandled page fault");
+ break;
+
+ /* ---- System Call ---- */
+ case TrapCause::Syscall:
+ syscall_dispatch_md(tf);
+ break;
+
+ /* ---- Interrupts ---- */
+ case TrapCause::IrqTimer:
+ /* Timer tick */
+ timer_tick();
+ break;
+
+ case TrapCause::IrqExternal: {
+ /* External interrupt: generic claim → dispatch → complete */
+ uint32 irq = g_irq_manager.claim();
+ if (irq != 0) {
+ g_irq_manager.dispatch(irq);
+ g_irq_manager.complete(irq);
+ }
+ break;
+ }
+
+ case TrapCause::IrqSoftware:
+ /* IPI handling — Phase 2 stub */
+ break;
+
+ /* ---- Fatal exceptions ---- */
+ case TrapCause::IllegalInst:
+ kprintf("[trap] illegal instruction\n");
+ /* Phase 2: panic. Phase 3: task_kill(SIGILL) */
+ kernel_panic("illegal instruction in user mode");
+ break;
+
+ case TrapCause::AccessFault:
+ kprintf("[trap] access fault\n");
+ kernel_panic("access fault");
+ break;
+
+ case TrapCause::AlignFault:
+ kprintf("[trap] alignment fault\n");
+ kernel_panic("alignment fault");
+ break;
+
+ case TrapCause::Breakpoint:
+ kprintf("[trap] breakpoint\n");
+ /* ebreak advance is handled by MD layer (arch-specific instruction size) */
+ break;
+
+ case TrapCause::Unknown:
+ default:
+ kprintf("[trap] unknown trap\n");
+ kernel_panic("unknown trap");
+ break;
+ }
+
+ /* Check if rescheduling is needed before returning to user mode */
+ if (info.origin == TrapOrigin::FromUser) {
+ sched_check_preempt();
+ }
+}