Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/arch/aarch64/zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ impl Zone {
}
match mem_region.mem_type {
MEM_TYPE_RAM | MEM_TYPE_IO => {
// Check for overlap with registered MMIO handler regions.
if inner.is_mmio_handler_overlap(
mem_region.virtual_start as GuestPhysAddr,
mem_region.size as _,
) {
panic!(
"Passthrough region [{:#x}, {:#x}) overlaps with existing MMIO handler",
mem_region.virtual_start,
mem_region.virtual_start as u64 + mem_region.size
);
}
inner
.gpm_mut()
.insert(MemoryRegion::new_with_offset_mapper(
Expand Down
37 changes: 31 additions & 6 deletions src/arch/loongarch64/zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ impl Zone {
let mem_type = region.mem_type;
match mem_type {
MEM_TYPE_RAM => {
// Check for overlap with registered MMIO handler regions.
if inner.is_mmio_handler_overlap(
region.virtual_start as GuestPhysAddr,
region.size as _,
) {
panic!(
"Passthrough region [{:#x}, {:#x}) overlaps with existing MMIO handler",
region.virtual_start,
region.virtual_start as u64 + region.size
);
}
inner
.gpm_mut()
.insert(MemoryRegion::new_with_offset_mapper(
Expand All @@ -57,6 +68,17 @@ impl Zone {
))?;
}
MEM_TYPE_IO => {
// Check for overlap with registered MMIO handler regions.
if inner.is_mmio_handler_overlap(
region.virtual_start as GuestPhysAddr,
region.size as _,
) {
panic!(
"Passthrough region [{:#x}, {:#x}) overlaps with existing MMIO handler",
region.virtual_start,
region.virtual_start as u64 + region.size
);
}
inner
.gpm_mut()
.insert(MemoryRegion::new_with_offset_mapper(
Expand All @@ -71,6 +93,15 @@ impl Zone {
"loongarch64: pt_init: register virtio mmio region: {:#x?}",
region
);
// Register the mmio handler first, so that the overlap check
// against the stage-2 page table in mmio_region_register does
// not find the VIRTIO trap page we are about to insert.
inner.mmio_region_register(
region.physical_start as _,
region.size as _,
mmio_virtio_handler,
region.physical_start as _,
);
inner
.gpm_mut()
.insert(MemoryRegion::new_with_offset_mapper(
Expand All @@ -79,12 +110,6 @@ impl Zone {
PAGE_SIZE, // since we only need 0x200 size for virtio mmio, but the minimal size is PAGE_SIZE
MemFlags::USER, // we use the USER as a hint flag for invalidating this stage-2 PTE
))?;
inner.mmio_region_register(
region.physical_start as _,
region.size as _,
mmio_virtio_handler,
region.physical_start as _,
);
}
_ => {
error!("loongarch64: pt_init: unknown mem type: {}", mem_type);
Expand Down
11 changes: 11 additions & 0 deletions src/arch/riscv64/zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ impl Zone {
}
match mem_region.mem_type {
MEM_TYPE_RAM | MEM_TYPE_IO => {
// Check for overlap with registered MMIO handler regions.
if inner.is_mmio_handler_overlap(
mem_region.virtual_start as GuestPhysAddr,
mem_region.size as _,
) {
panic!(
"Passthrough region [{:#x}, {:#x}) overlaps with existing MMIO handler",
mem_region.virtual_start,
mem_region.virtual_start as u64 + mem_region.size
);
}
inner
.gpm_mut()
.insert(MemoryRegion::new_with_offset_mapper(
Expand Down
11 changes: 11 additions & 0 deletions src/arch/x86_64/zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ impl Zone {
}
match mem_region.mem_type {
MEM_TYPE_RAM | MEM_TYPE_IO | MEM_TYPE_RESERVED => {
// Check for overlap with registered MMIO handler regions.
if inner.is_mmio_handler_overlap(
mem_region.virtual_start as GuestPhysAddr,
mem_region.size as _,
) {
panic!(
"Passthrough region [{:#x}, {:#x}) overlaps with existing MMIO handler",
mem_region.virtual_start,
mem_region.virtual_start as u64 + mem_region.size
);
}
inner.gpm_mut().insert(MemoryRegion::new_with_offset_mapper(
mem_region.virtual_start as GuestPhysAddr,
mem_region.physical_start as HostPhysAddr,
Expand Down
24 changes: 24 additions & 0 deletions src/memory/mm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,30 @@ where
self.pt.root_paddr()
}

/// Check whether `[start, start+size)` overlaps with any existing region in this MemorySet.
pub fn is_range_overlap(&self, start: usize, size: usize) -> bool
where
PT::VA: From<usize>,
{
let end = start + size;
let va_start: PT::VA = start.into();
// Check the region immediately before `start`.
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;
}
}
// Check the region at or after `start`.
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<PT::VA>) -> bool {
if let Some((_, before)) = self.regions.range(..other.start).last() {
if before.is_overlap_with(other) {
Expand Down
7 changes: 7 additions & 0 deletions src/memory/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
32 changes: 31 additions & 1 deletion src/zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,30 @@ impl ZoneInner {
mmio.handler = handler;
mmio.arg = arg;
} else {
let new_region = MMIORegion { start, size };

// Check for overlap with existing mmio handler regions.
if let Some(existing) = self
.mmio
.iter()
.find(|cfg| cfg.region.is_overlap_with(&new_region))
{
panic!(
"New MMIO handler region {:#x?} overlaps with existing handler {:#x?}",
new_region, existing.region
);
}

// Check for overlap with passthrough regions in the stage-2 page table.
if self.gpm.is_range_overlap(start, size) {
panic!(
"New MMIO handler region {:#x?} overlaps with passthrough region in stage-2 page table",
new_region
);
}

self.mmio.push(MMIOConfig {
region: MMIORegion { start, size },
region: new_region,
handler,
arg,
})
Expand Down Expand Up @@ -253,6 +275,14 @@ 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(&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;
Expand Down
Loading