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::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
203 pub fn is_feat_sve_present(self) -> bool {
205 self.sve() == Self::SVE_SUPPORTED
206 }
207
208 pub fn is_feat_mpam_present(self) -> bool {
210 self.mpam() == Self::MPAM_SUPPORTED
211 }
212}
213
214#[cfg(feature = "el1")]
215impl IdAa64pfr1El1 {
216 const SSBS_IMPLEMENTED: u8 = 0b1;
217 const MTE_IMPLEMENTED: u8 = 0b0001;
218 const MTE2_IMPLEMENTED: u8 = 0b0010;
219 const SME_IMPLEMENTED: u8 = 0b0001;
220 const SME2_IMPLEMENTED: u8 = 0b0010;
221 const NMI_IMPLEMENTED: u8 = 0b1;
222 const GCS_IMPLEMENTED: u8 = 0b1;
223
224 pub fn is_feat_ssbs_present(self) -> bool {
226 self.ssbs() >= Self::SSBS_IMPLEMENTED
227 }
228
229 pub fn is_feat_mte_present(self) -> bool {
231 self.mte() >= Self::MTE_IMPLEMENTED
232 }
233
234 pub fn is_feat_mte2_present(self) -> bool {
236 self.mte() >= Self::MTE2_IMPLEMENTED
237 }
238
239 pub fn is_feat_sme_present(self) -> bool {
241 self.sme() >= Self::SME_IMPLEMENTED
242 }
243
244 pub fn is_feat_sme2_present(self) -> bool {
246 self.sme() >= Self::SME2_IMPLEMENTED
247 }
248
249 pub fn is_feat_nmi_present(self) -> bool {
251 self.nmi() == Self::NMI_IMPLEMENTED
252 }
253
254 pub fn is_feat_gcs_present(self) -> bool {
256 self.gcs() == Self::GCS_IMPLEMENTED
257 }
258}
259
260#[cfg(feature = "el3")]
261impl MdcrEl3 {
262 pub const SPD32: Self = Self::from_bits_retain(0b10 << 14);
264 pub const NSPB_NS: Self = Self::from_bits_retain(0b11 << 12);
267 pub const NSTB_EN: Self = Self::from_bits_retain(1 << 24);
269 pub const NSTB_SS: Self = Self::from_bits_retain(1 << 25);
271}
272
273#[cfg(feature = "el1")]
274impl MpidrEl1 {
275 pub const AFFINITY_BITS: usize = 8;
277
278 #[cfg(any(test, feature = "fakes", target_arch = "aarch64"))]
286 pub fn from_psci_mpidr(psci_mpidr: u64) -> Self {
287 let mpidr_el1 = read_mpidr_el1();
288 Self::from_bits_retain(psci_mpidr) | (mpidr_el1 & (Self::MT | Self::U))
289 }
290}
291
292#[cfg(feature = "el3")]
293impl SmcrEl3 {
294 pub fn from_ssve_vector_len(vector_length: u64) -> Self {
296 Self::from_bits_retain(((vector_length - 1) / 128) & Self::LEN_MASK)
297 }
298}
299
300#[cfg(feature = "el1")]
301impl SpsrEl1 {
302 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
304}
305
306#[cfg(feature = "el2")]
307impl SpsrEl2 {
308 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
310}
311
312#[cfg(feature = "el3")]
313impl SpsrEl3 {
314 pub const M_AARCH64_EL0: Self = Self::from_bits_retain(0b00000);
316 pub const M_AARCH64_EL1T: Self = Self::from_bits_retain(0b00100);
318 pub const M_AARCH64_EL1H: Self = Self::from_bits_retain(0b00101);
320 pub const M_AARCH64_EL2T: Self = Self::from_bits_retain(0b01000);
322 pub const M_AARCH64_EL2H: Self = Self::from_bits_retain(0b01001);
324 pub const M_AARCH64_EL3T: Self = Self::from_bits_retain(0b01100);
326 pub const M_AARCH64_EL3H: Self = Self::from_bits_retain(0b01101);
328
329 pub const SP_EL0: Self = Self::from_bits_retain(0);
331 pub const SP_ELX: Self = Self::from_bits_retain(1);
333
334 pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
336
337 pub const SSBS: Self = Self::from_bits_retain(1 << 12);
339
340 const EL_MASK: u64 = 0x3;
341 const EL_SHIFT: usize = 2;
342 const SP_MASK: u64 = 0x1;
343
344 pub const fn exception_level(self) -> ExceptionLevel {
346 match (self.bits() >> Self::EL_SHIFT) & Self::EL_MASK {
347 0 => ExceptionLevel::El0,
348 1 => ExceptionLevel::El1,
349 2 => ExceptionLevel::El2,
350 3 => ExceptionLevel::El3,
351 _ => unreachable!(),
352 }
353 }
354
355 pub const fn stack_pointer(self) -> StackPointer {
357 match self.bits() & Self::SP_MASK {
358 0 => StackPointer::El0,
359 1 => StackPointer::ElX,
360 _ => unreachable!(),
361 }
362 }
363}
364
365#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
367#[repr(u8)]
368pub enum CacheType {
369 NoCache = 0b000,
371 InstructionOnly = 0b001,
373 DataOnly = 0b010,
375 SeparateInstructionAndData = 0b011,
377 Unified = 0b100,
379}
380
381#[derive(Clone, Copy, Debug, Eq, PartialEq)]
383pub struct CacheLevel(pub(crate) u8);
384
385impl CacheLevel {
386 pub fn new(level: u8) -> Self {
388 assert!((1..8).contains(&level));
389 Self(level)
390 }
391
392 pub fn level(&self) -> u8 {
394 self.0
395 }
396}
397
398impl From<CacheLevel> for u32 {
399 fn from(value: CacheLevel) -> Self {
400 (value.0 - 1).into()
401 }
402}
403
404impl From<CacheLevel> for u64 {
405 fn from(value: CacheLevel) -> Self {
406 u32::from(value).into()
407 }
408}
409
410#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive)]
412#[repr(u8)]
413pub enum ExceptionLevel {
414 El0 = 0,
416 El1 = 1,
418 El2 = 2,
420 El3 = 3,
422}
423
424#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive)]
426#[repr(u8)]
427pub enum StackPointer {
428 El0 = 0,
430 ElX = 1,
432}
433
434#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive)]
436#[repr(u8)]
437pub enum Shareability {
438 Non = 0b00,
440 Outer = 0b10,
442 Inner = 0b11,
444}
445
446#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive)]
448#[repr(u8)]
449pub enum Cacheability {
450 Non = 0b00,
452 WriteBackAllocate = 0b01,
454 WriteThrough = 0b10,
456 WriteBackNoAllocate = 0b11,
458}
459
460#[cfg(test)]
461mod tests {
462 #[cfg(feature = "el1")]
463 use super::*;
464
465 #[test]
466 #[cfg(feature = "el1")]
467 fn debug_mpidr_el1() {
468 assert_eq!(format!("{:?}", MpidrEl1::empty()), "MpidrEl1(0x0)");
469 assert_eq!(
470 format!("{:?}", MpidrEl1::MT | MpidrEl1::U),
471 "MpidrEl1(MT | U)"
472 );
473 assert_eq!(
474 format!("{:?}", MpidrEl1::from_bits_retain(0x12_4134_5678)),
475 "MpidrEl1(MT | U | 0x1200345678)"
476 );
477 }
478
479 #[cfg(feature = "el1")]
480 #[test]
481 fn debug_spsr_el1() {
482 assert_eq!(format!("{:?}", SpsrEl1::empty()), "SpsrEl1(0x0)");
483 assert_eq!(format!("{:?}", SpsrEl1::NZCV), "SpsrEl1(V | C | Z | N)");
484 }
485
486 #[cfg(feature = "el2")]
487 #[test]
488 fn debug_spsr_el2() {
489 assert_eq!(format!("{:?}", SpsrEl2::empty()), "SpsrEl2(0x0)");
490 assert_eq!(format!("{:?}", SpsrEl2::NZCV), "SpsrEl2(V | C | Z | N)");
491 }
492
493 #[cfg(feature = "el3")]
494 #[test]
495 fn debug_spsr_el3() {
496 assert_eq!(format!("{:?}", SpsrEl3::empty()), "SpsrEl3(0x0)");
497 assert_eq!(format!("{:?}", SpsrEl3::NZCV), "SpsrEl3(V | C | Z | N)");
498 assert_eq!(format!("{:?}", SpsrEl3::M_AARCH64_EL3H), "SpsrEl3(0xd)");
499 }
500
501 #[cfg(feature = "el1")]
502 #[test]
503 fn debug_esr_el1() {
504 assert_eq!(format!("{:?}", EsrEl1::empty()), "EsrEl1(0x0)");
505 assert_eq!(format!("{:?}", EsrEl1::IL), "EsrEl1(0x2000000)");
506 assert_eq!(
507 format!("{:?}", EsrEl1::ISS_SYSREG_OPCODE_MASK),
508 "EsrEl1(0x3ffc1e)"
509 );
510 }
511
512 #[cfg(feature = "el2")]
513 #[test]
514 fn debug_esr_el2() {
515 assert_eq!(format!("{:?}", EsrEl2::empty()), "EsrEl2(0x0)");
516 assert_eq!(format!("{:?}", EsrEl2::IL), "EsrEl2(0x2000000)");
517 assert_eq!(
518 format!("{:?}", EsrEl2::ISS_SYSREG_OPCODE_MASK),
519 "EsrEl2(0x3ffc1e)"
520 );
521 }
522
523 #[cfg(feature = "el3")]
524 #[test]
525 fn debug_esr_el3() {
526 assert_eq!(format!("{:?}", EsrEl3::empty()), "EsrEl3(0x0)");
527 assert_eq!(format!("{:?}", EsrEl3::IL), "EsrEl3(0x2000000)");
528 assert_eq!(
529 format!("{:?}", EsrEl3::ISS_SYSREG_OPCODE_MASK),
530 "EsrEl3(0x3ffc1e)"
531 );
532 }
533}