Enable hardware floats and save on every context switch

This commit is contained in:
pjht 2025-02-27 10:54:38 -06:00
parent c0d0ad5a1e
commit cc18a3f7f0
Signed by: pjht
GPG Key ID: CA239FC6934E6F3A
2 changed files with 57 additions and 10 deletions

View File

@ -86,7 +86,7 @@ mod start;
mod tasking; mod tasking;
mod virtual_memory; mod virtual_memory;
use core::{ptr, slice}; use core::{arch::asm, ptr, slice};
use bootinfo::BOOTINFO; use bootinfo::BOOTINFO;
use cast::usize; use cast::usize;
@ -105,7 +105,10 @@ use tar_no_std::TarArchiveRef;
use tasking::{SleepReason, TASKING}; use tasking::{SleepReason, TASKING};
use virtual_memory::{ACTIVE_SPACE, KERNEL_SPACE}; use virtual_memory::{ACTIVE_SPACE, KERNEL_SPACE};
use x86_64::{ use x86_64::{
registers::rflags::{self, RFlags}, registers::{
control::{Cr0, Cr0Flags, Cr4, Cr4Flags},
rflags::{self, RFlags},
},
structures::paging::{Page, PageTableFlags}, structures::paging::{Page, PageTableFlags},
VirtAddr, VirtAddr,
}; };
@ -129,6 +132,19 @@ pub fn main() {
unsafe { unsafe {
rflags::write(rflags_data); rflags::write(rflags_data);
} }
// Enable the FPU
unsafe {
Cr0::update(|cr0| {
cr0.remove(Cr0Flags::EMULATE_COPROCESSOR);
cr0.insert(Cr0Flags::MONITOR_COPROCESSOR);
});
Cr4::update(|cr4| {
cr4.insert(Cr4Flags::OSFXSR);
cr4.insert(Cr4Flags::OSXMMEXCPT_ENABLE);
});
asm!("FNINIT");
tasking::store_initial_fpu_state();
}
gdt::init(); gdt::init();
Lazy::force(&PHYSICAL_MEMORY); Lazy::force(&PHYSICAL_MEMORY);
Lazy::force(&KERNEL_SPACE); Lazy::force(&KERNEL_SPACE);

View File

@ -1,19 +1,14 @@
use crate::{ use crate::{
gdt, gdt, interrupts::{send_ipc_to, REGISTERD_PIDS}, pit, println, virtual_memory::{ASpaceMutex, AddressSpace, PagingError, ACTIVE_SPACE, KERNEL_SPACE}
interrupts::{send_ipc_to, REGISTERD_PIDS},
pit, println,
virtual_memory::{ASpaceMutex, AddressSpace, PagingError, ACTIVE_SPACE, KERNEL_SPACE},
}; };
use alloc::{boxed::Box, collections::VecDeque, vec, vec::Vec}; use alloc::{boxed::Box, collections::VecDeque, vec, vec::Vec};
use cast::{u64, usize}; use cast::{u64, usize};
use core::{ use core::{
arch::naked_asm, arch::{asm, naked_asm}, ptr::{addr_of, addr_of_mut}, sync::atomic::{AtomicBool, Ordering}
ptr::{addr_of, addr_of_mut},
sync::atomic::{AtomicBool, Ordering},
}; };
use crossbeam_queue::SegQueue; use crossbeam_queue::SegQueue;
use slab::Slab; use slab::Slab;
use spin::{Lazy, Mutex, RwLock}; use spin::{Lazy, Mutex, Once, RwLock};
use x86_64::{ use x86_64::{
structures::paging::{Page, PageTableFlags}, structures::paging::{Page, PageTableFlags},
VirtAddr, VirtAddr,
@ -88,6 +83,36 @@ pub enum SleepReason {
TimeSleep, TimeSleep,
} }
static INITIAL_FPU_STATE: Once<FpuState> = Once::new();
pub fn store_initial_fpu_state() {
let mut state = FpuState::new();
state.save();
INITIAL_FPU_STATE.call_once(|| state);
}
#[repr(align(16))]
#[derive(Debug, Clone, Copy)]
struct FpuState {
state: [u8; 512]
}
impl FpuState {
fn new() -> Self {
Self {
state: [0; 512],
}
}
fn save(&mut self) {
unsafe { asm!("fxsave [rax]", in("rax") &mut self.state) };
}
fn load(&self) {
unsafe { asm!("fxrstor [rax]", in("rax") &self.state) };
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Process { pub struct Process {
address_space: Option<AddressSpace>, address_space: Option<AddressSpace>,
@ -176,6 +201,7 @@ impl Process {
kernel_stack, kernel_stack,
sleeping: RwLock::new(sleeping), sleeping: RwLock::new(sleeping),
tls_values: Mutex::new(vec![0; self.num_tls]), tls_values: Mutex::new(vec![0; self.num_tls]),
fpu_state: Mutex::new(*INITIAL_FPU_STATE.get().unwrap()),
}; };
let idx = self.threads.write().insert(thread); let idx = self.threads.write().insert(thread);
self.num_threads += 1; self.num_threads += 1;
@ -194,6 +220,7 @@ pub struct Thread {
kernel_esp: *mut usize, kernel_esp: *mut usize,
kernel_esp_top: VirtAddr, kernel_esp_top: VirtAddr,
tls_values: Mutex<Vec<u64>>, tls_values: Mutex<Vec<u64>>,
fpu_state: Mutex<FpuState>,
} }
pub struct IpcMessage { pub struct IpcMessage {
@ -351,9 +378,11 @@ impl Tasking {
if self.current_thread(|thread| thread.sleeping.read().is_none()) { if self.current_thread(|thread| thread.sleeping.read().is_none()) {
self.ready_to_run.lock().push_back((current_pid, self.current_tid().unwrap())); self.ready_to_run.lock().push_back((current_pid, self.current_tid().unwrap()));
} }
self.current_thread(|thread| thread.fpu_state.lock().save());
let curr_stack = self.current_thread_mut(|thread| addr_of_mut!(thread.kernel_esp)); let curr_stack = self.current_thread_mut(|thread| addr_of_mut!(thread.kernel_esp));
*self.current_pid.write() = Some(next_process_pid); *self.current_pid.write() = Some(next_process_pid);
*self.current_tid.write() = Some(next_process_tid); *self.current_tid.write() = Some(next_process_tid);
self.current_thread(|thread| thread.fpu_state.lock().load());
let kernel_esp = self.current_thread(|thread| { let kernel_esp = self.current_thread(|thread| {
gdt::set_tss_stack(thread.kernel_esp_top); gdt::set_tss_stack(thread.kernel_esp_top);
thread.kernel_esp thread.kernel_esp
@ -437,6 +466,7 @@ impl Tasking {
.expect("Non-current process has active page table") .expect("Non-current process has active page table")
.activate(); .activate();
}); });
self.current_thread(|thread| thread.fpu_state.lock().load());
let kernel_esp = self.current_thread_mut(|thread| { let kernel_esp = self.current_thread_mut(|thread| {
gdt::set_tss_stack(thread.kernel_esp_top); gdt::set_tss_stack(thread.kernel_esp_top);
thread.kernel_esp thread.kernel_esp
@ -493,6 +523,7 @@ impl Tasking {
} }
*self.current_pid.write() = Some(next_process_pid); *self.current_pid.write() = Some(next_process_pid);
*self.current_tid.write() = Some(next_process_tid); *self.current_tid.write() = Some(next_process_tid);
self.current_thread(|thread| thread.fpu_state.lock().load());
let kernel_esp = self.current_thread_mut(|thread| { let kernel_esp = self.current_thread_mut(|thread| {
gdt::set_tss_stack(thread.kernel_esp_top); gdt::set_tss_stack(thread.kernel_esp_top);
thread.kernel_esp thread.kernel_esp