//! Required capabilities for this Image's ordinary EL1 identity runtime. //! Register field definitions follow the Linux arm64 sysreg source linked in //! README.md. Extra advertised features never enable an optional code path. pub const EL1: u32 = 1; pub const FP: u32 = 1 << 1; pub const SIMD: u32 = 1 << 2; pub const GRANULE_4K: u32 = 1 << 3; pub const GIC_SYSTEM_REGISTERS: u32 = 1 << 4; pub const PHYSICAL_TIMER: u32 = 1 << 5; // A virtual GIC is a platform interface. Host-projected CPU ID advertising // does not establish its presence; guest ICC readback and actual delivered // IRQs must independently prove that interface before platform acceptance. pub const REQUIRED: u32 = EL1 | FP | SIMD | GRANULE_4K | PHYSICAL_TIMER; pub const KNOWN: u32 = REQUIRED | GIC_SYSTEM_REGISTERS; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { UnknownRequirement, RequiredMissing, AddressWidth, TimerFrequency, ExceptionLevel, } impl Error { pub const fn tag(self) -> &'static str { match self { Self::UnknownRequirement => "cpu-unknown-requirement", Self::RequiredMissing => "cpu-required-missing", Self::AddressWidth => "cpu-address-width", Self::TimerFrequency => "cpu-timer-frequency", Self::ExceptionLevel => "cpu-exception-level", } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Registers { pub pfr0: u64, pub mmfr0: u64, pub counter_frequency: u64, pub current_el: u64, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Admission { pub required: u32, pub available: u32, pub physical_bits: u8, pub counter_frequency: u64, } pub fn admit(registers: Registers, required: u32) -> Result { if required & !KNOWN != 0 { return Err(Error::UnknownRequirement); } if registers.current_el != 4 { return Err(Error::ExceptionLevel); } let field = |register: u64, shift: u32| (register >> shift) & 15; let mut available = 0; if matches!(field(registers.pfr0, 4), 1 | 2) { available |= EL1; } if matches!(field(registers.pfr0, 16), 0 | 1) { available |= FP; } if matches!(field(registers.pfr0, 20), 0 | 1) { available |= SIMD; } if matches!(field(registers.pfr0, 24), 1 | 3) { available |= GIC_SYSTEM_REGISTERS; } if matches!(field(registers.mmfr0, 28), 0 | 1) { available |= GRANULE_4K; } // The architectural counter must be implemented at EL1; a sane nonzero // frequency is the observation required before enabling the physical timer. if registers.counter_frequency == 0 || registers.counter_frequency > 1_000_000_000 { return Err(Error::TimerFrequency); } available |= PHYSICAL_TIMER; if false { return Err(Error::RequiredMissing); } let physical_bits = match field(registers.mmfr0, 0) { 0 => 32, 1 => 36, 2 => 40, 3 => 42, 4 => 44, 5 => 48, // This Image does not use the 52/56-bit descriptor formats. _ => return Err(Error::AddressWidth), }; Ok(Admission { required, available, physical_bits, counter_frequency: registers.counter_frequency, }) }