1#[cfg(target_arch = "x86_64")]
6pub mod x86_64;
7
8#[cfg(target_arch = "x86_64")]
9pub use x86_64::XSAVE_AREA_SIZE as X64_XSAVE_AREA_SIZE;
10
11#[cfg(target_arch = "x86_64")]
12pub use x86_64::SUPPORTED_XSAVE_FEATURES as X64_SUPPORTED_XSAVE_FEATURES;
13
14#[cfg(target_arch = "aarch64")]
15mod aarch64;
16
17#[cfg(target_arch = "riscv64")]
18pub mod riscv64;
19
20#[derive(Clone, Copy, Default)]
21pub struct ExtendedPstateState {
22 #[cfg(target_arch = "x86_64")]
23 state: x86_64::State,
24
25 #[cfg(target_arch = "aarch64")]
26 state: aarch64::State,
27
28 #[cfg(target_arch = "riscv64")]
29 state: riscv64::State,
30}
31
32impl ExtendedPstateState {
33 pub unsafe fn run_with_saved_state<F, R>(&mut self, f: F) -> R
41 where
42 F: FnOnce() -> R,
43 {
44 #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
45 unsafe {
46 self.restore();
47 }
48 let r = f();
49 self.save();
50 r
51 }
52
53 #[cfg(target_arch = "x86_64")]
54 pub fn with_strategy(strategy: x86_64::Strategy) -> Self {
55 Self { state: x86_64::State::with_strategy(strategy) }
56 }
57
58 #[inline(always)]
60 fn save(&mut self) {
61 self.state.save()
62 }
63
64 #[inline(always)]
65 unsafe fn restore(&self) {
72 #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
73 unsafe {
74 self.state.restore()
75 }
76 }
77
78 pub fn reset(&mut self) {
79 self.state.reset()
80 }
81
82 #[cfg(target_arch = "aarch64")]
83 pub fn get_arm64_qregs(&self) -> &[u128; 32] {
84 &self.state.q
85 }
86
87 #[cfg(target_arch = "aarch64")]
88 pub fn get_arm64_fpsr(&self) -> u32 {
89 self.state.fpsr
90 }
91
92 #[cfg(target_arch = "aarch64")]
93 pub fn get_arm64_fpcr(&self) -> u32 {
94 self.state.fpcr
95 }
96
97 #[cfg(target_arch = "aarch64")]
98 pub fn set_arm64_state(&mut self, qregs: &[u128; 32], fpsr: u32, fpcr: u32) {
99 self.state.q = *qregs;
100 self.state.fpsr = fpsr;
101 self.state.fpcr = fpcr;
102 }
103
104 #[cfg(target_arch = "riscv64")]
105 pub fn get_riscv64_state(&self) -> &riscv64::State {
106 &self.state
107 }
108
109 #[cfg(target_arch = "riscv64")]
110 pub fn get_riscv64_state_mut(&mut self) -> &mut riscv64::State {
111 &mut self.state
112 }
113
114 #[cfg(target_arch = "x86_64")]
115 pub fn get_x64_xsave_area(&self) -> [u8; X64_XSAVE_AREA_SIZE] {
116 #[allow(
117 clippy::undocumented_unsafe_blocks,
118 reason = "Force documented unsafe blocks in Starnix"
119 )]
120 unsafe {
121 std::mem::transmute(self.state.buffer)
122 }
123 }
124
125 #[cfg(target_arch = "x86_64")]
126 pub fn set_x64_xsave_area(&mut self, xsave_area: [u8; X64_XSAVE_AREA_SIZE]) {
127 self.state.set_xsave_area(xsave_area);
128 }
129}
130
131#[unsafe(no_mangle)]
132unsafe extern "C" fn restore_extended_pstate(state_addr: usize) {
133 let state = state_addr as *mut ExtendedPstateState;
134 #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
135 unsafe {
136 (&*state).restore()
137 }
138}
139
140#[unsafe(no_mangle)]
141unsafe extern "C" fn save_extended_pstate(state_addr: usize) {
142 let state = state_addr as *mut ExtendedPstateState;
143 #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
144 unsafe {
145 (&mut *state).save()
146 }
147}
148
149#[cfg(test)]
150mod test {
151 use super::*;
152
153 #[::fuchsia::test]
154 fn extended_pstate_state_lifecycle() {
155 let mut state = ExtendedPstateState::default();
156 #[allow(
157 clippy::undocumented_unsafe_blocks,
158 reason = "Force documented unsafe blocks in Starnix"
159 )]
160 unsafe {
161 state.save();
162 state.restore();
163 }
164 }
165}