1pub mod context;
2pub mod gic;
3pub mod mmio;
4pub mod pauth;
5pub mod pmu;
6pub mod sea;
7pub mod simd;
8pub mod timer;
9
10use crate::realm::rd::Rd;
11use crate::rec::context::Context;
12use crate::rmi::error::Error;
13use crate::rmi::rec::params::NR_AUX;
14use crate::rmm_exit;
15use crate::rsi::attestation::MAX_CHALLENGE_SIZE;
16use aarch64_cpu::registers::*;
17
18use core::cell::OnceCell;
19use vmsa::guard::Content;
20
21const MAX_RECS_ORDER_VALUE: u64 = 4;
22
23#[derive(Copy, Clone, Debug)]
24pub enum RecAuxIndex {
25 SIMD = 0,
26 PMU = 1,
27 Undefined,
28}
29
30#[derive(Clone, Copy, Debug, PartialEq)]
31pub enum RmmRecAttestState {
32 AttestInProgress,
33 NoAttestInProgress,
34}
35
36#[derive(Clone, Copy, Debug, PartialEq)]
37pub enum RmmRecEmulatableAbort {
38 EmulatableAbort,
39 NotEmulatableAbort,
40}
41
42#[derive(Copy, Clone, Debug, PartialEq)]
43pub enum State {
44 Ready = 1,
45 Running = 2,
46}
47
48#[derive(Debug)]
49struct Ripas {
50 start: u64,
51 end: u64,
52 addr: u64,
53 state: u8,
54 flags: u64,
55}
56
57#[repr(C)]
58#[derive(Debug)]
59pub struct Rec<'a> {
60 pub context: Context,
61 attest_state: RmmRecAttestState,
62 attest_challenge: [u8; MAX_CHALLENGE_SIZE],
64 attest_token_offset: usize,
65 aux: [u64; NR_AUX], emulatable_abort: RmmRecEmulatableAbort,
67 owner: OnceCell<&'a Rd>,
73 vcpuid: usize,
74 runnable: bool,
75 psci_pending: bool,
76 state: State,
77 ripas: Ripas,
78 vtcr: u64,
79 host_call_pending: bool,
80}
81
82impl Rec<'_> {
83 pub fn new() -> Self {
84 Self {
85 context: Context::new(),
86 attest_state: RmmRecAttestState::NoAttestInProgress,
87 attest_challenge: [0; MAX_CHALLENGE_SIZE],
88 attest_token_offset: 0,
89 aux: [0; NR_AUX],
90 emulatable_abort: RmmRecEmulatableAbort::NotEmulatableAbort,
91 owner: OnceCell::new(),
92 vcpuid: 0,
93 runnable: false,
94 psci_pending: false,
95 state: State::Ready,
96 ripas: Ripas {
97 start: 0,
98 end: 0,
99 addr: 0,
100 state: 0,
101 flags: 0,
102 },
103 vtcr: 0,
104 host_call_pending: false,
105 }
106 }
107
108 pub fn init(
109 &mut self,
110 owner: usize,
111 vcpuid: usize,
112 flags: u64,
113 aux: [u64; NR_AUX],
114 vttbr: u64,
115 vmpidr: u64,
116 ) -> Result<(), Error> {
117 if owner == 0 {
118 error!("owner should be non-zero");
119 return Err(Error::RmiErrorInput);
120 }
121
122 if let Err(input_owner) = self.owner.set(unsafe { &*(owner as *const Rd) }) {
123 error!(
124 "Rec::init() called twice. cur owner: {:x}, input owner: {:x}",
125 self.get_owner()? as *const Rd as usize,
126 input_owner as *const Rd as usize
127 );
128 return Err(Error::RmiErrorRec);
129 }
130
131 self.vcpuid = vcpuid;
132 self.set_runnable(flags);
133 self.context.sys_regs.vttbr = vttbr;
134 self.context.sys_regs.vmpidr = vmpidr;
135 self.aux.copy_from_slice(&aux);
136 pauth::init_pauth(self);
137 pmu::init_pmu(self);
138 timer::init_timer(self);
139 gic::init_gic(self);
140 simd::init_simd(self)?;
141
142 Ok(())
143 }
144
145 pub fn attest_state(&self) -> RmmRecAttestState {
146 self.attest_state
147 }
148
149 pub fn attest_challenge(&self) -> &[u8] {
150 &self.attest_challenge
151 }
152
153 pub fn attest_token_offset(&self) -> usize {
154 self.attest_token_offset
155 }
156
157 pub fn aux(&self, index: usize) -> u64 {
158 self.aux[index]
159 }
160
161 pub fn emulatable_abort(&self) -> RmmRecEmulatableAbort {
162 self.emulatable_abort
163 }
164
165 pub fn runnable(&self) -> bool {
166 self.runnable
167 }
168
169 pub fn vcpuid(&self) -> usize {
170 self.vcpuid
171 }
172
173 fn get_owner(&self) -> Result<&Rd, Error> {
174 match self.owner.get() {
175 Some(owner) => Ok(owner),
176 None => {
177 #[cfg(kani)]
180 kani::assume(false);
181 Err(Error::RmiErrorRec)
182 }
183 }
184 }
185
186 pub fn owner(&self) -> Result<usize, Error> {
187 let owner = self.get_owner()?;
188 Ok(owner as *const Rd as usize)
189 }
190
191 pub fn host_call_pending(&self) -> bool {
192 self.host_call_pending
193 }
194
195 pub fn psci_pending(&self) -> bool {
196 self.psci_pending
197 }
198
199 pub fn set_attest_state(&mut self, state: RmmRecAttestState) {
200 self.attest_state = state;
201 }
202
203 pub fn set_attest_challenge(&mut self, challenge: &[u8]) {
204 self.attest_challenge.copy_from_slice(challenge);
205 }
206
207 pub fn set_attest_offset(&mut self, offset: usize) {
208 self.attest_token_offset = offset;
209 }
210
211 pub fn set_emulatable_abort(&mut self, val: RmmRecEmulatableAbort) {
212 self.emulatable_abort = val;
213 }
214
215 pub fn set_host_call_pending(&mut self, val: bool) {
216 self.host_call_pending = val;
217 }
218
219 pub fn set_psci_pending(&mut self, val: bool) {
220 self.psci_pending = val;
221 }
222
223 pub fn set_ripas(&mut self, start: u64, end: u64, state: u8, flags: u64) {
224 self.ripas.start = start;
225 self.ripas.end = end;
226 self.ripas.state = state;
227 self.ripas.flags = flags;
228 self.ripas.addr = start; }
230
231 pub fn set_vtcr(&mut self, vtcr: u64) {
232 self.vtcr = vtcr;
233 }
234
235 pub fn set_runnable(&mut self, flags: u64) {
237 const RUNNABLE_OFFSET: u64 = 1;
238 self.runnable = match flags & RUNNABLE_OFFSET {
239 0 => false,
240 _ => true,
241 }
242 }
243
244 pub fn set_state(&mut self, state: State) {
245 self.state = state;
246 }
247
248 pub fn get_state(&self) -> State {
249 self.state
250 }
251
252 pub fn set_ripas_addr(&mut self, addr: u64) {
253 self.ripas.addr = addr;
254 }
255
256 pub fn ripas_addr(&self) -> u64 {
257 self.ripas.addr
258 }
259
260 pub fn ripas_start(&self) -> u64 {
261 self.ripas.start
262 }
263
264 pub fn ripas_end(&self) -> u64 {
265 self.ripas.end
266 }
267
268 pub fn ripas_state(&self) -> u8 {
269 self.ripas.state
270 }
271
272 pub fn ripas_flags(&self) -> u64 {
273 self.ripas.flags
274 }
275
276 pub fn vtcr(&self) -> u64 {
277 self.vtcr
278 }
279
280 pub fn realmid(&self) -> Result<usize, Error> {
281 let owner = self.get_owner()?;
282 Ok(owner.id())
283 }
284
285 pub fn ipa_bits(&self) -> Result<usize, Error> {
286 let owner = self.get_owner()?;
287 Ok(owner.ipa_bits())
288 }
289
290 pub fn pmu_config(&self) -> Result<(bool, usize), Error> {
291 let owner = self.get_owner()?;
292 Ok(owner.pmu_config())
293 }
294
295 pub fn from_current(&mut self) {
296 unsafe {
297 Context::from_current(self);
298 }
299 }
300
301 pub fn into_current(&self) {
302 unsafe {
303 Context::into_current(self);
304 }
305 }
306
307 pub fn reset_ctx(&mut self) {
308 self.context.spsr_el2 = (SPSR_EL2::D.mask << SPSR_EL2::D.shift)
309 | (SPSR_EL2::A.mask << SPSR_EL2::A.shift)
310 | (SPSR_EL2::I.mask << SPSR_EL2::I.shift)
311 | (SPSR_EL2::F.mask << SPSR_EL2::F.shift)
312 | (SPSR_EL2::M.mask & u64::from(SPSR_EL2::M::EL1h)) << SPSR_EL2::M.shift;
313
314 self.context.sys_regs.sctlr = 0;
315 }
316}
317
318impl Content for Rec<'_> {}
319
320impl safe_abstraction::raw_ptr::RawPtr for Rec<'_> {}
321
322impl safe_abstraction::raw_ptr::SafetyChecked for Rec<'_> {}
323
324impl safe_abstraction::raw_ptr::SafetyAssured for Rec<'_> {
325 fn is_initialized(&self) -> bool {
326 true
330 }
331
332 fn verify_ownership(&self) -> bool {
333 true
343 }
344}
345
346unsafe fn current() -> Option<&'static mut Rec<'static>> {
348 match TPIDR_EL2.get() {
349 0 => None,
350 current => Some(&mut *(current as *mut Rec<'_>)),
351 }
352}
353
354fn enter() -> [usize; 4] {
355 unsafe {
356 if let Some(_rec) = current() {
357 return rmm_exit([0; 4]);
359 }
360 [0, 0, 0, 0]
361 }
362}
363
364fn exit() {
365 unsafe {
366 if let Some(rec) = current() {
367 rec.from_current();
368 }
369 }
370}
371
372pub fn run_prepare(rd: &Rd, vcpu: usize, rec: &mut Rec<'_>, incr_pc: usize) -> Result<(), Error> {
374 if incr_pc == 1 {
375 rec.context.elr_el2 += 4;
376 }
377 timer::update_timer_assertion(rec);
378 debug!("resuming: {:#x}", rec.context.elr_el2);
379 rec.into_current();
380
381 trace!("Switched to VCPU {} on Realm {}", vcpu, rd.id());
382 Ok(())
383}
384
385pub fn run() -> Result<[usize; 4], Error> {
386 let ret = enter();
387
388 exit();
389 Ok(ret)
390}
391
392pub fn max_recs_order() -> usize {
393 MAX_RECS_ORDER_VALUE as usize
394}
395
396pub fn save_host_state(rec: &Rec<'_>) {
400 pmu::save_host_state(rec);
401 timer::save_host_state(rec);
405}
406
407pub fn restore_host_state(rec: &Rec<'_>) {
408 pmu::restore_host_state(rec);
409 timer::restore_host_state(rec);
410}