Centralize guest physical layout logic#3501
Open
jstarks wants to merge 29 commits into
Open
Conversation
Add a pure-math layout allocator in vm_topology::layout that assigns address ranges to MMIO consumers within a flat physical address space. The allocator has no knowledge of specific architectures, firmware types, or pinned-address conventions -- those are the responsibility of the caller. Consumers call request() to declare allocation needs, passing a &mut MemoryRange that will be filled in when allocate() runs. Pinned requests are placed first at their fixed addresses with overlap validation. Dynamic requests (Below4GiB / Above4GiB) are sorted by alignment desc, size desc, input order asc, then greedy top-down placed into the remaining free space. allocate() returns a sorted Vec<MemoryRange> of all allocations. Free-space tracking uses subtract_ranges for linear-time updates. Pinned overlap detection sorts by address and checks adjacent pairs.
jstarks
commented
May 16, 2026
jstarks
commented
May 16, 2026
jstarks
commented
May 16, 2026
jstarks
commented
May 16, 2026
jstarks
commented
May 16, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR centralizes guest physical address layout decisions into vm_topology::layout and the OpenVMM worker resolver, replacing per-frontend MMIO gap carving with size-based layout requests.
Changes:
- Adds a deterministic layout allocator and worker memory-layout resolver.
- Updates OpenVMM/Petri/ttrpc configuration to request MMIO sizes instead of fixed default gaps.
- Updates loader paths, PCIe/virtio placement, tests, and Guide documentation for the new layout model.
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
vmm_tests/vmm_tests/tests/tests/x86_64/openhcl_linux_direct.rs |
Updates VTL2 MMIO self-allocation test expectations. |
vmm_tests/vmm_tests/tests/tests/multiarch/memstat.rs |
Removes explicit Petri MMIO gap selection. |
vmm_core/vm_manifest_builder/src/lib.rs |
Adds default chipset MMIO sizing outputs. |
vm/vmcore/vm_topology/src/memory.rs |
Adds constructor for resolved layouts and adjusts layout end handling. |
vm/vmcore/vm_topology/src/lib.rs |
Exposes the new layout module. |
vm/vmcore/vm_topology/src/layout.rs |
Adds the generic layout allocator and tests. |
petri/src/vm/openvmm/modify.rs |
Converts PCIe test topology setup to dynamic MMIO window sizes. |
petri/src/vm/openvmm/construct.rs |
Removes Petri-side default MMIO gap construction. |
petri/src/vm/mod.rs |
Removes Petri MmioConfig. |
petri/Cargo.toml |
Removes unused memory_range dependency. |
openvmm/openvmm_entry/src/ttrpc/mod.rs |
Removes fixed MMIO defaults from ttrpc VM config. |
openvmm/openvmm_entry/src/lib.rs |
Removes CLI-side MMIO carving and emits dynamic PCIe sizing. |
openvmm/openvmm_entry/Cargo.toml |
Removes unused memory_range dependency. |
openvmm/openvmm_defs/src/config.rs |
Changes VM config schema to MMIO sizes and dynamic/fixed PCIe BAR windows. |
openvmm/openvmm_defs/Cargo.toml |
Enables mesh support for memory_range. |
openvmm/openvmm_core/src/worker/vm_loaders/linux.rs |
Uses resolved layout MMIO for Linux direct DT VMBus ranges. |
openvmm/openvmm_core/src/worker/vm_loaders/igvm.rs |
Moves VTL2 memory placement into layout request/resolution flow. |
openvmm/openvmm_core/src/worker/mod.rs |
Adds worker memory-layout module. |
openvmm/openvmm_core/src/worker/memory_layout.rs |
Adds worker policy resolver for RAM, MMIO, PCIe, virtio, and VTL2 ranges. |
openvmm/openvmm_core/src/worker/dispatch.rs |
Integrates resolved layout outputs into VM initialization, PCIe, virtio, ACPI, and IGVM paths. |
openhcl/underhill_core/src/worker.rs |
Ignores new manifest result fields where not used. |
Guide/src/SUMMARY.md |
Adds the new memory-layout Guide page. |
Guide/src/reference/architecture/openvmm/memory-layout.md |
Documents allocator phases and worker layout policy. |
Cargo.lock |
Updates dependency graph after dependency removals. |
Comments suppressed due to low confidence (2)
openvmm/openvmm_core/src/worker/memory_layout.rs:275
- Flattening RAM extents by vnode order can produce an unsorted
ramvector even thoughMemoryLayout::new_from_resolved_rangesrequires RAM ranges to be sorted by address. For example, a large 1 GiB-aligned vnode can skip a low fragment around a fixed MMIO hole, and a later smaller vnode can then allocate that lower fragment; validation will reject the otherwise valid layout. Preserve the vnode metadata but sort the flattened RAM ranges by address before constructingMemoryLayout.
let ram = ram_ranges_by_node
.into_iter()
.enumerate()
.flat_map(|(vnode, ranges)| {
ranges.into_iter().map(move |range| MemoryRangeWithNode {
range,
vnode: vnode as u32,
})
})
.collect::<Vec<_>>();
openvmm/openvmm_core/src/worker/memory_layout.rs:327
- This host-width check only uses
MemoryLayout::end_of_layout(), which explicitly excludes the optional VTL2 private range and does not include the returnedvtl2_chipset_mmiorange. As a result, a layout can pass validation even when VTL2 private memory or VTL2 chipset MMIO is placed above the host physical-address limit, leading to a later mapping/boot failure. Include all resolved ranges (includingvtl2_rangeandvtl2_chipset_mmio) when validating the address-space limit.
let address_space_limit = 1u64 << input.physical_address_size;
if memory_layout.end_of_layout() > address_space_limit {
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 25 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
openvmm/openvmm_core/src/worker/memory_layout.rs:328
- For a full bus window (
start_bus = 0,end_bus = 255, which is the CLI default), this addition is performed asu8before conversion tou64.255 + 1overflows (panics in checked builds and wraps to 0 in release), so the resolved per-root-complex ECAM range has the wrong length andGenericPcieRootComplex::newwill later reject/panic because it expects 256 MiB. Widen the operands before adding one, as the segment ECAM calculation above does.
let size =
u64::from(root_complex.end_bus - root_complex.start_bus + 1) * PCIE_ECAM_BYTES_PER_BUS;
ranges.ecam_range =
MemoryRange::new(se.range.start() + offset..se.range.start() + offset + size);
Comment on lines
+300
to
+307
| if let Some(vtl2_layout) = input.vtl2_layout { | ||
| builder.request( | ||
| "vtl2", | ||
| &mut vtl2_range, | ||
| vtl2_layout.size, | ||
| vtl2_layout.alignment, | ||
| Placement::PostMmio, | ||
| ); |
|
|
||
| After `allocate()` succeeds, the worker collects the resolved ranges into | ||
| the `MemoryLayout`'s MMIO, PCI ECAM, and PCI MMIO gap vectors, then checks | ||
| `MemoryLayout::end_of_layout()` against the host's physical-address width. |
Comment on lines
+190
to
+193
| if let Some(entry) = segment_ecams.iter_mut().find(|e| e.segment == rc.segment) { | ||
| entry.min_bus = entry.min_bus.min(rc.start_bus); | ||
| entry.max_bus = entry.max_bus.max(rc.end_bus); | ||
| } else { |
| // Default chipset MMIO sizes for `HclHost` from | ||
| // `vm_manifest_builder::VmChipsetBuilder::build`. Keep in sync with that | ||
| // file. | ||
| const DEFAULT_LOW_MMIO_SIZE: u64 = 96 * 1024 * 1024; |
Comment on lines
+274
to
+275
| /// The RAM, MMIO, PCI ECAM, and PCI MMIO ranges must each be in sorted | ||
| /// order, non-empty, and non-overlapping. The combined layout is also |
Comment on lines
+241
to
+245
| let bus_count = u64::from(se.max_bus - se.min_bus) + 1; | ||
| builder.request( | ||
| format!("pcie-seg{}-ecam", se.segment), | ||
| &mut se.range, | ||
| bus_count * PCIE_ECAM_BYTES_PER_BUS, |
Comment on lines
+217
to
+229
| max_bus: u8, | ||
| range: MemoryRange, | ||
| } | ||
| let mut segment_ecams: Vec<SegmentEcam> = Vec::new(); | ||
| for rc in input.pcie_root_complexes { | ||
| if let Some(entry) = segment_ecams.iter_mut().find(|e| e.segment == rc.segment) { | ||
| entry.min_bus = entry.min_bus.min(rc.start_bus); | ||
| entry.max_bus = entry.max_bus.max(rc.end_bus); | ||
| } else { | ||
| segment_ecams.push(SegmentEcam { | ||
| segment: rc.segment, | ||
| min_bus: rc.start_bus, | ||
| max_bus: rc.end_bus, |
Comment on lines
+152
to
+153
| the `MemoryLayout`'s MMIO, PCI ECAM, and PCI MMIO gap vectors, then checks | ||
| `MemoryLayout::end_of_layout()` against the host's physical-address width. |
| arch_reserved.end(), | ||
| arch_reserved.len(), | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Layout decisions ("where does this MMIO range live?") are currently spread across the command line, ttrpc, petri, and the worker, each carving up
DEFAULT_MMIO_GAPS_*in its own way. This PR replaces all of that with a single allocator invm_topology::layoutand a worker resolver inopenvmm_core::worker::memory_layout. Front ends now specify sizes; the resolver picks addresses.What changes for callers:
Improvements as part of this:
See memory-layout.md for the allocator phases, worker policy, and worked examples.