Skip to main content

extended_pstate/
lib.rs

1// Copyright 2023 The Fuchsia Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#[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
32#[cfg(target_arch = "aarch64")]
33/// A version of [`ExtendedPstateState`] that only stores the processor state
34/// accessible from AArch32 (e.g., registers Q0-Q15).
35#[derive(Clone, Copy, Default)]
36pub struct ExtendedAarch32PstateState {
37    state: aarch64::Aarch32State,
38}
39
40#[cfg(target_arch = "aarch64")]
41impl ExtendedAarch32PstateState {
42    #[inline(always)]
43    pub fn save(&mut self) {
44        self.state.save()
45    }
46
47    /// This restores the extended processor state saved in this object into the processor's state
48    /// registers.
49    ///
50    /// # Safety
51    ///
52    /// This clobbers the current vector register, floating point register, and floating
53    /// point status and control register state including callee-saved registers. This should be
54    /// used in conjunction with save() to switch to an alternate extended processor state.
55    #[inline(always)]
56    pub unsafe fn restore(&self) {
57        #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
58        unsafe {
59            self.state.restore()
60        }
61    }
62
63    pub fn reset(&mut self) {
64        self.state.reset()
65    }
66}
67
68impl ExtendedPstateState {
69    #[cfg(target_arch = "x86_64")]
70    pub fn with_strategy(strategy: x86_64::Strategy) -> Self {
71        Self { state: x86_64::State::with_strategy(strategy) }
72    }
73
74    /// This saves the current extended processor state to this state object.
75    #[inline(always)]
76    fn save(&mut self) {
77        self.state.save()
78    }
79
80    #[inline(always)]
81    /// This restores the extended processor state saved in this object into the processor's state
82    /// registers.
83    ///
84    /// Safety: This clobbers the current vector register, floating point register, and floating
85    /// point status and control register state including callee-saved registers. This should be
86    /// used in conjunction with save() to switch to an alternate extended processor state.
87    unsafe fn restore(&self) {
88        #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
89        unsafe {
90            self.state.restore()
91        }
92    }
93
94    pub fn reset(&mut self) {
95        self.state.reset()
96    }
97
98    #[cfg(target_arch = "aarch64")]
99    pub fn get_arm64_qregs(&self) -> &[u128; 32] {
100        &self.state.q
101    }
102
103    #[cfg(target_arch = "aarch64")]
104    pub fn get_arm64_fpsr(&self) -> u32 {
105        self.state.fpsr
106    }
107
108    #[cfg(target_arch = "aarch64")]
109    pub fn get_arm64_fpcr(&self) -> u32 {
110        self.state.fpcr
111    }
112
113    #[cfg(target_arch = "aarch64")]
114    pub fn set_arm64_state(&mut self, qregs: &[u128; 32], fpsr: u32, fpcr: u32) {
115        self.state.q = *qregs;
116        self.state.fpsr = fpsr;
117        self.state.fpcr = fpcr;
118    }
119
120    #[cfg(target_arch = "riscv64")]
121    pub fn get_riscv64_state(&self) -> &riscv64::State {
122        &self.state
123    }
124
125    #[cfg(target_arch = "riscv64")]
126    pub fn get_riscv64_state_mut(&mut self) -> &mut riscv64::State {
127        &mut self.state
128    }
129
130    #[cfg(target_arch = "x86_64")]
131    pub fn get_x64_xsave_area(&self) -> [u8; X64_XSAVE_AREA_SIZE] {
132        #[allow(
133            clippy::undocumented_unsafe_blocks,
134            reason = "Force documented unsafe blocks in Starnix"
135        )]
136        unsafe {
137            std::mem::transmute(self.state.buffer)
138        }
139    }
140
141    #[cfg(target_arch = "x86_64")]
142    pub fn set_x64_xsave_area(&mut self, xsave_area: [u8; X64_XSAVE_AREA_SIZE]) {
143        self.state.set_xsave_area(xsave_area);
144    }
145}
146
147#[unsafe(no_mangle)]
148/// Restores the current extended architectural process state.
149///
150/// # Safety
151///    - state_addr must point to a pointer to an instance of ExtendedPstateState.
152pub unsafe extern "C" fn restore_extended_pstate(state_addr: usize) {
153    let state = state_addr as *const ExtendedPstateState;
154    #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
155    unsafe {
156        (*state).restore()
157    }
158}
159
160#[unsafe(no_mangle)]
161/// Save the current extended architectural process state.
162///
163/// # Safety
164///    - state_addr must point to pointer to an an exclusively owned instance of ExtendedPstateState.
165pub unsafe extern "C" fn save_extended_pstate(state_addr: usize) {
166    let state = state_addr as *mut ExtendedPstateState;
167    #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
168    unsafe {
169        (*state).save()
170    }
171}
172
173#[cfg(target_arch = "aarch64")]
174#[unsafe(no_mangle)]
175/// Restores the current extended AArch32-visible architectural process state.
176///
177/// # Safety
178///    - state_addr must point to pointer to an instance of ExtendedAarch32PstateState.
179pub unsafe extern "C" fn restore_extended_aarch32_pstate(state_addr: usize) {
180    let state = state_addr as *const ExtendedAarch32PstateState;
181    #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
182    unsafe {
183        (*state).restore()
184    }
185}
186
187#[cfg(target_arch = "aarch64")]
188#[unsafe(no_mangle)]
189/// Saves the current extended AArch32-visible architectural process state.
190///
191/// # Safety
192///    - state_addr must point to a pointer to an exclusively owned instance of ExtendedAarch32PstateState.
193pub unsafe extern "C" fn save_extended_aarch32_pstate(state_addr: usize) {
194    let state = state_addr as *mut ExtendedAarch32PstateState;
195    #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
196    unsafe {
197        (*state).save()
198    }
199}
200
201#[cfg(test)]
202mod test {
203    use super::*;
204
205    #[::fuchsia::test]
206    fn extended_pstate_state_lifecycle() {
207        let mut state = ExtendedPstateState::default();
208        #[allow(
209            clippy::undocumented_unsafe_blocks,
210            reason = "Force documented unsafe blocks in Starnix"
211        )]
212        unsafe {
213            state.save();
214            state.restore();
215        }
216    }
217}