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:
2026-10-28 03:20:41 +01:00
parent 34a44b5928
commit c256f4ecf3
7 changed files with 302 additions and 1 deletions

View File

@@ -1,9 +1,27 @@
//! Saved register state of a thread.
/// A thread's floating-point registers and their control word. A thread
/// has none until its first floating-point instruction (see
/// `SavedContext::enable_fp`): until then it cannot see another thread's.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FpState {
pub registers: [u64; 32],
pub control: u64,
}
impl FpState {
pub const ZERO: Self = Self {
registers: [0; 32],
control: 0,
};
}
pub struct SavedContext {
registers: [usize; 32],
pc: usize,
status: usize,
fp: FpState,
fp_enabled: bool,
}
impl SavedContext {
@@ -12,6 +30,8 @@ impl SavedContext {
registers: [0; 32],
pc: 0,
status: 0,
fp: FpState::ZERO,
fp_enabled: false,
}
}
@@ -48,4 +68,39 @@ impl SavedContext {
pub fn registers_mut(&mut self) -> &mut [usize; 32] {
&mut self.registers
}
/// Its floating-point registers, if it has used any.
pub fn fp(&self) -> Option<&FpState> {
self.fp_enabled.then_some(&self.fp)
}
pub fn fp_mut(&mut self) -> Option<&mut FpState> {
self.fp_enabled.then_some(&mut self.fp)
}
/// Gives it floating-point registers, all zero.
pub fn enable_fp(&mut self) -> &mut FpState {
self.fp = FpState::ZERO;
self.fp_enabled = true;
&mut self.fp
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_thread_has_no_fp_until_it_is_given_zeroed_registers() {
let mut c = SavedContext::empty();
assert!(c.fp().is_none() && c.fp_mut().is_none());
c.enable_fp().registers[3] = 7;
assert_eq!(c.fp().unwrap().registers[3], 7);
c.enable_fp();
assert_eq!(
c.fp(),
Some(&FpState::ZERO),
"enabling again starts from zero"
);
}
}

View File

@@ -9,7 +9,7 @@ use crate::error::KernelError;
mod context;
mod table;
pub use context::SavedContext;
pub use context::{FpState, SavedContext};
pub use table::{MAX_THREADS, ThreadTable};
#[cfg(test)]