diff options
Diffstat (limited to 'na/arch/riscv/trap')
| -rw-r--r-- | na/arch/riscv/trap/fpu.S | 103 | ||||
| -rw-r--r-- | na/arch/riscv/trap/trap_md.cc | 38 | ||||
| -rw-r--r-- | na/arch/riscv/trap/trap_vector.S | 10 |
3 files changed, 149 insertions, 2 deletions
diff --git a/na/arch/riscv/trap/fpu.S b/na/arch/riscv/trap/fpu.S new file mode 100644 index 0000000..90d96d9 --- /dev/null +++ b/na/arch/riscv/trap/fpu.S @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +/* + * FPU Save / Restore (RISC-V D extension) + * + * void fpu_save(FpState* state); + * Saves f0-f31 and fcsr to the FpState structure. + * + * void fpu_restore(FpState* state); + * Restores f0-f31 and fcsr from the FpState structure. + * + * FpState layout: f[0..31] at offset 0 (each 8 bytes), fcsr at offset 256. + * + * Called from schedule() when switching between tasks that have + * used the FPU (sstatus.FS == Dirty on save path). + */ + + .section .text + +/* ====================================================================== + * void fpu_save(FpState* state); // a0 = state pointer + * ====================================================================== */ + .globl fpu_save + .align 2 +fpu_save: + fsd f0, 0(a0) + fsd f1, 8(a0) + fsd f2, 16(a0) + fsd f3, 24(a0) + fsd f4, 32(a0) + fsd f5, 40(a0) + fsd f6, 48(a0) + fsd f7, 56(a0) + fsd f8, 64(a0) + fsd f9, 72(a0) + fsd f10, 80(a0) + fsd f11, 88(a0) + fsd f12, 96(a0) + fsd f13, 104(a0) + fsd f14, 112(a0) + fsd f15, 120(a0) + fsd f16, 128(a0) + fsd f17, 136(a0) + fsd f18, 144(a0) + fsd f19, 152(a0) + fsd f20, 160(a0) + fsd f21, 168(a0) + fsd f22, 176(a0) + fsd f23, 184(a0) + fsd f24, 192(a0) + fsd f25, 200(a0) + fsd f26, 208(a0) + fsd f27, 216(a0) + fsd f28, 224(a0) + fsd f29, 232(a0) + fsd f30, 240(a0) + fsd f31, 248(a0) + frcsr t0 + sw t0, 256(a0) + ret + +/* ====================================================================== + * void fpu_restore(FpState* state); // a0 = state pointer + * ====================================================================== */ + .globl fpu_restore + .align 2 +fpu_restore: + fld f0, 0(a0) + fld f1, 8(a0) + fld f2, 16(a0) + fld f3, 24(a0) + fld f4, 32(a0) + fld f5, 40(a0) + fld f6, 48(a0) + fld f7, 56(a0) + fld f8, 64(a0) + fld f9, 72(a0) + fld f10, 80(a0) + fld f11, 88(a0) + fld f12, 96(a0) + fld f13, 104(a0) + fld f14, 112(a0) + fld f15, 120(a0) + fld f16, 128(a0) + fld f17, 136(a0) + fld f18, 144(a0) + fld f19, 152(a0) + fld f20, 160(a0) + fld f21, 168(a0) + fld f22, 176(a0) + fld f23, 184(a0) + fld f24, 192(a0) + fld f25, 200(a0) + fld f26, 208(a0) + fld f27, 216(a0) + fld f28, 224(a0) + fld f29, 232(a0) + fld f30, 240(a0) + fld f31, 248(a0) + lw t0, 256(a0) + fscsr t0 + ret diff --git a/na/arch/riscv/trap/trap_md.cc b/na/arch/riscv/trap/trap_md.cc index f910b26..e30aea6 100644 --- a/na/arch/riscv/trap/trap_md.cc +++ b/na/arch/riscv/trap/trap_md.cc @@ -120,16 +120,45 @@ static TrapInfo build_trap_info(arch::TrapFrame* tf, * * Reads RISC-V CSRs, translates to MI TrapCause, applies arch-specific * fixups, then calls MI trap_handle(). + * + * After trap_handle returns, we must return to user mode via userret(). + * The assembly jalr t3 that called us has NO return-to-user code after it, + * so trap_dispatch must never return normally. * ======================================================================== */ -extern "C" void trap_dispatch(arch::TrapFrame* tf) +extern "C" void userret(arch::TrapFrame* tf); + +extern "C" [[noreturn]] void trap_dispatch(arch::TrapFrame* tf) { + /* Switch stvec to kernelvec immediately so that any traps during + * kernel execution (timer IRQs, page faults from copy_from_user) + * go through the kernel trap entry, not the user trap entry. + * This matches Linux which sets stvec to handle_exception (kernel) + * at the top of the user trap path. */ + extern void kernelvec(); + arch::trap::set_vector(reinterpret_cast<uint64>(&kernelvec)); + + /* Enable SUM so S-mode can access user pages (PTE_U). + * Without this, any dereference of user-space pointers in syscall + * handlers (sys_write buf, sys_read buf, etc.) would page fault. */ + arch::trap::enable_sum(); + uint64 scause = arch::trap::get_cause(); uint64 stval = arch::trap::get_value(); TrapOrigin origin = origin_from_sstatus(tf->sstatus); TrapInfo info = build_trap_info(tf, scause, stval, origin); + /* Per-trap trace from user mode. Stored at KLOG_DEBUG / KLOG_SUBSYS_TRAP + * so it lives in the ring buffer for postmortem but stays off the console + * by default. No more in-band 20-trap window — flip console_level or + * dump the ring on demand instead. */ + if (origin == TrapOrigin::FromUser) { + pr_debug_s(KLOG_SUBSYS_TRAP, + "trap: cause=%u epc=%llx val=%llx\n", + static_cast<unsigned>(info.cause), info.epc, info.val); + } + /* Save trapframe in TCB for syscall handlers (like fork) */ TaskControlBlock* curr = current_task(); if (curr) { @@ -152,6 +181,13 @@ extern "C" void trap_dispatch(arch::TrapFrame* tf) /* Call MI-layer dispatcher (zero inline assembly from here on) */ trap_handle(tf, info); + + /* Return to user mode. + * Set stvec back to trap_vector for the next user-mode trap, + * then jump to userret which restores registers and does sret. */ + arch::trap::set_vector(reinterpret_cast<uint64>(&trap_vector)); + userret(tf); + __builtin_unreachable(); } /* ======================================================================== diff --git a/na/arch/riscv/trap/trap_vector.S b/na/arch/riscv/trap/trap_vector.S index 160b122..8e45cae 100644 --- a/na/arch/riscv/trap/trap_vector.S +++ b/na/arch/riscv/trap/trap_vector.S @@ -90,6 +90,15 @@ trap_vector: /* Step 6: flush TLB after page table switch */ sfence.vma zero, zero + /* Step 6.5: restore kernel gp (global pointer). + * The compiler uses gp-relative addressing for global variable access + * (e.g. ld reg, offset(gp)). User mode may have set gp to anything, + * so we MUST reload it before entering any C++ code. */ +.option push +.option norelax + la gp, __global_pointer$ +.option pop + /* Pass TrapFrame* to C++ handler (a0 = tf) */ mv a0, tp @@ -97,7 +106,6 @@ trap_vector: mv tp, t2 /* Step 7: jump to C++ trap_handler */ - /* Step 7: jump to C++ trap_handler */ jalr t3 |
