feat(kernel): lazy user FPU: off until first FP insn (illegal-insn trap -> zeroed regs, retry), save on dirty trap, restore on switch, off for threads without + kernel; spawntest per-thread FP check
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
mod fast;
|
||||
mod fp;
|
||||
mod sched;
|
||||
mod vector;
|
||||
|
||||
@@ -17,6 +18,7 @@ const CAUSE_INTERRUPT_BIT: usize = 1 << 63;
|
||||
const CAUSE_S_SOFTWARE: usize = 1;
|
||||
const CAUSE_S_TIMER: usize = 5;
|
||||
const CAUSE_S_EXTERNAL: usize = 9;
|
||||
const CAUSE_ILLEGAL_INSTRUCTION: usize = 2;
|
||||
const CAUSE_ECALL_U: usize = 8;
|
||||
/// Set in `sstatus` when the trap came from supervisor mode.
|
||||
const SSTATUS_SPP: usize = 1 << 8;
|
||||
@@ -29,6 +31,8 @@ pub fn init() {
|
||||
let addr = trap_vector as *const () as usize;
|
||||
core::arch::asm!("csrw stvec, {0}", in(reg) addr);
|
||||
core::arch::asm!("csrw sscratch, zero");
|
||||
// The kernel never uses the FPU; user threads get it lazily.
|
||||
core::arch::asm!("csrc sstatus, {0}", in(reg) 3usize << 13);
|
||||
// SIE stays clear; interrupts are enabled only by sret into userspace.
|
||||
let sie_bits = (1usize << 5) | (1usize << 9) | (1usize << 1);
|
||||
core::arch::asm!("csrs sie, {0}", in(reg) sie_bits);
|
||||
@@ -90,6 +94,14 @@ extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
||||
}
|
||||
crate::smp::service_ipi();
|
||||
crate::smp::lock();
|
||||
// The thread's FP registers are saved before anything can switch away.
|
||||
if let Some(ctx) = kern()
|
||||
.current_thread()
|
||||
.and_then(|t| kern().thread_context_mut(t))
|
||||
{
|
||||
fp::save_if_dirty(frame, ctx);
|
||||
}
|
||||
fp::kernel_off();
|
||||
if scause & CAUSE_INTERRUPT_BIT != 0 {
|
||||
handle_interrupt(frame, scause & !CAUSE_INTERRUPT_BIT);
|
||||
} else {
|
||||
@@ -163,6 +175,11 @@ fn handle_exception(frame: &mut TrapFrame, scause: usize) {
|
||||
}
|
||||
}
|
||||
}
|
||||
CAUSE_ILLEGAL_INSTRUCTION
|
||||
if kern()
|
||||
.current_thread()
|
||||
.and_then(|t| kern().thread_context_mut(t))
|
||||
.is_some_and(|ctx| fp::first_use(frame, ctx)) => {}
|
||||
_ => {
|
||||
let uart = crate::hw::uart::Uart::new();
|
||||
uart.write_str("FAULT: scause=");
|
||||
|
||||
Reference in New Issue
Block a user