Skip to main content

ax_cpu/arch/aarch64/
capability.rs

1//! AArch64 CPU identity.
2
3/// Architectural MIDR_EL1 identity, independent of platform CPU numbering.
4/// Cluster grouping and Linux PMU source names belong to the caller.
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub struct Midr(u64);
7
8impl Midr {
9    /// Reads this CPU's architectural identity.
10    pub fn read() -> Self {
11        Self(read_midr_el1())
12    }
13
14    /// Wraps a previously captured identity without accessing hardware.
15    pub const fn from_raw(value: u64) -> Self {
16        Self(value)
17    }
18
19    /// Returns the complete captured MIDR value.
20    pub const fn raw(self) -> u64 {
21        self.0
22    }
23
24    /// Returns the implementer code in bits 31:24.
25    pub const fn implementer(self) -> u8 {
26        (self.0 >> 24) as u8
27    }
28
29    /// Returns the implementation's part number in bits 15:4.
30    pub const fn part_number(self) -> u16 {
31        ((self.0 >> 4) & 0xfff) as u16
32    }
33
34    /// Returns the major revision in bits 23:20.
35    pub const fn variant(self) -> u8 {
36        ((self.0 >> 20) & 15) as u8
37    }
38
39    /// Returns the minor revision in bits 3:0.
40    pub const fn revision(self) -> u8 {
41        (self.0 & 15) as u8
42    }
43}
44
45/// Reads the raw MIDR_EL1 identity of the current CPU.
46pub fn read_midr_el1() -> u64 {
47    let value;
48    // SAFETY: callers of CPU primitives execute in privileged kernel context.
49    unsafe {
50        core::arch::asm!("mrs {}, MIDR_EL1", out(reg) value, options(nomem, nostack));
51    }
52    value
53}
54
55/// Raw architectural feature registers used by upper-layer capability policy.
56/// Values are not filtered for any operating system's supported user context.
57#[derive(Clone, Copy, Debug, Eq, PartialEq)]
58pub enum IdRegister {
59    /// Processor features, including implemented exception levels and FP/SIMD.
60    Pfr0,
61    /// Instruction-set attributes, first group.
62    Isar0,
63    /// Instruction-set attributes, second group.
64    Isar1,
65    /// Memory-model attributes, first group.
66    Mmfr0,
67    /// Memory-model attributes, second group.
68    Mmfr1,
69    /// Memory-model attributes, third group.
70    Mmfr2,
71}
72
73impl IdRegister {
74    /// Reads this CPU's unmodified architectural feature value at a privileged EL.
75    pub fn read(self) -> u64 {
76        let value;
77        // SAFETY: the CPU API is used in privileged context; these architectural
78        // identification registers are read-only and do not transfer ownership.
79        unsafe {
80            match self {
81                Self::Pfr0 => {
82                    core::arch::asm!("mrs {}, ID_AA64PFR0_EL1", out(reg) value, options(nomem, nostack))
83                }
84                Self::Isar0 => {
85                    core::arch::asm!("mrs {}, ID_AA64ISAR0_EL1", out(reg) value, options(nomem, nostack))
86                }
87                Self::Isar1 => {
88                    core::arch::asm!("mrs {}, ID_AA64ISAR1_EL1", out(reg) value, options(nomem, nostack))
89                }
90                Self::Mmfr0 => {
91                    core::arch::asm!("mrs {}, ID_AA64MMFR0_EL1", out(reg) value, options(nomem, nostack))
92                }
93                Self::Mmfr1 => {
94                    core::arch::asm!("mrs {}, ID_AA64MMFR1_EL1", out(reg) value, options(nomem, nostack))
95                }
96                Self::Mmfr2 => {
97                    core::arch::asm!("mrs {}, ID_AA64MMFR2_EL1", out(reg) value, options(nomem, nostack))
98                }
99            }
100        }
101        value
102    }
103}
104
105/// Returns the implemented physical-address width from ID_AA64MMFR0_EL1.
106/// Reserved encodings return None; consumers choose their supported format cap.
107pub fn physical_address_bits() -> Option<usize> {
108    match IdRegister::Mmfr0.read() & 15 {
109        0 => Some(32),
110        1 => Some(36),
111        2 => Some(40),
112        3 => Some(42),
113        4 => Some(44),
114        5 => Some(48),
115        6 => Some(52),
116        7 => Some(56),
117        _ => None,
118    }
119}