Skip to content

Add overlap check between MMIO passthrough regions and MMIO intercept handler regions#327

Open
Solicey wants to merge 2 commits into
syswonder:devfrom
Solicey:add_mem_overlap_check
Open

Add overlap check between MMIO passthrough regions and MMIO intercept handler regions#327
Solicey wants to merge 2 commits into
syswonder:devfrom
Solicey:add_mem_overlap_check

Conversation

@Solicey

@Solicey Solicey commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Summary

MMIO passthrough regions (MEM_TYPE_IO, mapped in stage-2 page table) and MMIO intercept handler regions (registered via mmio_region_register()) have no cross-overlap validation. If both occupy overlapping GPA ranges, the handler silently becomes dead code — the stage-2 mapping prevents any fault, so the handler is never invoked.

Background

hvisor uses two mechanisms for guest MMIO:

Mechanism Registration Behavior
Passthrough pt_init()gpm.insert() Direct hardware access, no stage-2 fault
Intercept mmio_region_register()ZoneInner.mmio Stage-2 fault triggers handler

Each mechanism checks overlaps internally (gpm checks gpm-vs-gpm; mmio checks exact start-address duplicates), but no cross-check exists between them. The zone creation flow processes them independently:

zone_create()
  pt_init()      → gpm.insert()          (checks gpm-vs-gpm only)
  mmio_init()    → mmio_region_register() (checks exact duplicate only)
  PCI init       → mmio_region_register() (checks exact duplicate only)

Fix

Added bidirectional overlap checks at two insertion points:

1. mmio_region_register() (src/zone.rs) — When registering a new intercept handler, panic if:

  • It overlaps with any existing MMIO handler region (not just exact duplicates).
  • It overlaps with any passthrough region already in the stage-2 page table.

2. pt_init() (all four architectures) — Before inserting a passthrough region into gpm, check whether it overlaps with any already-registered MMIO handler. Overlap triggers a panic.

New utility methods:

  • MMIORegion::is_overlap_with() in src/memory/mmio.rs — range overlap test
  • MemorySet::is_range_overlap() in src/memory/mm.rs — public O(log n) query against stage-2 mappings
  • ZoneInner::is_mmio_handler_overlap() in src/zone.rs — helper for pt_init checks

On loongarch64, the VIRTIO branch in pt_init() was reordered (mmio_region_register before gpm.insert) to avoid a false positive from the VIRTIO trap page.

Coverage

Scenario Caught by
Two intercept handler regions overlap mmio_region_register() handler-vs-handler
Passthrough inserted before intercept handler mmio_region_register() handler-vs-gpm
Intercept handler registered before passthrough pt_init() gpm-vs-handler
Same loop: IO entry before VIRTIO entry mmio_region_register() handler-vs-gpm
Same loop: VIRTIO entry before IO entry pt_init() gpm-vs-handler

Files Changed

  • src/memory/mmio.rs — add MMIORegion::is_overlap_with()
  • src/memory/mm.rs — add MemorySet::is_range_overlap()
  • src/zone.rs — add checks in mmio_region_register() + is_mmio_handler_overlap() helper
  • src/arch/x86_64/zone.rs — add handler overlap check before gpm.insert()
  • src/arch/aarch64/zone.rs — same
  • src/arch/riscv64/zone.rs — same
  • src/arch/loongarch64/zone.rs — same + swap VIRTIO order

Verification

Tested on x86_64 QEMU by adding a VIRTIO region at the same address as the HPET IO passthrough (0xfed0_0000). The fix correctly panics at zone creation:

New MMIO handler region MMIORegion { start: 0xfed00000, size: 0x1000 }
overlaps with passthrough region in stage-2 page table

All four architectures (x86_64, aarch64, riscv64, loongarch64) compile successfully.

@Solicey Solicey requested a review from li041 June 28, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant