Skip to main content

islet_rmm/rmi/rec/
run.rs

1use armv9a::{define_bitfield, define_bits, define_mask};
2
3use crate::const_assert_eq;
4use crate::granule::GRANULE_SIZE;
5use crate::rmi::error::Error;
6use crate::rmi::{PMU_OVERFLOW_ACTIVE, PMU_OVERFLOW_NOT_ACTIVE};
7
8use autopadding::*;
9
10/// The structure holds data passsed between the Host and the RMM
11/// on Realm Execution Context (REC) entry and exit.
12#[repr(C)]
13#[derive(Default, Copy, Clone)]
14pub struct Run {
15    entry: Entry,
16    exit: Exit,
17}
18const_assert_eq!(core::mem::size_of::<Run>(), GRANULE_SIZE);
19
20pad_struct_and_impl_default!(
21struct Entry {
22    0x0   flags: u64,
23    0x200 gprs: [u64; NR_GPRS],
24    0x300 gicv3_hcr: u64,
25    0x308 gicv3_lrs: [u64; NR_GIC_LRS],
26    0x800 => @END,
27}
28);
29
30pad_struct_and_impl_default!(
31struct Exit {
32    0x0   exit_reason: u8,
33    0x100 esr: u64,
34    0x108 far: u64,
35    0x110 hpfar: u64,
36    0x200 gprs: [u64; NR_GPRS],
37    0x300 gicv3_hcr: u64,
38    0x308 gicv3_lrs: [u64; NR_GIC_LRS],
39    0x388 gicv3_misr: u64,
40    0x390 gicv3_vmcr: u64,
41    0x400 cntp_ctl: u64,
42    0x408 cntp_cval: u64,
43    0x410 cntv_ctl: u64,
44    0x418 cntv_cval: u64,
45    0x500 ripas_base: u64,
46    0x508 ripas_top: u64,
47    0x510 ripas_value: u8,
48    0x600 imm: u16,
49    0x700 pmu_ovf: u8,
50    0x800 => @END,
51}
52);
53
54impl Run {
55    pub fn entry_flags(&self) -> EntryFlag {
56        EntryFlag::new(self.entry.flags)
57    }
58
59    pub fn entry_gpr(&self, idx: usize) -> Result<u64, Error> {
60        if idx >= NR_GPRS {
61            error!("out of index: {}", idx);
62            return Err(Error::RmiErrorInput);
63        }
64        Ok(self.entry.gprs[idx])
65    }
66
67    pub fn entry_gic_lrs(&self) -> &[u64; 16] {
68        &self.entry.gicv3_lrs
69    }
70
71    pub fn entry_gic_hcr(&self) -> u64 {
72        self.entry.gicv3_hcr
73    }
74
75    pub fn exit_gic_lrs_mut(&mut self) -> &mut [u64; 16] {
76        &mut self.exit.gicv3_lrs
77    }
78
79    pub fn set_imm(&mut self, imm: u16) {
80        self.exit.imm = imm;
81    }
82
83    pub fn set_exit_reason(&mut self, exit_reason: u8) {
84        self.exit.exit_reason = exit_reason;
85    }
86
87    pub fn set_esr(&mut self, esr: u64) {
88        self.exit.esr = esr;
89    }
90
91    pub fn set_far(&mut self, far: u64) {
92        self.exit.far = far;
93    }
94
95    pub fn set_hpfar(&mut self, hpfar: u64) {
96        self.exit.hpfar = hpfar;
97    }
98
99    pub fn set_gpr(&mut self, idx: usize, val: u64) -> Result<(), Error> {
100        if idx >= NR_GPRS {
101            error!("out of index: {}", idx);
102            return Err(Error::RmiErrorInput);
103        }
104        self.exit.gprs[idx] = val;
105        Ok(())
106    }
107
108    pub fn set_ripas(&mut self, base: u64, top: u64, state: u8) {
109        self.exit.ripas_base = base;
110        self.exit.ripas_top = top;
111        self.exit.ripas_value = state;
112    }
113
114    pub fn set_gic_lrs(&mut self, src: &[u64], len: usize) {
115        self.exit.gicv3_lrs.copy_from_slice(&src[..len])
116    }
117
118    pub fn set_gic_misr(&mut self, val: u64) {
119        self.exit.gicv3_misr = val;
120    }
121
122    pub fn set_gic_vmcr(&mut self, val: u64) {
123        self.exit.gicv3_vmcr = val;
124    }
125
126    pub fn set_gic_hcr(&mut self, val: u64) {
127        self.exit.gicv3_hcr = val;
128    }
129
130    pub fn set_cntv_ctl(&mut self, val: u64) {
131        self.exit.cntv_ctl = val;
132    }
133
134    pub fn set_cntv_cval(&mut self, val: u64) {
135        self.exit.cntv_cval = val;
136    }
137
138    pub fn set_cntp_ctl(&mut self, val: u64) {
139        self.exit.cntp_ctl = val;
140    }
141
142    pub fn set_cntp_cval(&mut self, val: u64) {
143        self.exit.cntp_cval = val;
144    }
145
146    pub fn set_pmu_overflow(&mut self, val: bool) {
147        if val {
148            self.exit.pmu_ovf = PMU_OVERFLOW_ACTIVE;
149        } else {
150            self.exit.pmu_ovf = PMU_OVERFLOW_NOT_ACTIVE;
151        }
152    }
153
154    pub fn exit_reason(&self) -> u8 {
155        self.exit.exit_reason
156    }
157
158    pub fn gpr(&self, idx: usize) -> Result<u64, Error> {
159        if idx >= NR_GPRS {
160            error!("out of index: {}", idx);
161            return Err(Error::RmiErrorInput);
162        }
163        Ok(self.exit.gprs[idx])
164    }
165
166    pub fn ripas(&self) -> (u64, u64) {
167        (self.exit.ripas_base, self.exit.ripas_top)
168    }
169}
170
171#[cfg(fuzzing)]
172impl Run {
173    pub fn set_entry_flags(&mut self, flags: u64) {
174        self.entry.flags = flags;
175    }
176
177    pub fn set_entry_gpr(&mut self, idx: usize, val: u64) -> Result<(), Error> {
178        if idx >= NR_GPRS {
179            error!("out of index: {}", idx);
180            return Err(Error::RmiErrorInput);
181        }
182        self.entry.gprs[idx] = val;
183        Ok(())
184    }
185
186    pub fn set_entry_gic_hcr(&mut self, val: u64) {
187        self.entry.gicv3_hcr = val;
188    }
189
190    pub fn set_entry_gic_lrs(&mut self, src: &[u64], len: usize) {
191        self.entry.gicv3_lrs.copy_from_slice(&src[..len])
192    }
193}
194
195impl core::fmt::Debug for Run {
196    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
197        f.debug_struct("rec::Run")
198            .field("entry::flags", &format_args!("{:#X}", &self.entry.flags))
199            .field("entry::gprs", &self.entry.gprs)
200            .field(
201                "entry::gicv3_hcr",
202                &format_args!("{:#X}", &self.entry.gicv3_hcr),
203            )
204            .field("entry::gicv3_lrs", &self.entry.gicv3_lrs)
205            .field("exit::exit_reason", &self.exit.exit_reason)
206            .field("exit::imm", &self.exit.imm)
207            .field("exit::cntp_ctl", &self.exit.cntp_ctl)
208            .field("exit::cntp_cval", &self.exit.cntp_cval)
209            .field("exit::cntv_ctl", &self.exit.cntv_ctl)
210            .field("exit::cntv_cval", &self.exit.cntv_cval)
211            .field("exit::gpr0", &self.exit.gprs[0])
212            .finish()
213    }
214}
215
216// EntryFlag corresponds to the RmiRecEnterFlags fieldset in the spec document,
217// containing flags provided by the Host during REC entry.
218define_bits!(
219    EntryFlag,
220    // RIPAS_RESPONSE: Host response to RIPAS change request.
221    // val 0: Host accepted the Realm request.
222    // val 1: Host rejected the Realm request.
223    RIPAS_RESPONSE[4 - 4],
224    // TRAP_WFE: Whether to trap WFE execution by the Realm.
225    //  val 0: Trap is disabled.
226    //  val 1: Trap is enabled.
227    TRAP_WFE[3 - 3],
228    // TRAP_WFI: Whether to trap WFI execution by the Realm.
229    //  val 0: Trap is disabled.
230    //  val 1: Trap is enabled.
231    TRAP_WFI[2 - 2],
232    // INJECT_SEA: Whether to inject a Synchronous External Abort (SEA) into the Realm.
233    //  val 0: Do not inject an SEA into the Realm.
234    //  val 1: Inject an SEA into the Realm.
235    INJECT_SEA[1 - 1],
236    // EMUL_MMIO: Whether the host has completed emulation for an Emulatable Data Abort.
237    //  val 0: Host has not completed emulation for an Emulatable Abort.
238    //  val 1: Host has completed emulation for an Emulatable Abort.
239    EMUL_MMIO[0 - 0]
240);
241
242pub const NR_GPRS: usize = 31;
243pub const NR_GIC_LRS: usize = 16;
244
245impl Run {
246    pub fn verify_compliance(&self) -> Result<(), Error> {
247        const ICH_LR_HW_OFFSET: usize = 61;
248        // A6.1 Realm interrupts, HW == '0'
249        for lr in &self.entry.gicv3_lrs {
250            if lr & (1 << ICH_LR_HW_OFFSET) != 0 {
251                return Err(Error::RmiErrorRec);
252            }
253        }
254        Ok(())
255    }
256}
257
258impl safe_abstraction::raw_ptr::RawPtr for Run {}
259
260impl safe_abstraction::raw_ptr::SafetyChecked for Run {}
261
262impl safe_abstraction::raw_ptr::SafetyAssured for Run {
263    fn is_initialized(&self) -> bool {
264        // Returns `true` to maintain safety at the level preserved by the existing approach.
265        // TODO: It is crucial to re-evaluate whether this aspect could potentially
266        // lead to malfunctions related to RMM's memory safety.
267        true
268    }
269
270    fn verify_ownership(&self) -> bool {
271        // Returns `true` to maintain safety at the level preserved by the existing approach.
272        // TODO: It is crucial to re-evaluate whether this aspect could potentially
273        // lead to malfunctions related to RMM's memory safety.
274        true
275    }
276}