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
32impl ExtendedPstateState {
33    /// Runs the provided function with the saved extended processor state.  The
34    /// provided function must be written carefully to avoid inadvertently using
35    /// any extended state itself such as vector or floating point registers.
36    ///
37    /// # Safety
38    ///
39    /// |f| must not use any extended processor state.
40    pub unsafe fn run_with_saved_state<F, R>(&mut self, f: F) -> R
41    where
42        F: FnOnce() -> R,
43    {
44        self.restore();
45        let r = f();
46        self.save();
47        r
48    }
49
50    #[cfg(target_arch = "x86_64")]
51    pub fn with_strategy(strategy: x86_64::Strategy) -> Self {
52        Self { state: x86_64::State::with_strategy(strategy) }
53    }
54
55    /// This saves the current extended processor state to this state object.
56    #[inline(always)]
57    fn save(&mut self) {
58        self.state.save()
59    }
60
61    #[inline(always)]
62    /// This restores the extended processor state saved in this object into the processor's state
63    /// registers.
64    ///
65    /// Safety: This clobbers the current vector register, floating point register, and floating
66    /// point status and control register state including callee-saved registers. This should be
67    /// used in conjunction with save() to switch to an alternate extended processor state.
68    unsafe fn restore(&self) {
69        self.state.restore()
70    }
71
72    pub fn reset(&mut self) {
73        self.state.reset()
74    }
75
76    #[cfg(target_arch = "aarch64")]
77    pub fn get_arm64_qregs(&self) -> &[u128; 32] {
78        &self.state.q
79    }
80
81    #[cfg(target_arch = "aarch64")]
82    pub fn get_arm64_fpsr(&self) -> u32 {
83        self.state.fpsr
84    }
85
86    #[cfg(target_arch = "aarch64")]
87    pub fn get_arm64_fpcr(&self) -> u32 {
88        self.state.fpcr
89    }
90
91    #[cfg(target_arch = "aarch64")]
92    pub fn set_arm64_state(&mut self, qregs: &[u128; 32], fpsr: u32, fpcr: u32) {
93        self.state.q = *qregs;
94        self.state.fpsr = fpsr;
95        self.state.fpcr = fpcr;
96    }
97
98    #[cfg(target_arch = "riscv64")]
99    pub fn get_riscv64_state(&self) -> &riscv64::State {
100        &self.state
101    }
102
103    #[cfg(target_arch = "riscv64")]
104    pub fn get_riscv64_state_mut(&mut self) -> &mut riscv64::State {
105        &mut self.state
106    }
107
108    #[cfg(target_arch = "x86_64")]
109    pub fn get_x64_xsave_area(&self) -> [u8; X64_XSAVE_AREA_SIZE] {
110        unsafe { std::mem::transmute(self.state.buffer) }
111    }
112
113    #[cfg(target_arch = "x86_64")]
114    pub fn set_x64_xsave_area(&mut self, xsave_area: [u8; X64_XSAVE_AREA_SIZE]) {
115        self.state.set_xsave_area(xsave_area);
116    }
117}
118
119#[no_mangle]
120unsafe extern "C" fn restore_extended_pstate(state_addr: usize) {
121    let state = state_addr as *mut ExtendedPstateState;
122    (&*state).restore()
123}
124
125#[no_mangle]
126unsafe extern "C" fn save_extended_pstate(state_addr: usize) {
127    let state = state_addr as *mut ExtendedPstateState;
128    (&mut *state).save()
129}
130
131#[cfg(test)]
132mod test {
133    use super::*;
134
135    #[::fuchsia::test]
136    fn extended_pstate_state_lifecycle() {
137        let mut state = ExtendedPstateState::default();
138        unsafe {
139            state.save();
140            state.restore();
141        }
142    }
143}