use squib_core::MAX_SUPPORTED_VCPUS;
pub const MSI_REGION_BASE: u64 = 0x0500_0000;
pub const GICD_BASE: u64 = 0x0800_0000;
pub const GICD_RESERVED_SIZE: u64 = 0x0001_0000;
pub const GICR_BASE: u64 = 0x080A_0000;
pub const GICR_RESERVED_END: u64 = 0x0E0A_0000;
pub const PL011_BASE: u64 = 0x0E0A_0000;
pub const PL011_SIZE: u64 = 0x1000;
pub const VIRTIO_MMIO_BASE: u64 = 0x0F00_0000;
pub const VIRTIO_MMIO_SIZE: u64 = 32 * 0x1000;
pub const DRAM_BASE: u64 = 0x8000_0000;
pub const DRAM_MAX_END: u64 = 0x00FF_8000_0000 + DRAM_BASE;
pub const KERNEL_LOAD_OFFSET: u64 = 0x0020_0000;
pub const INITRD_FALLBACK_OFFSET: u64 = 0x1000_0000;
pub const FDT_MAX_SIZE: u64 = 0x0020_0000;
pub const GICR_REDISTRIBUTOR_SIZE_PER_VCPU: u64 = 0x0002_0000;
const _GICR_LIVE_MAX: u64 = (MAX_SUPPORTED_VCPUS as u64) * GICR_REDISTRIBUTOR_SIZE_PER_VCPU;
const _: () = {
assert!(
GICR_BASE + _GICR_LIVE_MAX <= GICR_RESERVED_END,
"GICR live region for 32 vCPUs overflows the reserved GICR window (D22)"
);
assert!(
PL011_BASE == GICR_RESERVED_END,
"PL011 must abut the GICR reservation (D22)"
);
assert!(
VIRTIO_MMIO_BASE >= PL011_BASE + PL011_SIZE,
"virtio-MMIO base must sit above PL011 (D22 — overlap regression)"
);
assert!(
VIRTIO_MMIO_BASE + VIRTIO_MMIO_SIZE <= DRAM_BASE,
"virtio-MMIO region overlaps DRAM (D22 — overlap regression)"
);
};
#[derive(Debug, Clone, Copy)]
pub struct PageGeometry {
pub host_page: u64,
pub hvf_stage2_granule: u64,
pub tracking_page_default: u64,
pub tracking_page_hot: u64,
}
impl PageGeometry {
pub const APPLE_SILICON: Self = Self {
host_page: 16 * 1024,
hvf_stage2_granule: 16 * 1024,
tracking_page_default: 2 * 1024 * 1024,
tracking_page_hot: 16 * 1024,
};
}
#[derive(Debug, Clone, Copy)]
pub struct MemoryLayout {
pub gicd_base: u64,
pub gicr_base: u64,
pub pl011_base: u64,
pub virtio_mmio_base: u64,
pub virtio_mmio_stride: u64,
pub virtio_mmio_slots: u32,
pub dram_base: u64,
pub page_geometry: PageGeometry,
}
pub const MEMORY_LAYOUT: MemoryLayout = MemoryLayout {
gicd_base: GICD_BASE,
gicr_base: GICR_BASE,
pl011_base: PL011_BASE,
virtio_mmio_base: VIRTIO_MMIO_BASE,
virtio_mmio_stride: 0x1000,
virtio_mmio_slots: 32,
dram_base: DRAM_BASE,
page_geometry: PageGeometry::APPLE_SILICON,
};
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum LayoutOverlap {
Ok,
GicrOverlapsMmio {
vcpu_count: u32,
live_gicr_end: u64,
boundary: u64,
},
}
#[must_use]
pub fn overlap_check(vcpu_count: u32, redistributor_size_per_vcpu: u64) -> LayoutOverlap {
let live_end =
GICR_BASE.saturating_add(u64::from(vcpu_count).saturating_mul(redistributor_size_per_vcpu));
if live_end > PL011_BASE {
LayoutOverlap::GicrOverlapsMmio {
vcpu_count,
live_gicr_end: live_end,
boundary: PL011_BASE,
}
} else {
LayoutOverlap::Ok
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn d22_reserved_window_has_correct_size() {
assert_eq!(GICR_RESERVED_END - GICR_BASE, 96 * 1024 * 1024);
}
#[test]
fn worst_case_gicr_fits_under_pl011() {
const { assert!(_GICR_LIVE_MAX < GICR_RESERVED_END - GICR_BASE) };
}
#[test]
fn pl011_abuts_gicr_window() {
assert_eq!(PL011_BASE, GICR_RESERVED_END);
}
#[test]
fn virtio_mmio_does_not_overlap_pl011() {
const { assert!(VIRTIO_MMIO_BASE >= PL011_BASE + PL011_SIZE) };
}
#[test]
fn virtio_mmio_does_not_overlap_dram() {
const { assert!(VIRTIO_MMIO_BASE + VIRTIO_MMIO_SIZE <= DRAM_BASE) };
}
#[test]
fn page_geometry_apple_silicon_matches_d21() {
let p = PageGeometry::APPLE_SILICON;
assert_eq!(p.host_page, 16 * 1024);
assert_eq!(p.hvf_stage2_granule, 16 * 1024);
assert_eq!(p.tracking_page_default, 2 * 1024 * 1024);
assert_eq!(p.tracking_page_hot, 16 * 1024);
}
#[test]
fn overlap_check_passes_at_max_vcpus() {
assert_eq!(
overlap_check(MAX_SUPPORTED_VCPUS, 0x0002_0000),
LayoutOverlap::Ok
);
}
#[test]
fn overlap_check_fails_if_apple_grows_redistributor_excessively() {
let result = overlap_check(MAX_SUPPORTED_VCPUS, 4 * 1024 * 1024);
assert!(matches!(result, LayoutOverlap::GicrOverlapsMmio { .. }));
}
#[test]
fn overlap_check_zero_vcpus_is_trivially_ok() {
assert_eq!(overlap_check(0, 0x0002_0000), LayoutOverlap::Ok);
}
#[test]
fn overlap_check_does_not_overflow_on_huge_redistributor_size() {
let result = overlap_check(MAX_SUPPORTED_VCPUS, u64::MAX);
assert!(matches!(result, LayoutOverlap::GicrOverlapsMmio { .. }));
}
}