xref: /DragonOS/kernel/src/arch/x86_64/fpu.rs (revision b11bb1b25676f528ec1b0e1da0af82b4652f70c4)
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::include::bindings::bindings::process_control_block;
13 
14 use super::asm::irqflags::{local_irq_restore, local_irq_save};
15 /// https://www.felixcloutier.com/x86/fxsave#tbl-3-47
16 #[repr(C, align(16))]
17 #[derive(Debug, Copy, Clone)]
18 pub struct FpState {
19     //0
20     fcw: u16,
21     fsw: u16,
22     ftw: u16,
23     fop: u16,
24     word2: u64,
25     //16
26     word3: u64,
27     mxcsr: u32,
28     mxcsr_mask: u32,
29     //32
30     mm: [u64; 16],
31     //160
32     xmm: [u64; 32],
33     //416
34     rest: [u64; 12],
35 }
36 
37 impl Default for FpState {
38     fn default() -> Self {
39         Self {
40             fcw: 0x037f,
41             fsw: Default::default(),
42             ftw: Default::default(),
43             fop: Default::default(),
44             word2: Default::default(),
45             word3: Default::default(),
46             mxcsr: 0x1f80,
47             mxcsr_mask: Default::default(),
48             mm: Default::default(),
49             xmm: Default::default(),
50             rest: Default::default(),
51         }
52     }
53 }
54 impl FpState {
55     #[allow(dead_code)]
56     pub fn new() -> Self {
57         assert!(core::mem::size_of::<Self>() == 512);
58         return Self::default();
59     }
60     #[allow(dead_code)]
61     pub fn save(&mut self) {
62         unsafe {
63             _fxsave64(self as *mut FpState as *mut u8);
64         }
65     }
66     #[allow(dead_code)]
67     pub fn restore(&self) {
68         unsafe {
69             _fxrstor64(self as *const FpState as *const u8);
70         }
71     }
72 
73     /// @brief 清空fp_state
74     pub fn clear(&mut self) {
75         *self = Self::default();
76     }
77 }
78 
79 /// @brief 从用户态进入内核时,保存浮点寄存器,并关闭浮点功能
80 pub fn fp_state_save(pcb: &mut process_control_block) {
81     // 该过程中不允许中断
82     let mut rflags: u64 = 0;
83     local_irq_save(&mut rflags);
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     local_irq_restore(&rflags);
116 }
117 
118 /// @brief 从内核态返回用户态时,恢复浮点寄存器,并开启浮点功能
119 pub fn fp_state_restore(pcb: &mut process_control_block) {
120     // 该过程中不允许中断
121     let mut rflags: u64 = 0;
122     local_irq_save(&mut rflags);
123 
124     if pcb.fp_state == null_mut() {
125         panic!("fp_state_restore: fp_state is null. pid={}", pcb.pid);
126     }
127 
128     unsafe {
129         asm! {
130             "mov rax, cr0",
131             "and ax, 0FFFBh",//[2]->0
132             "or ax,02h",//[1]->1
133             "mov cr0,rax",
134             "mov rax, cr4",
135             "or ax,3<<9",
136             "mov cr4, rax",
137             "clts",
138             "fninit"
139         }
140     }
141 
142     let fp = unsafe { (pcb.fp_state as usize as *mut FpState).as_mut().unwrap() };
143     fp.restore();
144     fp.clear();
145 
146     local_irq_restore(&rflags);
147 }
148