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)]
21#[repr(C)]
22pub struct ExtendedPstateState {
23    #[cfg(target_arch = "x86_64")]
24    state: x86_64::State,
25
26    #[cfg(target_arch = "aarch64")]
27    state: aarch64::State,
28
29    #[cfg(target_arch = "riscv64")]
30    state: riscv64::State,
31}
32
33#[cfg(target_arch = "aarch64")]
34/// A version of [`ExtendedPstateState`] that only stores the processor state
35/// accessible from AArch32 (e.g., registers Q0-Q15).
36#[derive(Clone, Copy, Default)]
37#[repr(C)]
38pub struct ExtendedAarch32PstateState {
39    state: aarch64::Aarch32State,
40}
41
42#[cfg(target_arch = "aarch64")]
43impl ExtendedAarch32PstateState {
44    pub fn reset(&mut self) {
45        self.state.reset()
46    }
47
48    pub fn get_arm32_qregs(&self) -> &[u128; 16] {
49        &self.state.q
50    }
51
52    pub fn get_arm32_fpsr(&self) -> u32 {
53        self.state.fpsr
54    }
55
56    pub fn get_arm32_fpcr(&self) -> u32 {
57        self.state.fpcr
58    }
59}
60
61impl ExtendedPstateState {
62    #[cfg(target_arch = "x86_64")]
63    pub fn with_strategy(strategy: x86_64::Strategy) -> Self {
64        Self { state: x86_64::State::with_strategy(strategy) }
65    }
66
67    pub fn reset(&mut self) {
68        self.state.reset()
69    }
70
71    #[cfg(target_arch = "aarch64")]
72    pub fn get_arm64_qregs(&self) -> &[u128; 32] {
73        &self.state.q
74    }
75
76    #[cfg(target_arch = "aarch64")]
77    pub fn get_arm64_fpsr(&self) -> u32 {
78        self.state.fpsr
79    }
80
81    #[cfg(target_arch = "aarch64")]
82    pub fn get_arm64_fpcr(&self) -> u32 {
83        self.state.fpcr
84    }
85
86    #[cfg(target_arch = "aarch64")]
87    pub fn set_arm64_state(&mut self, qregs: &[u128; 32], fpsr: u32, fpcr: u32) {
88        self.state.q = *qregs;
89        self.state.fpsr = fpsr;
90        self.state.fpcr = fpcr;
91    }
92
93    #[cfg(target_arch = "riscv64")]
94    pub fn get_riscv64_state(&self) -> &riscv64::State {
95        &self.state
96    }
97
98    #[cfg(target_arch = "riscv64")]
99    pub fn get_riscv64_state_mut(&mut self) -> &mut riscv64::State {
100        &mut self.state
101    }
102
103    #[cfg(target_arch = "x86_64")]
104    pub fn get_x64_xsave_area(&self) -> [u8; X64_XSAVE_AREA_SIZE] {
105        #[allow(
106            clippy::undocumented_unsafe_blocks,
107            reason = "Force documented unsafe blocks in Starnix"
108        )]
109        unsafe {
110            std::mem::transmute(self.state.buffer)
111        }
112    }
113
114    #[cfg(target_arch = "x86_64")]
115    pub fn set_x64_xsave_area(&mut self, xsave_area: [u8; X64_XSAVE_AREA_SIZE]) {
116        self.state.set_xsave_area(xsave_area);
117    }
118}
119
120/// Stores a pointer to the currently active extended pstate storage.
121/// The caller to the C entry points is responsible for ensuring that the active union
122/// member corresponds to the entry points being called.
123#[repr(C)]
124pub union ExtendedPstatePointer {
125    pub extended_pstate: *mut ExtendedPstateState,
126    #[cfg(target_arch = "aarch64")]
127    pub extended_aarch32_pstate: *mut ExtendedAarch32PstateState,
128}
129
130// Provided by assembly targets.
131unsafe extern "C" {
132    pub fn save_extended_pstate(state_addr: usize);
133    pub fn restore_extended_pstate(state_addr: usize);
134
135    #[cfg(target_arch = "aarch64")]
136    pub fn save_extended_aarch32_pstate(state_addr: usize);
137    #[cfg(target_arch = "aarch64")]
138    pub fn restore_extended_aarch32_pstate(state_addr: usize);
139}