pub const BOOT_PSTATE: u64 = 0x3C5;
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub enum Reg {
X(u8),
SpEl1,
Pc,
PState,
}
impl Reg {
#[must_use]
pub const fn x(index: u8) -> Option<Self> {
if index <= 30 {
Some(Self::X(index))
} else {
None
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct BootRegs {
pub kernel_load_addr: u64,
pub fdt_addr: u64,
pub pstate: u64,
}
impl BootRegs {
#[must_use]
pub const fn new(kernel_load_addr: u64, fdt_addr: u64) -> Self {
Self {
kernel_load_addr,
fdt_addr,
pstate: BOOT_PSTATE,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn boot_pstate_matches_spec() {
assert_eq!(BOOT_PSTATE, 0x3C5);
}
#[test]
fn x_constructor_accepts_valid_indices() {
for i in 0..=30u8 {
assert!(matches!(Reg::x(i), Some(Reg::X(_))));
}
}
#[test]
fn x_constructor_rejects_out_of_range() {
assert!(Reg::x(31).is_none());
assert!(Reg::x(255).is_none());
}
#[test]
fn boot_regs_default_pstate() {
let regs = BootRegs::new(0x8020_0000, 0xBFE0_0000);
assert_eq!(regs.pstate, BOOT_PSTATE);
assert_eq!(regs.kernel_load_addr, 0x8020_0000);
assert_eq!(regs.fdt_addr, 0xBFE0_0000);
}
}