diff --git a/openvmm/openvmm_core/src/worker/vm_loaders/igvm.rs b/openvmm/openvmm_core/src/worker/vm_loaders/igvm.rs index 8796e75159..32d6185c80 100644 --- a/openvmm/openvmm_core/src/worker/vm_loaders/igvm.rs +++ b/openvmm/openvmm_core/src/worker/vm_loaders/igvm.rs @@ -1217,6 +1217,14 @@ fn load_igvm_x86( relocation_region.base_gpa..=relocation_region.base_gpa + relocation_region.size - 1, offset as i64, ); + // The page table region is itself relocatable and must stay identity + // mapped, so its own range needs fixing up too. Otherwise the leaf + // entry mapping it keeps the pre-relocation VA and the root is + // unmapped. + reloc_regions.insert( + page_table_fixup.gpa..=page_table_fixup.gpa + page_table_fixup.size - 1, + offset as i64, + ); let page_table = page_table_fixup .build(offset as i64, reloc_regions, page_table_cpu_state) .map_err(Error::PageTableBuilder)?; diff --git a/vm/loader/src/paravisor.rs b/vm/loader/src/paravisor.rs index 3518e36b73..6207106e39 100644 --- a/vm/loader/src/paravisor.rs +++ b/vm/loader/src/paravisor.rs @@ -409,6 +409,12 @@ where )?; offset += heap_size; + // Some loaders only fix up identity map entries that overlap the relocation + // region, so keep the page table region in the same large page as it. + if offset.is_multiple_of(X64_LARGE_PAGE_SIZE) { + offset += HV_PAGE_SIZE; + } + // The end of memory used by the loader, excluding pagetables. let end_of_underhill_mem = offset; @@ -1155,6 +1161,12 @@ where )?; next_addr += heap_size; + // Some loaders only fix up identity map entries that overlap the relocation + // region, so keep the page table region in the same large page as it. + if next_addr.is_multiple_of(u64::from(Arm64PageSize::Large)) { + next_addr += HV_PAGE_SIZE; + } + // The end of memory used by the loader, excluding pagetables. let end_of_underhill_mem = next_addr;