#[cfg(all(any(test, feature = "fakes", target_arch = "aarch64"), feature = "el1"))]
use crate::read_mpidr_el1;
#[cfg(feature = "el1")]
use crate::{
ClidrEl1, CsselrEl1, EsrEl1, IdAa64dfr0El1, IdAa64dfr1El1, IdAa64mmfr0El1, IdAa64mmfr1El1,
IdAa64mmfr2El1, IdAa64mmfr3El1, IdAa64pfr0El1, IdAa64pfr1El1, MpidrEl1, SpsrEl1,
};
#[cfg(feature = "el2")]
use crate::{EsrEl2, SpsrEl2};
#[cfg(feature = "el3")]
use crate::{EsrEl3, MdcrEl3, SmcrEl3, SpsrEl3};
#[cfg(feature = "el1")]
use core::fmt::{self, Debug, Formatter};
use num_enum::{IntoPrimitive, TryFromPrimitive};
#[cfg(feature = "el1")]
impl ClidrEl1 {
pub fn icb_level(self) -> Option<CacheLevel> {
let icb = self.icb();
if icb != 0 {
Some(CacheLevel(icb as u8))
} else {
None
}
}
pub fn cache_type(self, level: CacheLevel) -> CacheType {
self.ctype(level.level().into()).try_into().unwrap()
}
}
#[cfg(feature = "el1")]
impl CsselrEl1 {
pub fn new(tnd: bool, level: CacheLevel, ind: bool) -> Self {
let mut instance = Self::from_bits_retain(u64::from(level) << 1);
if ind {
instance |= Self::IND;
} else if tnd {
instance |= Self::TND;
}
instance
}
pub fn cache_level(self) -> CacheLevel {
CacheLevel(self.level() + 1)
}
}
#[cfg(feature = "el1")]
impl EsrEl1 {
pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
}
#[cfg(feature = "el1")]
impl Debug for EsrEl1 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "EsrEl1({:#x})", self.0)
}
}
#[cfg(feature = "el2")]
impl EsrEl2 {
pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
}
#[cfg(feature = "el2")]
impl Debug for EsrEl2 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "EsrEl2({:#x})", self.0)
}
}
#[cfg(feature = "el3")]
impl EsrEl3 {
pub const ISS_SYSREG_OPCODE_MASK: Self = Self::from_bits_retain(0x003f_fc1e);
}
#[cfg(feature = "el3")]
impl Debug for EsrEl3 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "EsrEl3({:#x})", self.0)
}
}
#[cfg(feature = "el1")]
impl IdAa64dfr0El1 {
const SYS_REG_TRACE_SUPPORTED: u8 = 1;
const SPE_SUPPORTED: u8 = 1;
const TRF_SUPPORTED: u8 = 1;
const TRBE_NOT_SUPPORTED: u8 = 0;
const MTPMU_SUPPORTED: u8 = 1;
pub fn is_feat_sys_reg_trace_present(self) -> bool {
self.tracever() == Self::SYS_REG_TRACE_SUPPORTED
}
pub fn is_feat_spe_present(self) -> bool {
self.pmsver() >= Self::SPE_SUPPORTED
}
pub fn is_feat_trf_present(self) -> bool {
self.tracefilt() == Self::TRF_SUPPORTED
}
pub fn is_feat_trbe_present(self) -> bool {
self.tracebuffer() != Self::TRBE_NOT_SUPPORTED
}
pub fn is_feat_mtpmu_present(self) -> bool {
self.mtpmu() == Self::MTPMU_SUPPORTED
}
}
#[cfg(feature = "el1")]
impl IdAa64dfr1El1 {
const EBEP_IMPLEMENTED: u8 = 0b1;
pub fn is_feat_ebep_present(self) -> bool {
self.ebep() == Self::EBEP_IMPLEMENTED
}
}
#[cfg(feature = "el1")]
impl IdAa64mmfr0El1 {
const FGT_SUPPORTED: u8 = 0b0001;
const FGT2_SUPPORTED: u8 = 0b0010;
pub fn is_feat_fgt_present(self) -> bool {
let val = self.fgt();
val == Self::FGT_SUPPORTED || val == Self::FGT2_SUPPORTED
}
pub fn is_feat_fgt2_present(self) -> bool {
self.fgt() == Self::FGT2_SUPPORTED
}
}
#[cfg(feature = "el1")]
impl IdAa64mmfr1El1 {
const VH_SUPPORTED: u8 = 0b0001;
const HCX_SUPPORTED: u8 = 0b0001;
pub fn is_feat_vhe_present(self) -> bool {
self.vh() >= Self::VH_SUPPORTED
}
pub fn is_feat_hcx_present(self) -> bool {
self.hcx() >= Self::HCX_SUPPORTED
}
}
#[cfg(feature = "el1")]
impl IdAa64mmfr2El1 {
const CCIDX_64_BIT: u8 = 0b0001;
pub fn has_64_bit_ccsidr_el1(self) -> bool {
self.ccidx() == Self::CCIDX_64_BIT
}
}
#[cfg(feature = "el1")]
impl IdAa64mmfr3El1 {
const TCRX_SUPPORTED: u8 = 1;
pub fn is_feat_tcr2_present(self) -> bool {
self.tcrx() >= Self::TCRX_SUPPORTED
}
}
#[cfg(feature = "el1")]
impl IdAa64pfr0El1 {
const SVE_SUPPORTED: u8 = 1;
const MPAM_SUPPORTED: u8 = 1;
const AMU_SUPPORTED: u8 = 1;
pub fn is_feat_sve_present(self) -> bool {
self.sve() == Self::SVE_SUPPORTED
}
pub fn is_feat_mpam_present(self) -> bool {
self.mpam() == Self::MPAM_SUPPORTED
}
pub fn is_feat_amu_present(self) -> bool {
self.amu() >= Self::AMU_SUPPORTED
}
}
#[cfg(feature = "el1")]
impl IdAa64pfr1El1 {
const SSBS_IMPLEMENTED: u8 = 0b1;
const MTE_IMPLEMENTED: u8 = 0b0001;
const MTE2_IMPLEMENTED: u8 = 0b0010;
const SME_IMPLEMENTED: u8 = 0b0001;
const SME2_IMPLEMENTED: u8 = 0b0010;
const NMI_IMPLEMENTED: u8 = 0b1;
const GCS_IMPLEMENTED: u8 = 0b1;
pub fn is_feat_ssbs_present(self) -> bool {
self.ssbs() >= Self::SSBS_IMPLEMENTED
}
pub fn is_feat_mte_present(self) -> bool {
self.mte() >= Self::MTE_IMPLEMENTED
}
pub fn is_feat_mte2_present(self) -> bool {
self.mte() >= Self::MTE2_IMPLEMENTED
}
pub fn is_feat_sme_present(self) -> bool {
self.sme() >= Self::SME_IMPLEMENTED
}
pub fn is_feat_sme2_present(self) -> bool {
self.sme() >= Self::SME2_IMPLEMENTED
}
pub fn is_feat_nmi_present(self) -> bool {
self.nmi() == Self::NMI_IMPLEMENTED
}
pub fn is_feat_gcs_present(self) -> bool {
self.gcs() == Self::GCS_IMPLEMENTED
}
}
#[cfg(feature = "el3")]
impl MdcrEl3 {
pub const SPD32: Self = Self::from_bits_retain(0b10 << 14);
pub const NSPB_NS: Self = Self::from_bits_retain(0b11 << 12);
pub const NSTB_EN: Self = Self::from_bits_retain(1 << 24);
pub const NSTB_SS: Self = Self::from_bits_retain(1 << 25);
}
#[cfg(feature = "el1")]
impl MpidrEl1 {
pub const AFFINITY_BITS: usize = 8;
#[cfg(any(test, feature = "fakes", target_arch = "aarch64"))]
pub fn from_psci_mpidr(psci_mpidr: u64) -> Self {
let mpidr_el1 = read_mpidr_el1();
Self::from_bits_retain(psci_mpidr) | (mpidr_el1 & (Self::MT | Self::U))
}
}
#[cfg(feature = "el3")]
impl SmcrEl3 {
pub fn from_ssve_vector_len(vector_length: u64) -> Self {
Self::from_bits_retain(((vector_length - 1) / 128) & Self::LEN_MASK)
}
}
#[cfg(feature = "el1")]
impl SpsrEl1 {
pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
}
#[cfg(feature = "el2")]
impl SpsrEl2 {
pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
}
#[cfg(feature = "el3")]
impl SpsrEl3 {
pub const M_AARCH64_EL0: Self = Self::from_bits_retain(0b00000);
pub const M_AARCH64_EL1T: Self = Self::from_bits_retain(0b00100);
pub const M_AARCH64_EL1H: Self = Self::from_bits_retain(0b00101);
pub const M_AARCH64_EL2T: Self = Self::from_bits_retain(0b01000);
pub const M_AARCH64_EL2H: Self = Self::from_bits_retain(0b01001);
pub const M_AARCH64_EL3T: Self = Self::from_bits_retain(0b01100);
pub const M_AARCH64_EL3H: Self = Self::from_bits_retain(0b01101);
pub const SP_EL0: Self = Self::from_bits_retain(0);
pub const SP_ELX: Self = Self::from_bits_retain(1);
pub const NZCV: Self = Self::V.union(Self::C).union(Self::Z).union(Self::N);
pub const SSBS: Self = Self::from_bits_retain(1 << 12);
const EL_MASK: u64 = 0x3;
const EL_SHIFT: usize = 2;
const SP_MASK: u64 = 0x1;
pub const fn exception_level(self) -> ExceptionLevel {
match (self.bits() >> Self::EL_SHIFT) & Self::EL_MASK {
0 => ExceptionLevel::El0,
1 => ExceptionLevel::El1,
2 => ExceptionLevel::El2,
3 => ExceptionLevel::El3,
_ => unreachable!(),
}
}
pub const fn stack_pointer(self) -> StackPointer {
match self.bits() & Self::SP_MASK {
0 => StackPointer::El0,
1 => StackPointer::ElX,
_ => unreachable!(),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum CacheType {
NoCache = 0b000,
InstructionOnly = 0b001,
DataOnly = 0b010,
SeparateInstructionAndData = 0b011,
Unified = 0b100,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CacheLevel(pub(crate) u8);
impl CacheLevel {
pub fn new(level: u8) -> Self {
assert!((1..8).contains(&level));
Self(level)
}
pub fn level(&self) -> u8 {
self.0
}
}
impl From<CacheLevel> for u32 {
fn from(value: CacheLevel) -> Self {
(value.0 - 1).into()
}
}
impl From<CacheLevel> for u64 {
fn from(value: CacheLevel) -> Self {
u32::from(value).into()
}
}
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum ExceptionLevel {
El0 = 0,
El1 = 1,
El2 = 2,
El3 = 3,
}
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum StackPointer {
El0 = 0,
ElX = 1,
}
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum Shareability {
Non = 0b00,
Outer = 0b10,
Inner = 0b11,
}
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum Cacheability {
Non = 0b00,
WriteBackAllocate = 0b01,
WriteThrough = 0b10,
WriteBackNoAllocate = 0b11,
}
#[cfg(test)]
mod tests {
#[cfg(feature = "el1")]
use super::*;
#[test]
#[cfg(feature = "el1")]
fn debug_mpidr_el1() {
assert_eq!(format!("{:?}", MpidrEl1::empty()), "MpidrEl1(0x0)");
assert_eq!(
format!("{:?}", MpidrEl1::MT | MpidrEl1::U),
"MpidrEl1(MT | U)"
);
assert_eq!(
format!("{:?}", MpidrEl1::from_bits_retain(0x12_4134_5678)),
"MpidrEl1(MT | U | 0x1200345678)"
);
}
#[cfg(feature = "el1")]
#[test]
fn debug_spsr_el1() {
assert_eq!(format!("{:?}", SpsrEl1::empty()), "SpsrEl1(0x0)");
assert_eq!(format!("{:?}", SpsrEl1::NZCV), "SpsrEl1(V | C | Z | N)");
}
#[cfg(feature = "el2")]
#[test]
fn debug_spsr_el2() {
assert_eq!(format!("{:?}", SpsrEl2::empty()), "SpsrEl2(0x0)");
assert_eq!(format!("{:?}", SpsrEl2::NZCV), "SpsrEl2(V | C | Z | N)");
}
#[cfg(feature = "el3")]
#[test]
fn debug_spsr_el3() {
assert_eq!(format!("{:?}", SpsrEl3::empty()), "SpsrEl3(0x0)");
assert_eq!(format!("{:?}", SpsrEl3::NZCV), "SpsrEl3(V | C | Z | N)");
assert_eq!(format!("{:?}", SpsrEl3::M_AARCH64_EL3H), "SpsrEl3(0xd)");
}
#[cfg(feature = "el1")]
#[test]
fn debug_esr_el1() {
assert_eq!(format!("{:?}", EsrEl1::empty()), "EsrEl1(0x0)");
assert_eq!(format!("{:?}", EsrEl1::IL), "EsrEl1(0x2000000)");
assert_eq!(
format!("{:?}", EsrEl1::ISS_SYSREG_OPCODE_MASK),
"EsrEl1(0x3ffc1e)"
);
}
#[cfg(feature = "el2")]
#[test]
fn debug_esr_el2() {
assert_eq!(format!("{:?}", EsrEl2::empty()), "EsrEl2(0x0)");
assert_eq!(format!("{:?}", EsrEl2::IL), "EsrEl2(0x2000000)");
assert_eq!(
format!("{:?}", EsrEl2::ISS_SYSREG_OPCODE_MASK),
"EsrEl2(0x3ffc1e)"
);
}
#[cfg(feature = "el3")]
#[test]
fn debug_esr_el3() {
assert_eq!(format!("{:?}", EsrEl3::empty()), "EsrEl3(0x0)");
assert_eq!(format!("{:?}", EsrEl3::IL), "EsrEl3(0x2000000)");
assert_eq!(
format!("{:?}", EsrEl3::ISS_SYSREG_OPCODE_MASK),
"EsrEl3(0x3ffc1e)"
);
}
}