1#[cfg(feature = "el1")]
7use crate::{
8 ClidrEl1, CsselrEl1, EsrEl1, IdAa64dfr0El1, IdAa64dfr1El1, IdAa64mmfr0El1, IdAa64mmfr1El1,
9 IdAa64mmfr2El1, IdAa64mmfr3El1, IdAa64pfr0El1, IdAa64pfr1El1, MpidrEl1, SpsrEl1,
10 read_mpidr_el1,
11};
12#[cfg(feature = "el2")]
13use crate::{EsrEl2, SpsrEl2};
14#[cfg(feature = "el3")]
15use crate::{EsrEl3, MdcrEl3, SmcrEl3, SpsrEl3};
16#[cfg(feature = "el1")]
17use core::fmt::{self, Debug, Formatter};
18use num_enum::TryFromPrimitive;
19
20#[cfg(feature = "el1")]
21impl ClidrEl1 {
22 pub fn icb_level(self) -> Option<CacheLevel> {
24 let icb = self.icb();
25 if icb != 0 {
26 Some(CacheLevel(icb as u8))
27 } else {
28 None
29 }
30 }
31
32 pub fn cache_type(self, level: CacheLevel) -> CacheType {
34 self.ctype(level.level().into()).try_into().unwrap()
35 }
36}
37
38#[cfg(feature = "el1")]
39impl CsselrEl1 {
40 pub fn new(tnd: bool, level: CacheLevel, ind: bool) -> Self {
42 let mut instance = Self::from_bits_retain(u64::from(level) << 1);
43
44 if ind {
45 instance |= Self::IND;
46 } else if tnd {
47 instance |= Self::TND;
49 }
50
51 instance
52 }
53
54 pub fn cache_level(self) -> CacheLevel {
56 CacheLevel(self.level() + 1)
57 }
58}
59
60#[cfg(feature = "el1")]
61impl EsrEl1 {
62 pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
64}
65
66#[cfg(feature = "el1")]
67impl Debug for EsrEl1 {
68 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
69 write!(f, "EsrEl1({:#x})", self.0)
70 }
71}
72
73#[cfg(feature = "el2")]
74impl EsrEl2 {
75 pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
77}
78
79#[cfg(feature = "el2")]
80impl Debug for EsrEl2 {
81 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
82 write!(f, "EsrEl2({:#x})", self.0)
83 }
84}
85
86#[cfg(feature = "el3")]
87impl EsrEl3 {
88 pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
90}
91
92#[cfg(feature = "el3")]
93impl Debug for EsrEl3 {
94 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
95 write!(f, "EsrEl3({:#x})", self.0)
96 }
97}
98
99#[cfg(feature = "el1")]
100impl IdAa64dfr0El1 {
101 const SYS_REG_TRACE_SUPPORTED: u8 = 1;
102 const SPE_SUPPORTED: u8 = 1;
103 const TRF_SUPPORTED: u8 = 1;
104 const TRBE_NOT_SUPPORTED: u8 = 0;
105 const MTPMU_SUPPORTED: u8 = 1;
106
107 pub fn is_feat_sys_reg_trace_present(self) -> bool {
110 self.tracever() == Self::SYS_REG_TRACE_SUPPORTED
111 }
112
113 pub fn is_feat_spe_present(self) -> bool {
115 self.pmsver() >= Self::SPE_SUPPORTED
116 }
117
118 pub fn is_feat_trf_present(self) -> bool {
120 self.tracefilt() == Self::TRF_SUPPORTED
121 }
122
123 pub fn is_feat_trbe_present(self) -> bool {
125 self.tracebuffer() != Self::TRBE_NOT_SUPPORTED
126 }
127
128 pub fn is_feat_mtpmu_present(self) -> bool {
130 self.mtpmu() == Self::MTPMU_SUPPORTED
131 }
132}
133
134#[cfg(feature = "el1")]
135impl IdAa64dfr1El1 {
136 const EBEP_IMPLEMENTED: u8 = 0b1;
137
138 pub fn is_feat_ebep_present(self) -> bool {
140 self.ebep() == Self::EBEP_IMPLEMENTED
141 }
142}
143
144#[cfg(feature = "el1")]
145impl IdAa64mmfr0El1 {
146 const FGT_SUPPORTED: u8 = 0b0001;
147 const FGT2_SUPPORTED: u8 = 0b0001;
148
149 pub fn is_feat_fgt_present(self) -> bool {
151 let val = self.fgt();
152 val == Self::FGT_SUPPORTED || val == Self::FGT2_SUPPORTED
153 }
154
155 pub fn is_feat_fgt2_present(self) -> bool {
157 self.fgt() == Self::FGT2_SUPPORTED
158 }
159}
160
161#[cfg(feature = "el1")]
162impl IdAa64mmfr1El1 {
163 const VH_SUPPORTED: u8 = 0b0001;
164 const HCX_SUPPORTED: u8 = 0b0001;
165
166 pub fn is_feat_vhe_present(self) -> bool {
168 self.vh() >= Self::VH_SUPPORTED
169 }
170
171 pub fn is_feat_hcx_present(self) -> bool {
173 self.hcx() >= Self::HCX_SUPPORTED
174 }
175}
176
177#[cfg(feature = "el1")]
178impl IdAa64mmfr2El1 {
179 const CCIDX_64_BIT: u8 = 0b0001;
180
181 pub fn has_64_bit_ccsidr_el1(self) -> bool {
183 self.ccidx() == Self::CCIDX_64_BIT
184 }
185}
186
187#[cfg(feature = "el1")]
188impl IdAa64mmfr3El1 {
189 const TCRX_SUPPORTED: u8 = 1;
190
191 pub fn is_feat_tcr2_present(self) -> bool {
193 self.tcrx() >= Self::TCRX_SUPPORTED
194 }
195}
196
197#[cfg(feature = "el1")]
198impl IdAa64pfr0El1 {
199 const SVE_SUPPORTED: u8 = 1;
200 const MPAM_SUPPORTED: u8 = 1;
201
202 pub fn is_feat_sve_present(self) -> bool {
204 self.sve() == Self::SVE_SUPPORTED
205 }
206
207 pub fn is_feat_mpam_present(self) -> bool {
209 self.mpam() == Self::MPAM_SUPPORTED
210 }
211}
212
213#[cfg(feature = "el1")]
214impl IdAa64pfr1El1 {
215 const SSBS_IMPLEMENTED: u8 = 0b1;
216 const MTE_IMPLEMENTED: u8 = 0b0001;
217 const MTE2_IMPLEMENTED: u8 = 0b0010;
218 const SME_IMPLEMENTED: u8 = 0b0001;
219 const SME2_IMPLEMENTED: u8 = 0b0010;
220 const NMI_IMPLEMENTED: u8 = 0b1;
221 const GCS_IMPLEMENTED: u8 = 0b1;
222
223 pub fn is_feat_ssbs_present(self) -> bool {
225 self.ssbs() >= Self::SSBS_IMPLEMENTED
226 }
227
228 pub fn is_feat_mte_present(self) -> bool {
230 self.mte() >= Self::MTE_IMPLEMENTED
231 }
232
233 pub fn is_feat_mte2_present(self) -> bool {
235 self.mte() >= Self::MTE2_IMPLEMENTED
236 }
237
238 pub fn is_feat_sme_present(self) -> bool {
240 self.sme() >= Self::SME_IMPLEMENTED
241 }
242
243 pub fn is_feat_sme2_present(self) -> bool {
245 self.sme() >= Self::SME2_IMPLEMENTED
246 }
247
248 pub fn is_feat_nmi_present(self) -> bool {
250 self.nmi() == Self::NMI_IMPLEMENTED
251 }
252
253 pub fn is_feat_gcs_present(self) -> bool {
255 self.gcs() == Self::GCS_IMPLEMENTED
256 }
257}
258
259#[cfg(feature = "el3")]
260impl MdcrEl3 {
261 pub const SPD32: Self = Self::from_bits_retain(0b10 << 14);
263 pub const NSPB_NS: Self = Self::from_bits_retain(0b11 << 12);
266 pub const NSTB_EN: Self = Self::from_bits_retain(1 << 24);
268 pub const NSTB_SS: Self = Self::from_bits_retain(1 << 25);
270}
271
272#[cfg(feature = "el1")]
273impl MpidrEl1 {
274 pub const AFFINITY_BITS: usize = 8;
276
277 pub fn from_psci_mpidr(psci_mpidr: u64) -> Self {
285 let mpidr_el1 = read_mpidr_el1();
286 Self::from_bits_retain(psci_mpidr) | (mpidr_el1 & (Self::MT | Self::U))
287 }
288}
289
290#[cfg(feature = "el3")]
291impl SmcrEl3 {
292 pub fn from_ssve_vector_len(vector_length: u64) -> Self {
294 Self::from_bits_retain(((vector_length - 1) / 128) & Self::LEN_MASK)
295 }
296}
297
298#[cfg(feature = "el1")]
299impl SpsrEl1 {
300 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
302}
303
304#[cfg(feature = "el2")]
305impl SpsrEl2 {
306 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
308}
309
310#[cfg(feature = "el3")]
311impl SpsrEl3 {
312 pub const M_AARCH64_EL0: Self = Self::from_bits_retain(0b00000);
314 pub const M_AARCH64_EL1T: Self = Self::from_bits_retain(0b00100);
316 pub const M_AARCH64_EL1H: Self = Self::from_bits_retain(0b00101);
318 pub const M_AARCH64_EL2T: Self = Self::from_bits_retain(0b01000);
320 pub const M_AARCH64_EL2H: Self = Self::from_bits_retain(0b01001);
322 pub const M_AARCH64_EL3T: Self = Self::from_bits_retain(0b01100);
324 pub const M_AARCH64_EL3H: Self = Self::from_bits_retain(0b01101);
326
327 pub const SP_EL0: Self = Self::from_bits_retain(0);
329 pub const SP_ELX: Self = Self::from_bits_retain(1);
331
332 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
334
335 pub const SSBS: Self = Self::from_bits_retain(1 << 12);
337
338 const EL_MASK: u64 = 0x3;
339 const EL_SHIFT: usize = 2;
340 const SP_MASK: u64 = 0x1;
341
342 pub const fn exception_level(self) -> ExceptionLevel {
344 match (self.bits() >> Self::EL_SHIFT) & Self::EL_MASK {
345 0 => ExceptionLevel::El0,
346 1 => ExceptionLevel::El1,
347 2 => ExceptionLevel::El2,
348 3 => ExceptionLevel::El3,
349 _ => unreachable!(),
350 }
351 }
352
353 pub const fn stack_pointer(self) -> StackPointer {
355 match self.bits() & Self::SP_MASK {
356 0 => StackPointer::El0,
357 1 => StackPointer::ElX,
358 _ => unreachable!(),
359 }
360 }
361}
362
363#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
365#[repr(u8)]
366pub enum CacheType {
367 NoCache = 0b000,
369 InstructionOnly = 0b001,
371 DataOnly = 0b010,
373 SeparateInstructionAndData = 0b011,
375 Unified = 0b100,
377}
378
379#[derive(Clone, Copy, Debug, Eq, PartialEq)]
381pub struct CacheLevel(pub(crate) u8);
382
383impl CacheLevel {
384 pub fn new(level: u8) -> Self {
386 assert!((1..8).contains(&level));
387 Self(level)
388 }
389
390 pub fn level(&self) -> u8 {
392 self.0
393 }
394}
395
396impl From<CacheLevel> for u32 {
397 fn from(value: CacheLevel) -> Self {
398 (value.0 - 1).into()
399 }
400}
401
402impl From<CacheLevel> for u64 {
403 fn from(value: CacheLevel) -> Self {
404 u32::from(value).into()
405 }
406}
407
408#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive)]
410#[repr(u8)]
411pub enum ExceptionLevel {
412 El0 = 0,
414 El1 = 1,
416 El2 = 2,
418 El3 = 3,
420}
421
422#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive)]
424#[repr(u8)]
425pub enum StackPointer {
426 El0 = 0,
428 ElX = 1,
430}
431
432#[cfg(test)]
433mod tests {
434 #[cfg(feature = "el1")]
435 use super::*;
436
437 #[test]
438 #[cfg(feature = "el1")]
439 fn debug_mpidr_el1() {
440 assert_eq!(format!("{:?}", MpidrEl1::empty()), "MpidrEl1(0x0)");
441 assert_eq!(
442 format!("{:?}", MpidrEl1::MT | MpidrEl1::U),
443 "MpidrEl1(MT | U)"
444 );
445 assert_eq!(
446 format!("{:?}", MpidrEl1::from_bits_retain(0x12_4134_5678)),
447 "MpidrEl1(MT | U | 0x1200345678)"
448 );
449 }
450
451 #[cfg(feature = "el1")]
452 #[test]
453 fn debug_spsr_el1() {
454 assert_eq!(format!("{:?}", SpsrEl1::empty()), "SpsrEl1(0x0)");
455 assert_eq!(format!("{:?}", SpsrEl1::NZCV), "SpsrEl1(V | C | Z | N)");
456 }
457
458 #[cfg(feature = "el2")]
459 #[test]
460 fn debug_spsr_el2() {
461 assert_eq!(format!("{:?}", SpsrEl2::empty()), "SpsrEl2(0x0)");
462 assert_eq!(format!("{:?}", SpsrEl2::NZCV), "SpsrEl2(V | C | Z | N)");
463 }
464
465 #[cfg(feature = "el3")]
466 #[test]
467 fn debug_spsr_el3() {
468 assert_eq!(format!("{:?}", SpsrEl3::empty()), "SpsrEl3(0x0)");
469 assert_eq!(format!("{:?}", SpsrEl3::NZCV), "SpsrEl3(V | C | Z | N)");
470 assert_eq!(format!("{:?}", SpsrEl3::M_AARCH64_EL3H), "SpsrEl3(0xd)");
471 }
472
473 #[cfg(feature = "el1")]
474 #[test]
475 fn debug_esr_el1() {
476 assert_eq!(format!("{:?}", EsrEl1::empty()), "EsrEl1(0x0)");
477 assert_eq!(format!("{:?}", EsrEl1::IL), "EsrEl1(0x2000000)");
478 assert_eq!(
479 format!("{:?}", EsrEl1::ISS_SYSREG_OPCODE_MASK),
480 "EsrEl1(0x3ffc1e)"
481 );
482 }
483
484 #[cfg(feature = "el2")]
485 #[test]
486 fn debug_esr_el2() {
487 assert_eq!(format!("{:?}", EsrEl2::empty()), "EsrEl2(0x0)");
488 assert_eq!(format!("{:?}", EsrEl2::IL), "EsrEl2(0x2000000)");
489 assert_eq!(
490 format!("{:?}", EsrEl2::ISS_SYSREG_OPCODE_MASK),
491 "EsrEl2(0x3ffc1e)"
492 );
493 }
494
495 #[cfg(feature = "el3")]
496 #[test]
497 fn debug_esr_el3() {
498 assert_eq!(format!("{:?}", EsrEl3::empty()), "EsrEl3(0x0)");
499 assert_eq!(format!("{:?}", EsrEl3::IL), "EsrEl3(0x2000000)");
500 assert_eq!(
501 format!("{:?}", EsrEl3::ISS_SYSREG_OPCODE_MASK),
502 "EsrEl3(0x3ffc1e)"
503 );
504 }
505}