Check if pci range is within platform memory range
Also update the platform memory range to 0x100_0000_0000 (0x1<<40) to
correctly reflect the 40-bit IPA.
Bug: 249054080
Test: TH
Change-Id: Id00558a5e450c5d395a595d38c5c4fa573718f3f
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index fca4583..7d88455 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -18,8 +18,12 @@
use crate::helpers::flatten;
use crate::helpers::GUEST_PAGE_SIZE;
use crate::helpers::SIZE_4KB;
+use crate::memory::BASE_ADDR;
+use crate::memory::MAX_ADDR;
use crate::RebootReason;
use alloc::ffi::CString;
+use core::cmp::max;
+use core::cmp::min;
use core::ffi::CStr;
use core::mem::size_of;
use core::ops::Range;
@@ -103,8 +107,8 @@
/// Check if memory range is ok
fn validate_memory_range(range: &Range<usize>) -> Result<(), RebootReason> {
let base = range.start;
- if base as u64 != DeviceTreeInfo::RAM_BASE_ADDR {
- error!("Memory base address {:#x} is not {:#x}", base, DeviceTreeInfo::RAM_BASE_ADDR);
+ if base != BASE_ADDR {
+ error!("Memory base address {:#x} is not {:#x}", base, BASE_ADDR);
return Err(RebootReason::InvalidFdt);
}
@@ -123,10 +127,9 @@
fn patch_memory_range(fdt: &mut Fdt, memory_range: &Range<usize>) -> libfdt::Result<()> {
let size = memory_range.len() as u64;
- fdt.node_mut(cstr!("/memory"))?.ok_or(FdtError::NotFound)?.setprop_inplace(
- cstr!("reg"),
- flatten(&[DeviceTreeInfo::RAM_BASE_ADDR.to_be_bytes(), size.to_be_bytes()]),
- )
+ fdt.node_mut(cstr!("/memory"))?
+ .ok_or(FdtError::NotFound)?
+ .setprop_inplace(cstr!("reg"), flatten(&[BASE_ADDR.to_be_bytes(), size.to_be_bytes()]))
}
/// Read the number of CPUs from DT
@@ -225,9 +228,9 @@
Ok(PciInfo { ranges: [range0, range1], irq_masks, irq_maps })
}
-fn validate_pci_info(pci_info: &PciInfo) -> Result<(), RebootReason> {
+fn validate_pci_info(pci_info: &PciInfo, memory_range: &Range<usize>) -> Result<(), RebootReason> {
for range in pci_info.ranges.iter() {
- validate_pci_addr_range(range)?;
+ validate_pci_addr_range(range, memory_range)?;
}
for irq_mask in pci_info.irq_masks.iter() {
validate_pci_irq_mask(irq_mask)?;
@@ -238,7 +241,10 @@
Ok(())
}
-fn validate_pci_addr_range(range: &PciAddrRange) -> Result<(), RebootReason> {
+fn validate_pci_addr_range(
+ range: &PciAddrRange,
+ memory_range: &Range<usize>,
+) -> Result<(), RebootReason> {
let mem_flags = PciMemoryFlags(range.addr.0);
let range_type = mem_flags.range_type();
let prefetchable = mem_flags.prefetchable();
@@ -260,8 +266,23 @@
return Err(RebootReason::InvalidFdt);
}
- if bus_addr.checked_add(size).is_none() {
- error!("PCI address range size {:#x} too big", size);
+ let Some(bus_end) = bus_addr.checked_add(size) else {
+ error!("PCI address range size {:#x} overflows", size);
+ return Err(RebootReason::InvalidFdt);
+ };
+ if bus_end > MAX_ADDR.try_into().unwrap() {
+ error!("PCI address end {:#x} is outside of translatable range", bus_end);
+ return Err(RebootReason::InvalidFdt);
+ }
+
+ let memory_start = memory_range.start.try_into().unwrap();
+ let memory_end = memory_range.end.try_into().unwrap();
+
+ if max(bus_addr, memory_start) < min(bus_end, memory_end) {
+ error!(
+ "PCI address range {:#x}-{:#x} overlaps with main memory range {:#x}-{:#x}",
+ bus_addr, bus_end, memory_start, memory_end
+ );
return Err(RebootReason::InvalidFdt);
}
@@ -517,7 +538,6 @@
}
impl DeviceTreeInfo {
- const RAM_BASE_ADDR: u64 = 0x8000_0000;
const GIC_REDIST_SIZE_PER_CPU: u64 = (32 * SIZE_4KB) as u64;
}
@@ -566,7 +586,7 @@
error!("Failed to read pci info from DT: {e}");
RebootReason::InvalidFdt
})?;
- validate_pci_info(&pci_info)?;
+ validate_pci_info(&pci_info, &memory_range)?;
let serial_info = read_serial_info_from(fdt).map_err(|e| {
error!("Failed to read serial info from DT: {e}");
diff --git a/pvmfw/src/memory.rs b/pvmfw/src/memory.rs
index 17dd36b..b223f82 100644
--- a/pvmfw/src/memory.rs
+++ b/pvmfw/src/memory.rs
@@ -35,6 +35,11 @@
use log::error;
use tinyvec::ArrayVec;
+/// Base of the system's contiguous "main" memory.
+pub const BASE_ADDR: usize = 0x8000_0000;
+/// First address that can't be translated by a level 1 TTBR0_EL1.
+pub const MAX_ADDR: usize = 1 << 40;
+
pub type MemoryRange = Range<usize>;
#[derive(Clone, Copy, Debug, Default)]
@@ -129,15 +134,11 @@
impl MemoryTracker {
const CAPACITY: usize = 5;
const MMIO_CAPACITY: usize = 5;
- /// Base of the system's contiguous "main" memory.
- const BASE: usize = 0x8000_0000;
- /// First address that can't be translated by a level 1 TTBR0_EL1.
- const MAX_ADDR: usize = 1 << 39;
/// Create a new instance from an active page table, covering the maximum RAM size.
pub fn new(page_table: mmu::PageTable) -> Self {
Self {
- total: Self::BASE..Self::MAX_ADDR,
+ total: BASE_ADDR..MAX_ADDR,
page_table,
regions: ArrayVec::new(),
mmio_regions: ArrayVec::new(),