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#[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
216define_bits!(
219 EntryFlag,
220 RIPAS_RESPONSE[4 - 4],
224 TRAP_WFE[3 - 3],
228 TRAP_WFI[2 - 2],
232 INJECT_SEA[1 - 1],
236 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 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 true
268 }
269
270 fn verify_ownership(&self) -> bool {
271 true
275 }
276}