diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:24:56 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:24:56 +0800 |
| commit | 1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (patch) | |
| tree | 0f5e01cd7c7a05abb6b1c7472d7f00f49caf02cc /na/kernel/trap.cc | |
| parent | 63dc025705f6533b91fb1a7d26e6ed864efd9900 (diff) | |
| download | lume-1767d390fbf3d0c65389de46caf0b6d43ef3b6ad.tar.gz lume-1767d390fbf3d0c65389de46caf0b6d43ef3b6ad.tar.xz | |
feat: establish bootable new architecture checkpoint
Replace the compressed boot path with a relocatable higher-half RISC-V entry, expand memory and SMP support, and add the driver, TTY, VFS, exec, signal, syscall, initramfs, and self-test infrastructure needed for a bootable kernel checkpoint.
Diffstat (limited to 'na/kernel/trap.cc')
| -rw-r--r-- | na/kernel/trap.cc | 118 |
1 files changed, 91 insertions, 27 deletions
diff --git a/na/kernel/trap.cc b/na/kernel/trap.cc index 738b2db..2116d91 100644 --- a/na/kernel/trap.cc +++ b/na/kernel/trap.cc @@ -15,6 +15,7 @@ * Reference: docs/specs/trap.md §4 */ +#include <arch/cpu.h> #include <lume/trap.h> #include <lume/irq.h> #include <lume/console.h> @@ -26,8 +27,11 @@ #include <lume/syscall.h> #include <lume/task.h> #include <lume/vmm.h> +#include <lume/signal.h> #include <lume/signal_nr.h> +#include <lume/smp.h> #include <arch/trapframe.h> /* TrapFrame: cross-layer data contract */ +#include <arch/extable.h> /* search_extable: kernel fault recovery */ /* ======================================================================== * trap_handle() — MI-layer dispatcher for traps @@ -39,22 +43,18 @@ 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; + uint32 raw = static_cast<uint32>(cause); + + /* Exceptions 0-7 map directly to indices 0-7 */ + if (raw <= 7) { + return raw; + } + /* IRQs 16-18 map to indices 8-10 */ + if (raw >= 16 && raw <= 18) { + return raw - 16 + 8; } + /* Unknown / out-of-range */ + return 11; } static void trap_record(const TrapInfo& info) @@ -100,10 +100,33 @@ void trap_handle(arch::TrapFrame* tf, const TrapInfo& info) { trap_record(info); + /* ---- Kernel exception handling ---- + * Interrupts are always allowed through. For exceptions: + * - Page faults: handled in the switch below (extable fixup path) + * - Other exceptions: try extable, then panic. + * + * This replaces the old blanket kernel_panic, enabling + * copy_from_user/copy_to_user to safely fault on user pages. */ if (info.origin == TrapOrigin::FromKernel && info.cls != TrapClass::Interrupt) { - kprintf("[trap] kernel exception\n"); - kernel_panic("kernel exception"); + + /* Page faults are dispatched in the switch — let them through */ + bool is_page_fault = + (info.cause == TrapCause::PageFaultLoad || + info.cause == TrapCause::PageFaultStore || + info.cause == TrapCause::PageFaultExec); + + if (!is_page_fault) { + /* Non-page-fault kernel exception: try extable fixup */ + uint64 fixup = search_extable(info.epc); + if (fixup != 0) { + tf->epc = fixup; + return; + } + kprintf("[trap] fatal kernel exception: cause=%u epc=0x%llx val=0x%llx\n", + static_cast<unsigned>(info.cause), info.epc, info.val); + kernel_panic("unrecoverable kernel exception"); + } } switch (info.cause) { @@ -120,17 +143,43 @@ void trap_handle(arch::TrapFrame* tf, const TrapInfo& info) int ret = vmm_handle_page_fault(curr->mm, info.val, vm_fault_cause_from_trap(info.cause)); if (ret == -EFAULT) { - task_kill_current(SIGSEGV); + kprintf("[trap] user SIGSEGV (MAPERR) epc=0x%llx addr=0x%llx\n", + info.epc, info.val); + force_sig_fault(SIGSEGV, 1 /* SEGV_MAPERR */, info.val); } else if (ret == -ENOMEM) { - task_kill_current(SIGKILL); + kprintf("[trap] user SIGKILL (OOM) epc=0x%llx addr=0x%llx\n", + info.epc, info.val); + force_sig_fault(SIGKILL, 0, info.val); } else if (ret < 0) { - task_kill_current(SIGSEGV); + kprintf("[trap] user SIGSEGV (ACCERR) epc=0x%llx addr=0x%llx\n", + info.epc, info.val); + force_sig_fault(SIGSEGV, 2 /* SEGV_ACCERR */, info.val); } break; } - kprintf("[trap] kernel page fault\n"); - kernel_panic("unhandled page fault"); + /* Kernel page fault — try exception table fixup. + * This is the path used by copy_from_user/copy_to_user when + * accessing unmapped or faulting user addresses from S-mode. */ + { + uint64 fixup = search_extable(info.epc); + if (fixup != 0) { + tf->epc = fixup; + break; + } + } + kprintf("[trap] kernel page fault: epc=0x%llx addr=0x%llx\n", + info.epc, info.val); + { + TaskControlBlock* curr = current_task(); + if (curr) { + kprintf("[trap] pid=%d state=%d\n", + curr->pid, static_cast<int>(curr->state)); + kprintf("[trap] tf->epc=%llx tf->ra=%llx tf->sp=%llx\n", + tf->epc, tf->ra, tf->sp); + } + } + kernel_panic("unhandled kernel page fault (no extable entry)"); break; /* ---- System Call ---- */ @@ -155,14 +204,20 @@ void trap_handle(arch::TrapFrame* tf, const TrapInfo& info) } case TrapCause::IrqSoftware: - /* IPI handling — Phase 2 stub */ + /* S-mode software interrupt = IPI from another hart */ + smp_handle_ipi(); 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"); + if (info.origin == TrapOrigin::FromUser) { + kprintf("[trap] user illegal instruction at epc=0x%llx stval=0x%llx\n", + info.epc, info.val); + force_sig_fault(SIGILL, 1 /* ILL_ILLOPC */, info.epc); + } else { + kprintf("[trap] illegal instruction at epc=0x%llx\n", info.epc); + kernel_panic("illegal instruction in kernel mode"); + } break; case TrapCause::AccessFault: @@ -187,8 +242,17 @@ void trap_handle(arch::TrapFrame* tf, const TrapInfo& info) break; } - /* Check if rescheduling is needed before returning to user mode */ + /* Process pending signals before returning to user mode */ if (info.origin == TrapOrigin::FromUser) { + do_signal(tf); + } + + /* Preemption check on return from any interrupt. + * This is the kernel's equivalent of Linux's retint_kernel path: + * if a timer tick (or IPI) set need_resched, we must call schedule() + * before returning — otherwise the idle loop never yields to + * runnable tasks like PID 1. */ + if (info.cls == TrapClass::Interrupt) { sched_check_preempt(); } } |
