1#[cfg(all(any(test, feature = "fakes", target_arch = "aarch64"), feature = "el1"))]
7use crate::read_mpidr_el1;
8#[cfg(feature = "el1")]
9use crate::{
10 ClidrEl1, CsselrEl1, EsrEl1, IdAa64dfr0El1, IdAa64dfr1El1, IdAa64mmfr0El1, IdAa64mmfr1El1,
11 IdAa64mmfr2El1, IdAa64mmfr3El1, IdAa64pfr0El1, IdAa64pfr1El1, MpidrEl1, SpsrEl1,
12};
13#[cfg(feature = "el2")]
14use crate::{EsrEl2, SpsrEl2};
15#[cfg(feature = "el3")]
16use crate::{EsrEl3, MdcrEl3, SmcrEl3, SpsrEl3};
17#[cfg(feature = "el1")]
18use core::fmt::{self, Debug, Formatter};
19use num_enum::{IntoPrimitive, TryFromPrimitive};
20
21#[cfg(feature = "el1")]
22impl ClidrEl1 {
23 pub fn icb_level(self) -> Option<CacheLevel> {
25 let icb = self.icb();
26 if icb != 0 {
27 Some(CacheLevel(icb as u8))
28 } else {
29 None
30 }
31 }
32
33 pub fn cache_type(self, level: CacheLevel) -> CacheType {
35 self.ctype(level.level().into()).try_into().unwrap()
36 }
37}
38
39#[cfg(feature = "el1")]
40impl CsselrEl1 {
41 pub fn new(tnd: bool, level: CacheLevel, ind: bool) -> Self {
43 let mut instance = Self::from_bits_retain(u64::from(level) << 1);
44
45 if ind {
46 instance |= Self::IND;
47 } else if tnd {
48 instance |= Self::TND;
50 }
51
52 instance
53 }
54
55 pub fn cache_level(self) -> CacheLevel {
57 CacheLevel(self.level() + 1)
58 }
59}
60
61#[cfg(feature = "el1")]
62impl EsrEl1 {
63 pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
65}
66
67#[cfg(feature = "el1")]
68impl Debug for EsrEl1 {
69 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
70 write!(f, "EsrEl1({:#x})", self.0)
71 }
72}
73
74#[cfg(feature = "el2")]
75impl EsrEl2 {
76 pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
78}
79
80#[cfg(feature = "el2")]
81impl Debug for EsrEl2 {
82 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
83 write!(f, "EsrEl2({:#x})", self.0)
84 }
85}
86
87#[cfg(feature = "el3")]
88impl EsrEl3 {
89 pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
91}
92
93#[cfg(feature = "el3")]
94impl Debug for EsrEl3 {
95 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
96 write!(f, "EsrEl3({:#x})", self.0)
97 }
98}
99
100#[cfg(feature = "el1")]
101impl IdAa64dfr0El1 {
102 const SYS_REG_TRACE_SUPPORTED: u8 = 1;
103 const SPE_SUPPORTED: u8 = 1;
104 const TRF_SUPPORTED: u8 = 1;
105 const TRBE_NOT_SUPPORTED: u8 = 0;
106 const MTPMU_SUPPORTED: u8 = 1;
107
108 pub fn is_feat_sys_reg_trace_present(self) -> bool {
111 self.tracever() == Self::SYS_REG_TRACE_SUPPORTED
112 }
113
114 pub fn is_feat_spe_present(self) -> bool {
116 self.pmsver() >= Self::SPE_SUPPORTED
117 }
118
119 pub fn is_feat_trf_present(self) -> bool {
121 self.tracefilt() == Self::TRF_SUPPORTED
122 }
123
124 pub fn is_feat_trbe_present(self) -> bool {
126 self.tracebuffer() != Self::TRBE_NOT_SUPPORTED
127 }
128
129 pub fn is_feat_mtpmu_present(self) -> bool {
131 self.mtpmu() == Self::MTPMU_SUPPORTED
132 }
133}
134
135#[cfg(feature = "el1")]
136impl IdAa64dfr1El1 {
137 const EBEP_IMPLEMENTED: u8 = 0b1;
138
139 pub fn is_feat_ebep_present(self) -> bool {
141 self.ebep() == Self::EBEP_IMPLEMENTED
142 }
143}
144
145#[cfg(feature = "el1")]
146impl IdAa64mmfr0El1 {
147 const FGT_SUPPORTED: u8 = 0b0001;
148 const FGT2_SUPPORTED: u8 = 0b0010;
149
150 pub fn is_feat_fgt_present(self) -> bool {
152 let val = self.fgt();
153 val == Self::FGT_SUPPORTED || val == Self::FGT2_SUPPORTED
154 }
155
156 pub fn is_feat_fgt2_present(self) -> bool {
158 self.fgt() == Self::FGT2_SUPPORTED
159 }
160}
161
162#[cfg(feature = "el1")]
163impl IdAa64mmfr1El1 {
164 const VH_SUPPORTED: u8 = 0b0001;
165 const HCX_SUPPORTED: u8 = 0b0001;
166
167 pub fn is_feat_vhe_present(self) -> bool {
169 self.vh() >= Self::VH_SUPPORTED
170 }
171
172 pub fn is_feat_hcx_present(self) -> bool {
174 self.hcx() >= Self::HCX_SUPPORTED
175 }
176}
177
178#[cfg(feature = "el1")]
179impl IdAa64mmfr2El1 {
180 const CCIDX_64_BIT: u8 = 0b0001;
181
182 pub fn has_64_bit_ccsidr_el1(self) -> bool {
184 self.ccidx() == Self::CCIDX_64_BIT
185 }
186}
187
188#[cfg(feature = "el1")]
189impl IdAa64mmfr3El1 {
190 const TCRX_SUPPORTED: u8 = 1;
191
192 pub fn is_feat_tcr2_present(self) -> bool {
194 self.tcrx() >= Self::TCRX_SUPPORTED
195 }
196}
197
198#[cfg(feature = "el1")]
199impl IdAa64pfr0El1 {
200 const SVE_SUPPORTED: u8 = 1;
201 const MPAM_SUPPORTED: u8 = 1;
202 const AMU_SUPPORTED: u8 = 1;
203
204 pub fn is_feat_sve_present(self) -> bool {
206 self.sve() == Self::SVE_SUPPORTED
207 }
208
209 pub fn is_feat_mpam_present(self) -> bool {
211 self.mpam() == Self::MPAM_SUPPORTED
212 }
213
214 pub fn is_feat_amu_present(self) -> bool {
216 self.amu() >= Self::AMU_SUPPORTED
217 }
218}
219
220#[cfg(feature = "el1")]
221impl IdAa64pfr1El1 {
222 const SSBS_IMPLEMENTED: u8 = 0b1;
223 const MTE_IMPLEMENTED: u8 = 0b0001;
224 const MTE2_IMPLEMENTED: u8 = 0b0010;
225 const SME_IMPLEMENTED: u8 = 0b0001;
226 const SME2_IMPLEMENTED: u8 = 0b0010;
227 const NMI_IMPLEMENTED: u8 = 0b1;
228 const GCS_IMPLEMENTED: u8 = 0b1;
229
230 pub fn is_feat_ssbs_present(self) -> bool {
232 self.ssbs() >= Self::SSBS_IMPLEMENTED
233 }
234
235 pub fn is_feat_mte_present(self) -> bool {
237 self.mte() >= Self::MTE_IMPLEMENTED
238 }
239
240 pub fn is_feat_mte2_present(self) -> bool {
242 self.mte() >= Self::MTE2_IMPLEMENTED
243 }
244
245 pub fn is_feat_sme_present(self) -> bool {
247 self.sme() >= Self::SME_IMPLEMENTED
248 }
249
250 pub fn is_feat_sme2_present(self) -> bool {
252 self.sme() >= Self::SME2_IMPLEMENTED
253 }
254
255 pub fn is_feat_nmi_present(self) -> bool {
257 self.nmi() == Self::NMI_IMPLEMENTED
258 }
259
260 pub fn is_feat_gcs_present(self) -> bool {
262 self.gcs() == Self::GCS_IMPLEMENTED
263 }
264}
265
266#[cfg(feature = "el3")]
267impl MdcrEl3 {
268 pub const SPD32: Self = Self::from_bits_retain(0b10 << 14);
270 pub const NSPB_NS: Self = Self::from_bits_retain(0b11 << 12);
273 pub const NSTB_EN: Self = Self::from_bits_retain(1 << 24);
275 pub const NSTB_SS: Self = Self::from_bits_retain(1 << 25);
277}
278
279#[cfg(feature = "el1")]
280impl MpidrEl1 {
281 pub const AFFINITY_BITS: usize = 8;
283
284 #[cfg(any(test, feature = "fakes", target_arch = "aarch64"))]
292 pub fn from_psci_mpidr(psci_mpidr: u64) -> Self {
293 let mpidr_el1 = read_mpidr_el1();
294 Self::from_bits_retain(psci_mpidr) | (mpidr_el1 & (Self::MT | Self::U))
295 }
296}
297
298#[cfg(feature = "el3")]
299impl SmcrEl3 {
300 pub fn from_ssve_vector_len(vector_length: u64) -> Self {
302 Self::from_bits_retain(((vector_length - 1) / 128) & Self::LEN_MASK)
303 }
304}
305
306#[cfg(feature = "el1")]
307impl SpsrEl1 {
308 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
310}
311
312#[cfg(feature = "el2")]
313impl SpsrEl2 {
314 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
316}
317
318#[cfg(feature = "el3")]
319impl SpsrEl3 {
320 pub const M_AARCH64_EL0: Self = Self::from_bits_retain(0b00000);
322 pub const M_AARCH64_EL1T: Self = Self::from_bits_retain(0b00100);
324 pub const M_AARCH64_EL1H: Self = Self::from_bits_retain(0b00101);
326 pub const M_AARCH64_EL2T: Self = Self::from_bits_retain(0b01000);
328 pub const M_AARCH64_EL2H: Self = Self::from_bits_retain(0b01001);
330 pub const M_AARCH64_EL3T: Self = Self::from_bits_retain(0b01100);
332 pub const M_AARCH64_EL3H: Self = Self::from_bits_retain(0b01101);
334
335 pub const SP_EL0: Self = Self::from_bits_retain(0);
337 pub const SP_ELX: Self = Self::from_bits_retain(1);
339
340 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
342
343 pub const SSBS: Self = Self::from_bits_retain(1 << 12);
345
346 const EL_MASK: u64 = 0x3;
347 const EL_SHIFT: usize = 2;
348 const SP_MASK: u64 = 0x1;
349
350 pub const fn exception_level(self) -> ExceptionLevel {
352 match (self.bits() >> Self::EL_SHIFT) & Self::EL_MASK {
353 0 => ExceptionLevel::El0,
354 1 => ExceptionLevel::El1,
355 2 => ExceptionLevel::El2,
356 3 => ExceptionLevel::El3,
357 _ => unreachable!(),
358 }
359 }
360
361 pub const fn stack_pointer(self) -> StackPointer {
363 match self.bits() & Self::SP_MASK {
364 0 => StackPointer::El0,
365 1 => StackPointer::ElX,
366 _ => unreachable!(),
367 }
368 }
369}
370
371#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
373#[repr(u8)]
374pub enum CacheType {
375 NoCache = 0b000,
377 InstructionOnly = 0b001,
379 DataOnly = 0b010,
381 SeparateInstructionAndData = 0b011,
383 Unified = 0b100,
385}
386
387#[derive(Clone, Copy, Debug, Eq, PartialEq)]
389pub struct CacheLevel(pub(crate) u8);
390
391impl CacheLevel {
392 pub fn new(level: u8) -> Self {
394 assert!((1..8).contains(&level));
395 Self(level)
396 }
397
398 pub fn level(&self) -> u8 {
400 self.0
401 }
402}
403
404impl From<CacheLevel> for u32 {
405 fn from(value: CacheLevel) -> Self {
406 (value.0 - 1).into()
407 }
408}
409
410impl From<CacheLevel> for u64 {
411 fn from(value: CacheLevel) -> Self {
412 u32::from(value).into()
413 }
414}
415
416#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive, IntoPrimitive)]
418#[repr(u8)]
419pub enum ExceptionLevel {
420 El0 = 0,
422 El1 = 1,
424 El2 = 2,
426 El3 = 3,
428}
429
430#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive, IntoPrimitive)]
432#[repr(u8)]
433pub enum StackPointer {
434 El0 = 0,
436 ElX = 1,
438}
439
440#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive, IntoPrimitive)]
442#[repr(u8)]
443pub enum Shareability {
444 Non = 0b00,
446 Outer = 0b10,
448 Inner = 0b11,
450}
451
452#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive, IntoPrimitive)]
454#[repr(u8)]
455pub enum Cacheability {
456 Non = 0b00,
458 WriteBackAllocate = 0b01,
460 WriteThrough = 0b10,
462 WriteBackNoAllocate = 0b11,
464}
465
466#[cfg(test)]
467mod tests {
468 #[cfg(feature = "el1")]
469 use super::*;
470
471 #[test]
472 #[cfg(feature = "el1")]
473 fn debug_mpidr_el1() {
474 assert_eq!(format!("{:?}", MpidrEl1::empty()), "MpidrEl1(0x0)");
475 assert_eq!(
476 format!("{:?}", MpidrEl1::MT | MpidrEl1::U),
477 "MpidrEl1(MT | U)"
478 );
479 assert_eq!(
480 format!("{:?}", MpidrEl1::from_bits_retain(0x12_4134_5678)),
481 "MpidrEl1(MT | U | 0x1200345678)"
482 );
483 }
484
485 #[cfg(feature = "el1")]
486 #[test]
487 fn debug_spsr_el1() {
488 assert_eq!(format!("{:?}", SpsrEl1::empty()), "SpsrEl1(0x0)");
489 assert_eq!(format!("{:?}", SpsrEl1::NZCV), "SpsrEl1(V | C | Z | N)");
490 }
491
492 #[cfg(feature = "el2")]
493 #[test]
494 fn debug_spsr_el2() {
495 assert_eq!(format!("{:?}", SpsrEl2::empty()), "SpsrEl2(0x0)");
496 assert_eq!(format!("{:?}", SpsrEl2::NZCV), "SpsrEl2(V | C | Z | N)");
497 }
498
499 #[cfg(feature = "el3")]
500 #[test]
501 fn debug_spsr_el3() {
502 assert_eq!(format!("{:?}", SpsrEl3::empty()), "SpsrEl3(0x0)");
503 assert_eq!(format!("{:?}", SpsrEl3::NZCV), "SpsrEl3(V | C | Z | N)");
504 assert_eq!(format!("{:?}", SpsrEl3::M_AARCH64_EL3H), "SpsrEl3(0xd)");
505 }
506
507 #[cfg(feature = "el1")]
508 #[test]
509 fn debug_esr_el1() {
510 assert_eq!(format!("{:?}", EsrEl1::empty()), "EsrEl1(0x0)");
511 assert_eq!(format!("{:?}", EsrEl1::IL), "EsrEl1(0x2000000)");
512 assert_eq!(
513 format!("{:?}", EsrEl1::ISS_SYSREG_OPCODE_MASK),
514 "EsrEl1(0x3ffc1e)"
515 );
516 }
517
518 #[cfg(feature = "el2")]
519 #[test]
520 fn debug_esr_el2() {
521 assert_eq!(format!("{:?}", EsrEl2::empty()), "EsrEl2(0x0)");
522 assert_eq!(format!("{:?}", EsrEl2::IL), "EsrEl2(0x2000000)");
523 assert_eq!(
524 format!("{:?}", EsrEl2::ISS_SYSREG_OPCODE_MASK),
525 "EsrEl2(0x3ffc1e)"
526 );
527 }
528
529 #[cfg(feature = "el3")]
530 #[test]
531 fn debug_esr_el3() {
532 assert_eq!(format!("{:?}", EsrEl3::empty()), "EsrEl3(0x0)");
533 assert_eq!(format!("{:?}", EsrEl3::IL), "EsrEl3(0x2000000)");
534 assert_eq!(
535 format!("{:?}", EsrEl3::ISS_SYSREG_OPCODE_MASK),
536 "EsrEl3(0x3ffc1e)"
537 );
538 }
539}