xref: /DragonOS/kernel/src/arch/x86_64/fpu.rs (revision 5db5a5652c9f4ae77bc8dc298f02057299442208)
1 use core::{
2     arch::{
3         asm,
4         x86_64::{_fxrstor64, _fxsave64},
5     },
6     ffi::c_void,
7     ptr::null_mut,
8 };
9 
10 use alloc::boxed::Box;
11 
12 use crate::{exception::InterruptArch, include::bindings::bindings::process_control_block};
13 
14 use crate::arch::CurrentIrqArch;
15 
16 /// https://www.felixcloutier.com/x86/fxsave#tbl-3-47
17 #[repr(C, align(16))]
18 #[derive(Debug, Copy, Clone)]
19 pub struct FpState {
20     //0
21     fcw: u16,
22     fsw: u16,
23     ftw: u16,
24     fop: u16,
25     word2: u64,
26     //16
27     word3: u64,
28     mxcsr: u32,
29     mxcsr_mask: u32,
30     //32
31     mm: [u64; 16],
32     //160
33     xmm: [u64; 32],
34     //416
35     rest: [u64; 12],
36 }
37 
38 impl Default for FpState {
39     fn default() -> Self {
40         Self {
41             fcw: 0x037f,
42             fsw: Default::default(),
43             ftw: Default::default(),
44             fop: Default::default(),
45             word2: Default::default(),
46             word3: Default::default(),
47             mxcsr: 0x1f80,
48             mxcsr_mask: Default::default(),
49             mm: Default::default(),
50             xmm: Default::default(),
51             rest: Default::default(),
52         }
53     }
54 }
55 impl FpState {
56     #[allow(dead_code)]
57     pub fn new() -> Self {
58         assert!(core::mem::size_of::<Self>() == 512);
59         return Self::default();
60     }
61     #[allow(dead_code)]
62     pub fn save(&mut self) {
63         unsafe {
64             _fxsave64(self as *mut FpState as *mut u8);
65         }
66     }
67     #[allow(dead_code)]
68     pub fn restore(&self) {
69         unsafe {
70             _fxrstor64(self as *const FpState as *const u8);
71         }
72     }
73 
74     /// @brief 清空fp_state
75     pub fn clear(&mut self) {
76         *self = Self::default();
77     }
78 }
79 
80 /// @brief 从用户态进入内核时,保存浮点寄存器,并关闭浮点功能
81 pub fn fp_state_save(pcb: &mut process_control_block) {
82     // 该过程中不允许中断
83     let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
84 
85     let fp: &mut FpState = if pcb.fp_state == null_mut() {
86         let f = Box::leak(Box::new(FpState::default()));
87         pcb.fp_state = f as *mut FpState as usize as *mut c_void;
88         f
89     } else {
90         unsafe { (pcb.fp_state as usize as *mut FpState).as_mut().unwrap() }
91     };
92 
93     // 保存浮点寄存器
94     fp.save();
95 
96     // 关闭浮点功能
97     unsafe {
98         asm!(
99             "mov rax, cr4",
100             "and ax,~(3<<9)", //[9][10]->0
101             "mov cr4,rax",
102             "mov rax, cr0",
103             "and ax,~(02h)",    //[1]->0
104             "or ax, ~(0FFFBh)", //[2]->1
105             "mov cr0, rax"      /*
106                                 "mov rax, cr0",
107                                 "and ax, 0xFFFB",
108                                 "or ax,0x2",
109                                 "mov cr0,rax",
110                                 "mov rax, cr4",
111                                 "or ax,3<<9",
112                                 "mov cr4, rax" */
113         )
114     }
115     drop(guard);
116 }
117 
118 /// @brief 从内核态返回用户态时,恢复浮点寄存器,并开启浮点功能
119 pub fn fp_state_restore(pcb: &mut process_control_block) {
120     // 该过程中不允许中断
121     let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
122 
123     if pcb.fp_state == null_mut() {
124         panic!("fp_state_restore: fp_state is null. pid={}", pcb.pid);
125     }
126 
127     unsafe {
128         asm! {
129             "mov rax, cr0",
130             "and ax, 0FFFBh",//[2]->0
131             "or ax,02h",//[1]->1
132             "mov cr0,rax",
133             "mov rax, cr4",
134             "or ax,3<<9",
135             "mov cr4, rax",
136             "clts",
137             "fninit"
138         }
139     }
140 
141     let fp = unsafe { (pcb.fp_state as usize as *mut FpState).as_mut().unwrap() };
142     fp.restore();
143     fp.clear();
144 
145     drop(guard);
146 }
147