use super::IntId;
use bitflags::bitflags;
use core::{
cmp::min,
fmt::{self, Debug, Formatter},
};
use safe_mmio::fields::{ReadPure, ReadPureWrite, WriteOnly};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[repr(transparent)]
#[derive(Copy, Clone, Default, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
pub struct GicdCtlr(u32);
bitflags! {
impl GicdCtlr: u32 {
const RWP = 1 << 31;
const nASSGIreq = 1 << 8;
const E1NWF = 1 << 7;
const DS = 1 << 6;
const ARE_NS = 1 << 5;
const ARE_S = 1 << 4;
const EnableGrp1S = 1 << 2;
const EnableGrp1NS = 1 << 1;
const EnableGrp0 = 1 << 0;
}
}
impl Debug for GicdCtlr {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "GicdCtlr(")?;
bitflags::parser::to_writer(self, &mut *f)?;
write!(f, ")")?;
Ok(())
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Default, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
pub struct GicrCtlr(u32);
bitflags! {
impl GicrCtlr: u32 {
const UWP = 1 << 31;
const DPG1S = 1 << 26;
const DPG1NS = 1 << 25;
const DPG0 = 1 << 24;
const RWP = 1 << 3;
const IR = 1 << 2;
const CES = 1 << 1;
const EnableLPIs = 1 << 0;
}
}
impl Debug for GicrCtlr {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "GicrCtlr(")?;
bitflags::parser::to_writer(self, &mut *f)?;
write!(f, ")")?;
Ok(())
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
pub struct GicrPwrr(u32);
bitflags! {
impl GicrPwrr: u32 {
const RedistributorGroupPoweredOff = 1 << 3;
const RedistributorGroupPowerDown = 1 << 2;
const RedistributorApplyGroup = 1 << 1;
const RedistributorPowerDown = 1 << 0;
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
pub struct GicrIidr(u32);
impl GicrIidr {
pub const MODEL_ID_ARM_GIC_600: u32 = 0x0200043b;
pub const MODEL_ID_ARM_GIC_600AE: u32 = 0x0300043b;
pub const MODEL_ID_ARM_GIC_700: u32 = 0x0400043b;
pub fn model_id(self) -> u32 {
const PRODUCT_ID_MASK: u32 = 0xff << 24;
const IMPLEMENTER_MASK: u32 = 0xfff;
self.0 & (PRODUCT_ID_MASK | IMPLEMENTER_MASK)
}
}
#[derive(Clone, Copy, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
#[repr(transparent)]
pub struct GicrTyper(u64);
impl GicrTyper {
fn affinity_value(self) -> [u8; 4] {
((self.0 >> 32) as u32).to_le_bytes()
}
pub fn core_mpidr(self) -> u64 {
let affinity_value = self.affinity_value();
u64::from_le_bytes([
affinity_value[0],
affinity_value[1],
affinity_value[2],
0,
affinity_value[3],
0,
0,
0,
])
}
fn ppi_num(self) -> u32 {
((self.0 >> 27) & 0b11111) as u32
}
pub fn max_eppi_count(self) -> u32 {
32 * self.ppi_num()
}
pub fn processor_number(self) -> u16 {
(self.0 >> 8) as u16
}
pub fn mpam_supported(self) -> bool {
self.0 & (1 << 6) != 0
}
pub fn disable_processor_group_supported(self) -> bool {
self.0 & (1 << 5) != 0
}
pub fn last_redistributor(self) -> bool {
self.0 & (1 << 4) != 0
}
pub fn direct_lpis_supported(self) -> bool {
self.0 & (1 << 3) != 0
}
pub fn dirty_supported(self) -> bool {
self.0 & (1 << 2) != 0
}
pub fn virtual_lpis_supported(self) -> bool {
self.0 & (1 << 1) != 0
}
pub fn physical_lpis_supported(self) -> bool {
self.0 & (1 << 0) != 0
}
}
#[derive(Clone, Copy, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
#[repr(transparent)]
pub struct Typer(u32);
impl Typer {
fn espi_range(self) -> u32 {
self.0 >> 27
}
pub fn max_espi(self) -> IntId {
IntId::espi(32 * self.espi_range() + 31)
}
pub fn num_espis(self) -> u32 {
if self.espi_supported() {
min(32 * (self.espi_range() + 1), IntId::MAX_ESPI_COUNT)
} else {
0
}
}
pub fn range_selector_support(self) -> RangeSelectorSupport {
if self.0 & (1 << 26) == 0 {
RangeSelectorSupport::AffZero16
} else {
RangeSelectorSupport::AffZero256
}
}
pub fn one_of_n_supported(self) -> bool {
self.0 & (1 << 25) == 0
}
pub fn affinity_3_supported(self) -> bool {
self.0 & (1 << 24) != 0
}
pub fn id_bits(self) -> u32 {
((self.0 >> 19) & 0b11111) + 1
}
pub fn dvi_supported(self) -> bool {
self.0 & (1 << 18) != 0
}
pub fn lpis_supported(self) -> bool {
self.0 & (1 << 17) != 0
}
pub fn mpis_supported(self) -> bool {
self.0 & (1 << 16) != 0
}
pub fn num_lpis(self) -> u32 {
let num_lpis = (self.0 >> 11) & 0b11111;
if num_lpis == 0 {
(1u32 << self.id_bits()).saturating_sub(8192)
} else {
2 << num_lpis
}
}
pub fn has_security_extension(self) -> bool {
self.0 & (1 << 10) != 0
}
pub fn nmi_supported(self) -> bool {
self.0 & (1 << 9) != 0
}
pub fn espi_supported(self) -> bool {
self.0 & (1 << 8) != 0
}
pub fn num_cpus(self) -> u32 {
(self.0 >> 5) & 0b111
}
pub fn num_spis(self) -> u32 {
let it_lines = self.0 & 0b11111;
min(32 * it_lines, IntId::MAX_SPI_COUNT)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RangeSelectorSupport {
AffZero16,
AffZero256,
}
#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
#[repr(C, align(8))]
pub struct Gicd {
pub ctlr: ReadPureWrite<GicdCtlr>,
pub typer: ReadPure<Typer>,
pub iidr: ReadPure<u32>,
pub typer2: ReadPure<u32>,
pub statusr: ReadPureWrite<u32>,
_reserved0: [u32; 3],
pub implementation_defined: [u32; 8],
pub setspi_nsr: WriteOnly<u32>,
_reserved1: u32,
pub clrspi_nsr: WriteOnly<u32>,
_reserved2: u32,
pub setspi_sr: WriteOnly<u32>,
_reserved3: u32,
pub clrspi_sr: WriteOnly<u32>,
_reserved4: [u32; 9],
pub igroupr: [ReadPureWrite<u32>; 32],
pub isenabler: [ReadPureWrite<u32>; 32],
pub icenabler: [ReadPureWrite<u32>; 32],
pub ispendr: [ReadPureWrite<u32>; 32],
pub icpendr: [ReadPureWrite<u32>; 32],
pub isactiver: [ReadPureWrite<u32>; 32],
pub icactiver: [ReadPureWrite<u32>; 32],
pub ipriorityr: [ReadPureWrite<u8>; 1024],
pub itargetsr: [ReadPure<u32>; 256],
pub icfgr: [ReadPureWrite<u32>; 64],
pub igrpmodr: [ReadPureWrite<u32>; 32],
_reserved5: [u32; 32],
pub nsacr: [ReadPureWrite<u32>; 64],
pub sigr: u32,
_reserved6: [u32; 3],
pub cpendsgir: [ReadPureWrite<u32>; 4],
pub spendsgir: [ReadPureWrite<u32>; 4],
_reserved7: [u32; 20],
pub inmir: [ReadPureWrite<u32>; 32],
pub igroupr_e: [ReadPureWrite<u32>; 32],
_reserved8: [u32; 96],
pub isenabler_e: [ReadPureWrite<u32>; 32],
_reserved9: [u32; 96],
pub icenabler_e: [ReadPureWrite<u32>; 32],
_reserved10: [u32; 96],
pub ispendr_e: [ReadPureWrite<u32>; 32],
_reserved11: [u32; 96],
pub icpendr_e: [ReadPureWrite<u32>; 32],
_reserved12: [u32; 96],
pub isactiver_e: [ReadPureWrite<u32>; 32],
_reserved13: [u32; 96],
pub icactive_e: [ReadPureWrite<u32>; 32],
_reserved14: [u32; 224],
pub ipriorityr_e: [ReadPureWrite<u8>; 1024],
_reserved15: [u32; 768],
pub icfgr_e: [ReadPureWrite<u32>; 64],
_reserved16: [u32; 192],
pub igrpmodr_e: [ReadPureWrite<u32>; 32],
_reserved17: [u32; 96],
pub nsacr_e: [ReadPureWrite<u32>; 64],
_reserved18: [u32; 256],
pub inmr_e: [ReadPureWrite<u32>; 32],
_reserved19: [u32; 2400],
pub irouter: [ReadPureWrite<u64>; 988],
_reserved20: [u32; 8],
pub irouter_e: [ReadPureWrite<u64>; 1024],
_reserved21: [u32; 2048],
pub implementation_defined2: [u32; 4084],
pub id_registers: [ReadPure<u32>; 12],
}
impl Gicd {
pub const IGROUPR_BITS: usize = 1;
pub const ISENABLER_BITS: usize = 1;
pub const ICENABLER_BITS: usize = 1;
pub const ISPENDR_BITS: usize = 1;
pub const ISACTIVER_BITS: usize = 1;
pub const ICACTIVER_BITS: usize = 1;
pub const IPRIORITY_BITS: usize = 8;
pub const ICFGR_BITS: usize = 2;
pub const IGRPMODR_BITS: usize = 1;
pub const NSACR_BITS: usize = 2;
pub const IROUTER_BITS: usize = 64;
}
#[repr(transparent)]
#[derive(Copy, Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
pub struct Waker(u32);
impl Debug for Waker {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Waker(")?;
bitflags::parser::to_writer(self, &mut *f)?;
write!(f, ")")?;
Ok(())
}
}
bitflags! {
impl Waker: u32 {
const CHILDREN_ASLEEP = 1 << 2;
const PROCESSOR_SLEEP = 1 << 1;
}
}
#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
#[repr(C, align(8))]
pub struct GicrSgi {
pub gicr: Gicr,
pub sgi: Sgi,
}
#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
#[repr(C, align(8))]
pub struct Gicr {
pub ctlr: ReadPureWrite<GicrCtlr>,
pub iidr: ReadPure<GicrIidr>,
pub typer: ReadPure<GicrTyper>,
pub statusr: ReadPureWrite<u32>,
pub waker: ReadPureWrite<Waker>,
pub mpamidr: ReadPure<u32>,
pub partidr: ReadPureWrite<u32>,
pub implementation_defined1: u32,
pub pwrr: ReadPureWrite<GicrPwrr>,
pub implementation_defined2: [u32; 6],
pub setlprir: WriteOnly<u64>,
pub clrlpir: WriteOnly<u64>,
_reserved0: [u32; 8],
pub propbaser: ReadPureWrite<u64>,
pub pendbaser: ReadPureWrite<u64>,
_reserved1: [u32; 8],
pub invlpir: WriteOnly<u64>,
_reserved2: u64,
pub invallr: WriteOnly<u64>,
_reserved3: u64,
pub syncr: ReadPure<u32>,
_reserved4: [u32; 15],
pub implementation_defined3: u64,
_reserved5: u64,
pub implementation_defined4: u64,
_reserved6: [u32; 12218],
pub implementation_defined5: [u32; 4084],
pub id_registers: [ReadPure<u32>; 12],
}
#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
#[repr(C, align(8))]
pub struct Sgi {
_reserved0: [u32; 32],
pub igroupr: [ReadPureWrite<u32>; 3],
_reserved1: [u32; 29],
pub isenabler: [ReadPureWrite<u32>; 3],
_reserved2: [u32; 29],
pub icenabler: [ReadPureWrite<u32>; 3],
_reserved3: [u32; 29],
pub ispendr: [ReadPureWrite<u32>; 3],
_reserved4: [u32; 29],
pub icpendr: [ReadPureWrite<u32>; 3],
_reserved5: [u32; 29],
pub isactiver: [ReadPureWrite<u32>; 3],
_reserved6: [u32; 29],
pub icactiver: [ReadPureWrite<u32>; 3],
_reserved7: [u32; 29],
pub ipriorityr: [ReadPureWrite<u8>; 96],
_reserved8: [u32; 488],
pub icfgr: [ReadPureWrite<u32>; 6],
_reserved9: [u32; 58],
pub igrpmodr: [ReadPureWrite<u32>; 3],
_reserved10: [u32; 61],
pub nsacr: ReadPureWrite<u32>,
_reserved11: [u32; 95],
pub inmir: [ReadPureWrite<u32>; 32],
_reserved12: [u32; 11264],
pub implementation_defined: [u32; 4084],
_reserved13: [u32; 12],
}
impl Sgi {
pub const IGROUPR_BITS: usize = 1;
pub const ISENABLER_BITS: usize = 1;
pub const ICENABLER_BITS: usize = 1;
pub const ISPENDR_BITS: usize = 1;
pub const ISACTIVER_BITS: usize = 1;
pub const ICACTIVER_BITS: usize = 1;
pub const IPRIORITY_BITS: usize = 8;
pub const ICFGR_BITS: usize = 2;
pub const IGRPMODR_BITS: usize = 1;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn max_espi() {
assert_eq!(Typer(0xffffffff).max_espi().0, IntId::ESPI_END - 1);
}
#[test]
fn num_lpis() {
assert_eq!(Typer(0).num_lpis(), 0);
assert_eq!(Typer(12 << 19).num_lpis(), 0);
assert_eq!(Typer(13 << 19).num_lpis(), 1 << 13);
assert_eq!(Typer(13 << 19).num_lpis(), 1 << 13);
assert_eq!(Typer(1 << 11).num_lpis(), 4);
assert_eq!(Typer(2 << 11).num_lpis(), 8);
assert_eq!(Typer(16 << 11).num_lpis(), 1 << 17);
}
#[test]
fn gicr_size() {
assert_eq!(size_of::<Gicr>(), 0x10000);
}
#[test]
fn gicr_typer_affinity() {
let gicr_typer = GicrTyper(0x12_34_56_78_c0_ff_ee_ee);
let expected_affinity_values = [0x78, 0x56, 0x34, 0x12];
assert_eq!(gicr_typer.affinity_value(), expected_affinity_values);
let expected_core_mpidr = 0x00_00_00_12_00_34_56_78;
assert_eq!(gicr_typer.core_mpidr(), expected_core_mpidr);
}
#[test]
fn gicr_typer_flags() {
assert!(!GicrTyper(0b0000000).physical_lpis_supported());
assert!(GicrTyper(0b0000001).physical_lpis_supported());
assert!(!GicrTyper(0b0000000).virtual_lpis_supported());
assert!(GicrTyper(0b0000010).virtual_lpis_supported());
assert!(!GicrTyper(0b0000000).direct_lpis_supported());
assert!(GicrTyper(0b0001000).direct_lpis_supported());
assert!(!GicrTyper(0b0000000).last_redistributor());
assert!(GicrTyper(0b0010000).last_redistributor());
assert!(!GicrTyper(0b0000000).disable_processor_group_supported());
assert!(GicrTyper(0b0100000).disable_processor_group_supported());
}
}