Skip to main content

islet_rmm/rec/
context.rs

1use super::gic;
2use super::pauth;
3use super::pauth::PauthRegister;
4use super::pmu;
5use super::pmu::PmuRegister;
6use super::simd;
7use super::simd::SimdContext;
8use super::timer;
9use super::Rec;
10use crate::rmi::error::Error;
11
12use aarch64_cpu::registers::*;
13
14#[repr(C)]
15#[derive(Default, Debug)]
16pub struct Context {
17    pub gp_regs: [u64; 31],
18    pub elr_el2: u64,
19    pub spsr_el2: u64,
20    pub sys_regs: SystemRegister,
21    pub mdcr_el2: u64,
22    pub gic_state: GICRegister,
23    pub timer: TimerRegister,
24    pub simd: SimdContext,
25    pub pauth: PauthRegister,
26    pub pmu: PmuRegister,
27}
28
29pub struct RegOffset;
30impl RegOffset {
31    pub const PC: usize = 31;
32    pub const PSTATE: usize = 32;
33    pub const SCTLR: usize = 40;
34}
35
36pub fn set_reg(rec: &mut Rec<'_>, register: usize, value: usize) -> Result<(), Error> {
37    match register {
38        0..=30 => {
39            rec.context.gp_regs[register] = value as u64;
40            Ok(())
41        }
42        RegOffset::PC => {
43            rec.context.elr_el2 = value as u64;
44            Ok(())
45        }
46        RegOffset::PSTATE => {
47            rec.context.spsr_el2 = value as u64;
48            Ok(())
49        }
50        _ => Err(Error::RmiErrorInput),
51    }?;
52    Ok(())
53}
54
55pub fn get_reg(rec: &Rec<'_>, register: usize) -> Result<usize, Error> {
56    match register {
57        0..=30 => {
58            let value = rec.context.gp_regs[register];
59            Ok(value as usize)
60        }
61        RegOffset::PC => {
62            let value = rec.context.elr_el2;
63            Ok(value as usize)
64        }
65        _ => Err(Error::RmiErrorInput),
66    }
67}
68
69impl Context {
70    pub fn new() -> Self {
71        // Set appropriate sys registers
72        // TODO: enable floating point
73        // CPTR_EL2, CPACR_EL1, update vectors.s, etc..
74        Self {
75            spsr_el2: (SPSR_EL2::D.mask << SPSR_EL2::D.shift)
76                | (SPSR_EL2::A.mask << SPSR_EL2::A.shift)
77                | (SPSR_EL2::I.mask << SPSR_EL2::I.shift)
78                | (SPSR_EL2::F.mask << SPSR_EL2::F.shift)
79                | (SPSR_EL2::M.mask & u64::from(SPSR_EL2::M::EL1h)) << SPSR_EL2::M.shift,
80            ..Default::default()
81        }
82    }
83
84    /// Restores the current execution context from the given `Rec`.
85    ///
86    /// # Safety
87    ///
88    /// - This function modifies processor-specific registers and state;
89    ///   ensure that this is safe in the current execution context.
90    pub unsafe fn into_current(rec: &Rec<'_>) {
91        TPIDR_EL2.set(rec as *const _ as u64);
92        gic::restore_state(rec);
93        pauth::restore_state(rec);
94        pmu::restore_state(rec);
95        #[cfg(not(fuzzing))]
96        timer::restore_state(rec);
97        #[cfg(not(any(test, miri, fuzzing)))]
98        simd::restore_state(rec);
99    }
100
101    /// Saves the current execution context into the given `Rec` record.
102    ///
103    /// # Safety
104    ///
105    /// - This function reads and modifies processor-specific registers and state;
106    ///   ensure that this is appropriate in the current execution context.
107    pub unsafe fn from_current(rec: &mut Rec<'_>) {
108        gic::save_state(rec);
109        pauth::save_state(rec);
110        pmu::save_state(rec);
111        #[cfg(not(fuzzing))]
112        timer::save_state(rec);
113        #[cfg(not(any(test, miri, fuzzing)))]
114        simd::save_state(rec);
115    }
116}
117
118/// Generic Interrupt Controller Registers
119#[repr(C)]
120#[derive(Default, Debug)]
121pub struct GICRegister {
122    // Interrupt Controller Hyp Active Priorities Group 0 Registers
123    pub ich_ap0r_el2: [u64; 4],
124    // Interrupt Controller Hyp Active Priorities Group 1 Registers
125    pub ich_ap1r_el2: [u64; 4],
126    // GICv3 Virtual Machine Control Register
127    pub ich_vmcr_el2: u64,
128    // Interrupt Controller Hyp Control Register
129    pub ich_hcr_el2: u64,
130    // GICv3 List Registers
131    pub ich_lr_el2: [u64; 16],
132    // GICv3 Maintenance Interrupt State Register
133    pub ich_misr_el2: u64,
134}
135
136#[repr(C)]
137#[derive(Default, Debug)]
138// System registers without explicit exception level are for EL1
139// unless it is unique to EL2 (e.g., vmpidr_el2, hpfar_el2)
140pub struct SystemRegister {
141    pub sp: u64,
142    pub sp_el0: u64,
143    pub esr_el1: u64,
144    pub vbar: u64,
145    pub ttbr0: u64,
146    pub ttbr1: u64,
147    pub mair: u64,
148    pub amair: u64,
149    pub tcr: u64,
150    pub tpidr: u64,
151    pub tpidr_el0: u64,
152    pub tpidrro: u64,
153    pub actlr: u64,
154    pub vmpidr: u64,
155    pub csselr: u64,
156    pub cpacr: u64,
157    pub afsr0: u64,
158    pub afsr1: u64,
159    pub far: u64,
160    pub contextidr: u64,
161    pub cntkctl: u64,
162    pub par: u64,
163    pub vttbr: u64,
164    pub elr: u64,
165    pub spsr: u64,
166    pub sctlr: u64,
167    pub esr_el2: u64,
168    pub hpfar: u64,
169    pub far_el2: u64,
170}
171
172#[repr(C)]
173#[derive(Default, Debug)]
174pub struct TimerRegister {
175    pub cntvoff_el2: u64,
176    pub cntv_cval_el0: u64,
177    pub cntv_ctl_el0: u64,
178    pub cntpoff_el2: u64,
179    pub cntp_cval_el0: u64,
180    pub cntp_ctl_el0: u64,
181    pub cnthctl_el2: u64,
182}