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,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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user