kernel/arch/riscv64/fpu/
fpu_switch.rs

1use super::super::vcpu::Vcpu;
2
3/// Save user FPU context when switching away from a task in the kernel.
4///
5/// RISC-V uses FS dirty tracking, so we only save when needed.
6#[inline]
7pub fn kernel_switch_out_user_fpu(vcpu: &mut Vcpu) {
8    if !crate::arch::user_fpu_enabled() {
9        return;
10    }
11    if super::is_fpu_dirty() {
12        vcpu.fpu_used = true;
13        super::enable_fpu();
14        unsafe { vcpu.fpu.save() };
15        super::mark_fpu_clean();
16    }
17}
18
19/// Restore user FPU context when resuming a task in the kernel.
20///
21/// This restores the task's saved context into the architectural registers so
22/// subsequent kernel operations (and the eventual user return path) can rely on
23/// a consistent state.
24#[inline]
25pub fn kernel_switch_in_user_fpu(vcpu: &mut Vcpu) {
26    if !crate::arch::user_fpu_enabled() {
27        return;
28    }
29    if vcpu.fpu_used {
30        super::enable_fpu();
31        unsafe { vcpu.fpu.restore() };
32        super::mark_fpu_clean();
33    }
34}
35
36/// Handle user vector state on kernel switch-out.
37///
38/// We avoid saving vregs on every timeslice. If VS is dirty for the current
39/// owner, we mark the per-hart owner as dirty so the save can be deferred until
40/// another task must overwrite the live vregs.
41#[inline]
42pub fn kernel_switch_out_user_vector(cpu_id: usize, task_id: usize, vcpu: &mut Vcpu) {
43    if !crate::arch::user_vector_enabled() {
44        return;
45    }
46    if super::is_vector_dirty() {
47        vcpu.vector_used = true;
48
49        if super::super::get_vector_owner(cpu_id) == task_id {
50            super::super::set_vector_owner_dirty(cpu_id, true);
51        }
52
53        // Keep VS off while in the kernel unless explicitly needed.
54        super::disable_vector();
55    }
56}