From dc70d28233659d31514d7d92fbb51dfe370f0c79 Mon Sep 17 00:00:00 2001 From: Solicey Date: Sat, 22 Aug 2026 13:21:37 +0800 Subject: [PATCH] warn on MMIO handler/passthrough region overlap --- src/memory/mm.rs | 22 +++++++++++ src/memory/mmio.rs | 7 ++++ src/pci/pci_handler.rs | 84 ++++++++++++++++++++++++------------------ src/zone.rs | 34 ++++++++++++++++- 4 files changed, 110 insertions(+), 37 deletions(-) diff --git a/src/memory/mm.rs b/src/memory/mm.rs index dd8fc3ba6..0ba681fb1 100644 --- a/src/memory/mm.rs +++ b/src/memory/mm.rs @@ -93,6 +93,28 @@ where self.pt.root_paddr() } + /// Check whether `[start, start+size)` overlaps with any region in this MemorySet. + pub fn is_range_overlap(&self, start: usize, size: usize) -> bool + where + PT::VA: From, + { + let end = start + size; + let va_start: PT::VA = start.into(); + if let Some((_, before)) = self.regions.range(..va_start).last() { + let before_end: usize = before.start.into() + before.size; + if before_end > start { + return true; + } + } + if let Some((_, after)) = self.regions.range(va_start..).next() { + let after_start: usize = after.start.into(); + if after_start < end { + return true; + } + } + false + } + fn test_free_area(&self, other: &MemoryRegion) -> bool { if let Some((_, before)) = self.regions.range(..other.start).last() { if before.is_overlap_with(other) { diff --git a/src/memory/mmio.rs b/src/memory/mmio.rs index 1d4771892..f8522da13 100644 --- a/src/memory/mmio.rs +++ b/src/memory/mmio.rs @@ -51,6 +51,13 @@ impl MMIORegion { pub fn contains_region(&self, addr: GuestPhysAddr, sz: usize) -> bool { addr >= self.start && addr + (sz as usize) <= self.start + (self.size as usize) } + + /// Check whether this region overlaps with `other`. + pub fn is_overlap_with(&self, other: &MMIORegion) -> bool { + let self_end = self.start + self.size; + let other_end = other.start + other.size; + !(self_end <= other.start || self.start >= other_end) + } } pub fn mmio_perform_access(base: usize, mmio: &mut MMIOAccess) { diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index ee0d42356..f6d05036b 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -784,12 +784,14 @@ fn handle_endpoint_access( ) .is_ok() {} - gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( - new_vaddr_aligned as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; + guard.insert_passthrough_region_quiet( + MemoryRegion::new_with_offset_mapper( + new_vaddr_aligned as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ), + )?; } drop(guard); #[cfg(target_arch = "aarch64")] @@ -925,12 +927,14 @@ fn handle_endpoint_access( // warn!("delete bar {}: can not found 0x{:x}", slot, old_vaddr); } // Insert new gpm mapping at new address - gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; + guard.insert_passthrough_region_quiet( + MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ), + )?; } drop(guard); /* after update gpm, mem barrier is needed @@ -1072,12 +1076,14 @@ fn handle_endpoint_access( { // warn!("delete rom bar: can not found 0x{:x}", old_vaddr); } - gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( - new_vaddr_aligned as GuestPhysAddr, - paddr as HostPhysAddr, - rom_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; + guard.insert_passthrough_region_quiet( + MemoryRegion::new_with_offset_mapper( + new_vaddr_aligned as GuestPhysAddr, + paddr as HostPhysAddr, + rom_size as _, + MemFlags::READ | MemFlags::WRITE, + ), + )?; drop(guard); /* after update gpm, mem barrier is needed */ @@ -1280,12 +1286,14 @@ fn handle_pci_bridge_access( ) .is_ok() {} - gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( - new_vaddr_aligned as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; + guard.insert_passthrough_region_quiet( + MemoryRegion::new_with_offset_mapper( + new_vaddr_aligned as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ), + )?; } drop(guard); #[cfg(target_arch = "aarch64")] @@ -1401,12 +1409,14 @@ fn handle_pci_bridge_access( // warn!("delete bar {}: can not found 0x{:x}", slot, old_vaddr); } // Insert new gpm mapping at new address - gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( - new_vaddr_aligned as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; + guard.insert_passthrough_region_quiet( + MemoryRegion::new_with_offset_mapper( + new_vaddr_aligned as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ), + )?; } drop(guard); /* after update gpm, mem barrier is needed @@ -1543,12 +1553,14 @@ fn handle_pci_bridge_access( { // warn!("delete rom bar: can not found 0x{:x}", old_vaddr); } - gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( - new_vaddr_aligned as GuestPhysAddr, - paddr as HostPhysAddr, - rom_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; + guard.insert_passthrough_region_quiet( + MemoryRegion::new_with_offset_mapper( + new_vaddr_aligned as GuestPhysAddr, + paddr as HostPhysAddr, + rom_size as _, + MemFlags::READ | MemFlags::WRITE, + ), + )?; drop(guard); /* after update gpm, mem barrier is needed */ diff --git a/src/zone.rs b/src/zone.rs index e2dcff07d..2214a289c 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -32,7 +32,7 @@ use crate::config::{HvZoneBootMode, HvZoneConfig, CONFIG_NAME_MAXLEN}; use crate::cpu_data::{get_cpu_data, this_zone, CpuSet}; use crate::error::HvResult; use crate::memory::addr::GuestPhysAddr; -use crate::memory::{MMIOConfig, MMIOHandler, MMIORegion, MemorySet}; +use crate::memory::{MMIOConfig, MMIOHandler, MMIORegion, MemoryRegion, MemorySet}; use core::panic; use core::sync::atomic::{AtomicBool, Ordering}; @@ -221,6 +221,15 @@ impl ZoneInner { handler: MMIOHandler, arg: usize, ) { + // TODO: add error handling instead of just warning. + // See https://github.com/syswonder/hvisor/issues/385 + if self.gpm.is_range_overlap(start, size) { + warn!( + "MMIO handler region [{:#x}, {:#x}) overlaps with passthrough region", + start, + start + size + ); + } if let Some(mmio) = self.mmio.iter_mut().find(|mmio| mmio.region.start == start) { warn!("duplicated mmio region {:#x?}", mmio); if mmio.region.size != size { @@ -259,6 +268,29 @@ impl ZoneInner { .find(|cfg| cfg.region.contains_region(addr, size)) .map(|cfg| (cfg.region, cfg.handler, cfg.arg)) } + /// Check whether `[start, start+size)` overlaps with any registered MMIO handler region. + pub fn is_mmio_handler_overlap(&self, start: GuestPhysAddr, size: usize) -> bool { + let region = MMIORegion { start, size }; + self.mmio + .iter() + .any(|cfg| cfg.region.is_overlap_with(®ion)) + } + /// Insert a passthrough region, warning if it overlaps an MMIO handler region. + pub fn insert_passthrough_region_quiet( + &mut self, + region: MemoryRegion, + ) -> HvResult { + // TODO: add error handling instead of just warning. + // See https://github.com/syswonder/hvisor/issues/385 + if self.is_mmio_handler_overlap(region.start, region.size) { + warn!( + "passthrough region [{:#x}, {:#x}) overlaps with MMIO handler region", + region.start, + region.start + region.size + ); + } + self.gpm.try_insert_quiet(region) + } /// If irq_id belongs to this zone pub fn irq_in_zone(&self, irq_id: u32) -> bool { let idx = (irq_id / 32) as usize;