From edd7ad04b573f081de7ac0d6c3ffc21e3aecbb9c Mon Sep 17 00:00:00 2001 From: John Starks Date: Thu, 14 May 2026 18:33:24 -0700 Subject: [PATCH 1/4] Add support for running UEFI without VMBus Some VM configurations do not require VMBus, but the UEFI firmware currently assumes it is always present. This causes issues when the host does not provide MMIO gap configuration, and leaves unnecessary VMBus devices in the ACPI namespace. Introduce a VmbusDisabled flag in the UEFI_CONFIG_FLAGS blob that the host can set to indicate VMBus is not available. The flag uses disabled polarity so that the default zero value in reserved bits preserves existing behavior. This is exposed as PcdVmbusEnabled internally, which gates VMBus driver initialization, DSDT VMBus device presence, and MMIO gap HOB publication. The MMIO ranges blob is no longer required when VMBus is disabled, since those ranges are only used for VMBus device assignment. On AARCH64, the MMU setup falls back to a flat memory map when no MMIO gap information is provided, since the existing code assumes MMIO ranges are always available to carve out of the address space. Hyper-V enlightenments (hypercalls, synthetic timers) remain functional regardless of VMBus state, as they operate independently via the hypervisor interface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf | 1 + MsvmPkg/AcpiPlatformDxe/Dsdt.c | 2 + MsvmPkg/AcpiTables/Dsdt.asl | 144 +++++++++++--------- MsvmPkg/Include/BiosInterface.h | 4 +- MsvmPkg/MsvmPkg.dec | 1 + MsvmPkg/MsvmPkgAARCH64.dsc | 1 + MsvmPkg/MsvmPkgX64.dsc | 1 + MsvmPkg/PlatformPei/AArch64/Mmu.c | 25 ++++ MsvmPkg/PlatformPei/Config.c | 11 ++ MsvmPkg/PlatformPei/Platform.c | 71 +++++----- MsvmPkg/PlatformPei/PlatformPei.inf | 1 + MsvmPkg/VmbusDxe/VmbusDxe.inf | 1 + MsvmPkg/VmbusDxe/VmbusRoot.c | 6 + 13 files changed, 166 insertions(+), 103 deletions(-) diff --git a/MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf index 02ee5827d4..e10f9c542d 100644 --- a/MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf +++ b/MsvmPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf @@ -95,6 +95,7 @@ gMsvmPkgTokenSpaceGuid.PcdHmatSize ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdTpmEnabled ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdVirtualBatteryEnabled ## CONSUMES + gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdWatchdogEnabled ## CONSUMES [Pcd.X64] diff --git a/MsvmPkg/AcpiPlatformDxe/Dsdt.c b/MsvmPkg/AcpiPlatformDxe/Dsdt.c index 224537c1c6..1d62bac3ab 100644 --- a/MsvmPkg/AcpiPlatformDxe/Dsdt.c +++ b/MsvmPkg/AcpiPlatformDxe/Dsdt.c @@ -33,6 +33,7 @@ typedef struct _DSDT_AML_DATA UINT8 ProcIdleEnabled; UINT8 CxlMemoryEnabled; UINT16 NvdimmCount; + UINT8 VmbusEnabled; } DSDT_AML_DATA; typedef struct _DSDT_AML_DESCRIPTOR @@ -138,6 +139,7 @@ Return Value: data->ProcIdleEnabled = PcdGetBool(PcdProcIdleEnabled); data->CxlMemoryEnabled = PcdGetBool(PcdCxlMemoryEnabled); data->NvdimmCount = PcdGet16(PcdNvdimmCount); + data->VmbusEnabled = PcdGetBool(PcdVmbusEnabled); DEBUG((DEBUG_VERBOSE, "--- %a: Mmio1Start 0x%lx\n", __func__, data->Mmio1Start)); DEBUG((DEBUG_VERBOSE, "--- %a: Mmio1Length 0x%lx\n", __func__, data->Mmio1Length)); diff --git a/MsvmPkg/AcpiTables/Dsdt.asl b/MsvmPkg/AcpiTables/Dsdt.asl index abd5c3a0ba..aa0299c9af 100644 --- a/MsvmPkg/AcpiTables/Dsdt.asl +++ b/MsvmPkg/AcpiTables/Dsdt.asl @@ -63,6 +63,7 @@ DefinitionBlock ( PADE,8, // Processor Aggregator Device enabled/disabled CCFG,8, // CXL memory support enabled/disabled NCNT,16, // NVDIMM count + VCFG,8, // VMBus enabled/disabled } // Supported machine sleep states ========================================= @@ -166,19 +167,23 @@ DefinitionBlock ( Method(_INI, 0) { - // Update the DWORDMemory resource descriptor with the low MMIO region. - Store(MG2B, MIN6) - Store(MG2L, LEN6) - Store(MG2L, Local0) - Add(MIN6, Decrement(Local0), MAX6) + // Only populate MMIO resources when VMBus is enabled. + If(LGreater(VCFG, 0)) + { + // Update the DWORDMemory resource descriptor with the low MMIO region. + Store(MG2B, MIN6) + Store(MG2L, LEN6) + Store(MG2L, Local0) + Add(MIN6, Decrement(Local0), MAX6) - // Update the QWORDMemory resource descriptor with the high MMIO region. - ShiftLeft (HMIB, 20, Local1) - ShiftLeft (HMIL, 20, Local2) - Store(Local1, MIN7) - Store(Local2, LEN7) - Store(Local2, Local0) - Add(MIN7, Decrement(Local0), MAX7) + // Update the QWORDMemory resource descriptor with the high MMIO region. + ShiftLeft (HMIB, 20, Local1) + ShiftLeft (HMIL, 20, Local2) + Store(Local1, MIN7) + Store(Local2, LEN7) + Store(Local2, Local0) + Add(MIN7, Decrement(Local0), MAX7) + } } } @@ -306,74 +311,77 @@ DefinitionBlock ( // VMBus ================================================================== - Device(\_SB.VMOD.VMBS) + If(LGreater(VCFG, 0)) { - Name(STA, 0xF) - Name(_ADR, 0x00) + Device(\_SB.VMOD.VMBS) + { + Name(STA, 0xF) + Name(_ADR, 0x00) #if defined(_DSDT_ARM_) - Name(_CCA, One) + Name(_CCA, One) #endif - Name(_DDN, "VMBUS") - Name(_HID, "MSFT1000") - Name(_CID, "VMBus") - Name(_UID, 0) - Method(_DIS, 0) { And(STA, 0xD, STA) } - Method(_PS0, 0) { Or(STA, 0xF, STA) } - Method(_STA, 0) - { - return(STA) - } - - // Older versions of this DSDT implemented _PS3 improperly, as: - // Name(_PS3, 0) - // This is intentionally a do-nothing method in case any version of Windows requires _PS3 to be implemented - - Method(_PS3, 0) { return(STA) } - - // TODO: SPIs are not available to the guest on AARCH64, which is what - // PcdVmbusVector is currently defined as. Supposedly it should use a PPI, - // but those are strange because they're reserved for hypervisor devices. - // - // Windows doesn't boot when VmBus is given an SPI, since it's unable to - // allocate any since none exist in guests. Thus, leave it out on AARCH64 - // for now. - // - // Linux may need this field if it's not hardcoded, unsure. - // - // Additionally, no Interrupt-Signaled event devices currently work either, - // due to SPIs not being available to guests. - Name(_CRS, + Name(_DDN, "VMBUS") + Name(_HID, "MSFT1000") + Name(_CID, "VMBus") + Name(_UID, 0) + Method(_DIS, 0) { And(STA, 0xD, STA) } + Method(_PS0, 0) { Or(STA, 0xF, STA) } + Method(_STA, 0) + { + return(STA) + } - // Include an interrupt resource so that Linux VMs can get IDT - // entries. - // - // N.B. All Windows VMs that support UEFI also support - // getting IDT entries via other mechanisms, so this is not - // necessary for Windows. + // Older versions of this DSDT implemented _PS3 improperly, as: + // Name(_PS3, 0) + // This is intentionally a do-nothing method in case any version of Windows requires _PS3 to be implemented - ResourceTemplate() - { + Method(_PS3, 0) { return(STA) } + + // TODO: SPIs are not available to the guest on AARCH64, which is what + // PcdVmbusVector is currently defined as. Supposedly it should use a PPI, + // but those are strange because they're reserved for hypervisor devices. + // + // Windows doesn't boot when VmBus is given an SPI, since it's unable to + // allocate any since none exist in guests. Thus, leave it out on AARCH64 + // for now. + // + // Linux may need this field if it's not hardcoded, unsure. + // + // Additionally, no Interrupt-Signaled event devices currently work either, + // due to SPIs not being available to guests. + Name(_CRS, + + // Include an interrupt resource so that Linux VMs can get IDT + // entries. + // + // N.B. All Windows VMs that support UEFI also support + // getting IDT entries via other mechanisms, so this is not + // necessary for Windows. + + ResourceTemplate() + { #if defined(_DSDT_INTEL_) - // Older Linux kernels like RHEL/CentOS don't seem to be able to - // parse the new Extended Interrupt Descriptor resource type (see ACPI Section 6.4.3.6), - // so we instead use the old legacy IRQ description which - // becomes the short form of Interrupt Descriptor (ACPI Section 5.4.2.1) - // which only supports legacy PIC devices to describe up to 15 - // interrupts. VMBUS is interrupt 5 on X64, so this is okay. - IRQ(Edge,ActiveHigh,Exclusive) - {FixedPcdGet8(PcdVmbusVector)} + // Older Linux kernels like RHEL/CentOS don't seem to be able to + // parse the new Extended Interrupt Descriptor resource type (see ACPI Section 6.4.3.6), + // so we instead use the old legacy IRQ description which + // becomes the short form of Interrupt Descriptor (ACPI Section 5.4.2.1) + // which only supports legacy PIC devices to describe up to 15 + // interrupts. VMBUS is interrupt 5 on X64, so this is okay. + IRQ(Edge,ActiveHigh,Exclusive) + {FixedPcdGet8(PcdVmbusVector)} #else - // On AArch64, we select a PPI (16) because Linux expects it to - // be available to all CPUs. - Interrupt(ResourceConsumer, Edge, ActiveHigh, Exclusive) - {FixedPcdGet8(PcdVmbusVector)} + // On AArch64, we select a PPI (16) because Linux expects it to + // be available to all CPUs. + Interrupt(ResourceConsumer, Edge, ActiveHigh, Exclusive) + {FixedPcdGet8(PcdVmbusVector)} #endif - } - ) + } + ) + } } // TPM ==================================================================== diff --git a/MsvmPkg/Include/BiosInterface.h b/MsvmPkg/Include/BiosInterface.h index 72e6d6f9ec..42951361b4 100644 --- a/MsvmPkg/Include/BiosInterface.h +++ b/MsvmPkg/Include/BiosInterface.h @@ -789,7 +789,9 @@ typedef struct _UEFI_CONFIG_FLAGS UINT64 Dhcp6DuidTypeLlt : 1; UINT64 CxlMemoryEnabled : 1; UINT64 MtrrsInitializedAtLoad : 1; - UINT64 Reserved:35; + UINT64 HvSintEnabled : 1; // Reserved; used by other codebase. + UINT64 VmbusDisabled : 1; + UINT64 Reserved:33; } Flags; } UEFI_CONFIG_FLAGS; diff --git a/MsvmPkg/MsvmPkg.dec b/MsvmPkg/MsvmPkg.dec index b326956e97..8ec8f9b7a4 100644 --- a/MsvmPkg/MsvmPkg.dec +++ b/MsvmPkg/MsvmPkg.dec @@ -298,6 +298,7 @@ gMsvmPkgTokenSpaceGuid.PcdHostEmulatorsWhenHardwareIsolated|FALSE|BOOLEAN|0x6064 gMsvmPkgTokenSpaceGuid.PcdTpmLocalityRegsEnabled|FALSE|BOOLEAN|0x6065 gMsvmPkgTokenSpaceGuid.PcdMtrrsInitializedAtLoad|FALSE|BOOLEAN|0x6067 + gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled|TRUE|BOOLEAN|0x6068 # UEFI_CONFIG_PROCESSOR_INFORMATION gMsvmPkgTokenSpaceGuid.PcdProcessorCount|0x0|UINT32|0x6032 diff --git a/MsvmPkg/MsvmPkgAARCH64.dsc b/MsvmPkg/MsvmPkgAARCH64.dsc index 48dccb27c1..5d3d598193 100644 --- a/MsvmPkg/MsvmPkgAARCH64.dsc +++ b/MsvmPkg/MsvmPkgAARCH64.dsc @@ -697,6 +697,7 @@ gMsvmPkgTokenSpaceGuid.PcdWatchdogEnabled|FALSE gMsvmPkgTokenSpaceGuid.PcdHostEmulatorsWhenHardwareIsolated|FALSE gMsvmPkgTokenSpaceGuid.PcdTpmLocalityRegsEnabled|FALSE + gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled|TRUE # UEFI_CONFIG_PROCESSOR_INFORMATION gMsvmPkgTokenSpaceGuid.PcdProcessorCount|0x0 diff --git a/MsvmPkg/MsvmPkgX64.dsc b/MsvmPkg/MsvmPkgX64.dsc index a62c04c226..2523eb8be1 100644 --- a/MsvmPkg/MsvmPkgX64.dsc +++ b/MsvmPkg/MsvmPkgX64.dsc @@ -715,6 +715,7 @@ gMsvmPkgTokenSpaceGuid.PcdWatchdogEnabled|FALSE gMsvmPkgTokenSpaceGuid.PcdHostEmulatorsWhenHardwareIsolated|FALSE gMsvmPkgTokenSpaceGuid.PcdTpmLocalityRegsEnabled|FALSE + gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled|TRUE # UEFI_CONFIG_PROCESSOR_INFORMATION gMsvmPkgTokenSpaceGuid.PcdProcessorCount|0x0 diff --git a/MsvmPkg/PlatformPei/AArch64/Mmu.c b/MsvmPkg/PlatformPei/AArch64/Mmu.c index 093beaf4cc..c4578a5af0 100644 --- a/MsvmPkg/PlatformPei/AArch64/Mmu.c +++ b/MsvmPkg/PlatformPei/AArch64/Mmu.c @@ -405,6 +405,30 @@ ConfigureMmu( #define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 6 ARM_MEMORY_REGION_DESCRIPTOR virtualMemoryTable[MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS]; + // + // When VMBus is disabled, there are no MMIO gaps to carve out. Use a + // simple flat memory map covering the entire address space as write-back. + // This is safe because the hypervisor's stage-2 page tables enforce the + // correct memory type for device regions regardless of stage-1 attributes. + // TODO: Consider adopting a more precise strategy (similar to QEMU virt) + // that only maps known RAM and leaves device regions unmapped or marked + // as DEVICE in stage-1. + // + if (!PcdGetBool(PcdVmbusEnabled)) + { + virtualMemoryTable[0].PhysicalBase = 0; + virtualMemoryTable[0].VirtualBase = 0; + virtualMemoryTable[0].Length = MaxAddress + 1; + virtualMemoryTable[0].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + + virtualMemoryTable[1].PhysicalBase = 0; + virtualMemoryTable[1].VirtualBase = 0; + virtualMemoryTable[1].Length = 0; + virtualMemoryTable[1].Attributes = 0; + + goto SetupMmu; + } + // // Convert PCD page counts to byte addresses/sizes using safe // multiplication to catch overflow from host-supplied values. @@ -504,6 +528,7 @@ ConfigureMmu( virtualMemoryTable[5].Length = 0; virtualMemoryTable[5].Attributes = 0; +SetupMmu: // Lookup the Table Level to get the information LookupAddresstoRootTable(MaxAddress, &T0SZ, &RootTableEntryCount); diff --git a/MsvmPkg/PlatformPei/Config.c b/MsvmPkg/PlatformPei/Config.c index 6532196828..91a940bf5d 100644 --- a/MsvmPkg/PlatformPei/Config.c +++ b/MsvmPkg/PlatformPei/Config.c @@ -762,6 +762,7 @@ DebugDumpUefiConfigStruct( DEBUG((DEBUG_VERBOSE, "\tWatchdogEnabled: %u\n", flags->Flags.WatchdogEnabled)); DEBUG((DEBUG_VERBOSE, "\tTpmLocalityRegsEnabled: %u\n", flags->Flags.TpmLocalityRegsEnabled)); DEBUG((DEBUG_VERBOSE, "\tMtrrsInitializedAtLoad: %u\n", flags->Flags.MtrrsInitializedAtLoad)); + DEBUG((DEBUG_VERBOSE, "\tVmbusDisabled: %u\n", flags->Flags.VmbusDisabled)); break; } case UefiConfigProcessorInformation: @@ -941,6 +942,7 @@ ConfigSetUefiConfigFlags( PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdWatchdogEnabled, (UINT8) ConfigFlags->Flags.WatchdogEnabled)); PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdTpmLocalityRegsEnabled, (UINT8) ConfigFlags->Flags.TpmLocalityRegsEnabled)); PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdMtrrsInitializedAtLoad, (UINT8) ConfigFlags->Flags.MtrrsInitializedAtLoad)); + PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdVmbusEnabled, ConfigFlags->Flags.VmbusDisabled ? FALSE : TRUE)); // // If memory protections are enabled, configure the value into the HOB. @@ -1794,6 +1796,15 @@ Return Value: header = (UEFI_CONFIG_HEADER*) ((UINT64) header + header->Length); } + // + // If VMBus is disabled, MMIO ranges are not required since they are + // VMBus MMIO gaps. + // + if (!PcdGetBool(PcdVmbusEnabled)) + { + requiredStructures.UefiConfigMmioRanges = 1; + } + if (requiredStructures.AsUINT64 != AllStructuresFound) { DEBUG((DEBUG_ERROR, "Missing required structures, found structures: 0x%x\n", requiredStructures.AsUINT64)); diff --git a/MsvmPkg/PlatformPei/Platform.c b/MsvmPkg/PlatformPei/Platform.c index e513a8be37..5bf08e5dd2 100644 --- a/MsvmPkg/PlatformPei/Platform.c +++ b/MsvmPkg/PlatformPei/Platform.c @@ -701,45 +701,48 @@ Return Value: #endif // - // Low and high MMIO range + // Low and high MMIO range. Only present when VMBus is enabled. // + if (PcdGetBool(PcdVmbusEnabled)) + { #if defined (MDE_CPU_X64) - HobAddMmioRange( - PcdGet64(PcdLowMmioGapBasePageNumber) * SIZE_4KB, - PcdGet64(PcdLowMmioGapSizeInPages) * SIZE_4KB - ); + HobAddMmioRange( + PcdGet64(PcdLowMmioGapBasePageNumber) * SIZE_4KB, + PcdGet64(PcdLowMmioGapSizeInPages) * SIZE_4KB + ); #elif defined(MDE_CPU_AARCH64) - // - // For ARM64 we are still using the BiosDevice for runtime services. - // However the registers are now in MMIO space instead of IO space. Therefore the - // addresses need to be translated after the guest calls SetVirtualAddressMap. - // To have the address range included with the guest's call to SetVirtualAddressMap - // the range has to be declared as DXE runtime memory. That has to be done in DXE phase - // by a driver so the range can't be declared as MMIO here. Therefore leave that page - // out of this early general platform declaration. - // - UINT64 GapBase = PcdGet32(PcdBiosBaseAddress); - UINT64 GapSize = SIZE_4KB; - UINT64 FirstRangeBase = PcdGet64(PcdLowMmioGapBasePageNumber) * SIZE_4KB; - UINT64 FirstRangeSize = GapBase - FirstRangeBase; - UINT64 SecondRangeBase = FirstRangeBase + FirstRangeSize + GapSize; - UINT64 SecondRangeSize = (PcdGet64(PcdLowMmioGapSizeInPages) * SIZE_4KB) - - (FirstRangeSize + GapSize); - - HobAddMmioRange( - FirstRangeBase, - FirstRangeSize - ); + // + // For ARM64 we are still using the BiosDevice for runtime services. + // However the registers are now in MMIO space instead of IO space. Therefore the + // addresses need to be translated after the guest calls SetVirtualAddressMap. + // To have the address range included with the guest's call to SetVirtualAddressMap + // the range has to be declared as DXE runtime memory. That has to be done in DXE phase + // by a driver so the range can't be declared as MMIO here. Therefore leave that page + // out of this early general platform declaration. + // + UINT64 GapBase = PcdGet32(PcdBiosBaseAddress); + UINT64 GapSize = SIZE_4KB; + UINT64 FirstRangeBase = PcdGet64(PcdLowMmioGapBasePageNumber) * SIZE_4KB; + UINT64 FirstRangeSize = GapBase - FirstRangeBase; + UINT64 SecondRangeBase = FirstRangeBase + FirstRangeSize + GapSize; + UINT64 SecondRangeSize = (PcdGet64(PcdLowMmioGapSizeInPages) * SIZE_4KB) - + (FirstRangeSize + GapSize); + + HobAddMmioRange( + FirstRangeBase, + FirstRangeSize + ); - HobAddMmioRange( - SecondRangeBase, - SecondRangeSize - ); + HobAddMmioRange( + SecondRangeBase, + SecondRangeSize + ); #endif - HobAddMmioRange( - PcdGet64(PcdHighMmioGapBasePageNumber) * SIZE_4KB, - PcdGet64(PcdHighMmioGapSizeInPages) * SIZE_4KB - ); + HobAddMmioRange( + PcdGet64(PcdHighMmioGapBasePageNumber) * SIZE_4KB, + PcdGet64(PcdHighMmioGapSizeInPages) * SIZE_4KB + ); + } // // Read PcieBarApertures first -- these determine which bridges UEFI diff --git a/MsvmPkg/PlatformPei/PlatformPei.inf b/MsvmPkg/PlatformPei/PlatformPei.inf index 3fd7c92cc0..7eb5b21818 100644 --- a/MsvmPkg/PlatformPei/PlatformPei.inf +++ b/MsvmPkg/PlatformPei/PlatformPei.inf @@ -196,6 +196,7 @@ gMsvmPkgTokenSpaceGuid.PcdHostEmulatorsWhenHardwareIsolated gMsvmPkgTokenSpaceGuid.PcdTpmLocalityRegsEnabled gMsvmPkgTokenSpaceGuid.PcdMtrrsInitializedAtLoad + gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled gMsvmPkgTokenSpaceGuid.PcdPcieBarAperturesPtr gMsvmPkgTokenSpaceGuid.PcdPcieBarAperturesSize diff --git a/MsvmPkg/VmbusDxe/VmbusDxe.inf b/MsvmPkg/VmbusDxe/VmbusDxe.inf index 0e09956d11..276bbdfa8c 100644 --- a/MsvmPkg/VmbusDxe/VmbusDxe.inf +++ b/MsvmPkg/VmbusDxe/VmbusDxe.inf @@ -56,6 +56,7 @@ gInternalEventServicesProtocolGuid ## CONSUMES [Pcd] + gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdVmbusSintVector ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdVmbusSintIndex ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdIsolationSharedGpaBoundary ## CONSUMES diff --git a/MsvmPkg/VmbusDxe/VmbusRoot.c b/MsvmPkg/VmbusDxe/VmbusRoot.c index 9aa1662b37..86522fcc47 100644 --- a/MsvmPkg/VmbusDxe/VmbusRoot.c +++ b/MsvmPkg/VmbusDxe/VmbusRoot.c @@ -2282,6 +2282,12 @@ VmbusDriverInitialize ( DEBUG((DEBUG_VERBOSE, ">>> %a\n", __func__)); + if (!PcdGetBool(PcdVmbusEnabled)) + { + DEBUG((DEBUG_INFO, "VMBus is disabled by configuration, not starting VMBus driver.\n")); + return EFI_UNSUPPORTED; + } + mVmbusImageHandle = ImageHandle; // From 86b41fd847f78de045a1abb20fc2ab284f0eaa66 Mon Sep 17 00:00:00 2001 From: John Starks Date: Fri, 15 May 2026 11:58:16 -0700 Subject: [PATCH 2/4] feedback --- MsvmPkg/AcpiTables/Dsdt.asl | 55 +++++++++++++++++++---------------- MsvmPkg/PlatformPei/Config.c | 7 +++-- MsvmPkg/VmbusDxe/VmbusDxe.inf | 2 +- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/MsvmPkg/AcpiTables/Dsdt.asl b/MsvmPkg/AcpiTables/Dsdt.asl index aa0299c9af..210f439a23 100644 --- a/MsvmPkg/AcpiTables/Dsdt.asl +++ b/MsvmPkg/AcpiTables/Dsdt.asl @@ -141,34 +141,39 @@ DefinitionBlock ( { Name(_HID, "ACPI0004") Name(_UID, 0) - Name(_CRS, - ResourceTemplate() - { - // MMIO space below 4GB. - DWORDMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, - // Granularity Min Max Translation Range (Length = Max-Min+1) - 0, 0, 0, 0, 0,,, - MEM6) // Name declaration for this descriptor - // MMIO above 4GB - QWORDMemory( ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, - // Granularity Min Max Translation Range (Length = Max-Min+1) - 0, 0, 0, 0, 0,,, - MEM7) - } - ) - CreateDwordField(_CRS, MEM6._MIN, MIN6) // Min - CreateDwordField(_CRS, MEM6._MAX, MAX6) // Max - CreateDwordField(_CRS, MEM6._LEN, LEN6) // Memory length + // + // MMIO resources are only needed when VMBus is enabled; they describe + // the VMBus MMIO gaps that the resource arbiter hands out to VMBus + // children (virtual PCI, SR-IOV, synthetic video, etc.). + // + If(LGreater(VCFG, 0)) + { + Name(_CRS, + ResourceTemplate() + { + // MMIO space below 4GB. + DWORDMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + // Granularity Min Max Translation Range (Length = Max-Min+1) + 0, 0, 0, 0, 0,,, + MEM6) // Name declaration for this descriptor + // MMIO above 4GB + QWORDMemory( ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + // Granularity Min Max Translation Range (Length = Max-Min+1) + 0, 0, 0, 0, 0,,, + MEM7) + } + ) - CreateQwordField(_CRS, MEM7._MIN, MIN7) // Min - CreateQwordField(_CRS, MEM7._MAX, MAX7) // Max - CreateQwordField(_CRS, MEM7._LEN, LEN7) // Memory length + CreateDwordField(_CRS, MEM6._MIN, MIN6) // Min + CreateDwordField(_CRS, MEM6._MAX, MAX6) // Max + CreateDwordField(_CRS, MEM6._LEN, LEN6) // Memory length - Method(_INI, 0) - { - // Only populate MMIO resources when VMBus is enabled. - If(LGreater(VCFG, 0)) + CreateQwordField(_CRS, MEM7._MIN, MIN7) // Min + CreateQwordField(_CRS, MEM7._MAX, MAX7) // Max + CreateQwordField(_CRS, MEM7._LEN, LEN7) // Memory length + + Method(_INI, 0) { // Update the DWORDMemory resource descriptor with the low MMIO region. Store(MG2B, MIN6) diff --git a/MsvmPkg/PlatformPei/Config.c b/MsvmPkg/PlatformPei/Config.c index 91a940bf5d..41c8331f17 100644 --- a/MsvmPkg/PlatformPei/Config.c +++ b/MsvmPkg/PlatformPei/Config.c @@ -942,7 +942,7 @@ ConfigSetUefiConfigFlags( PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdWatchdogEnabled, (UINT8) ConfigFlags->Flags.WatchdogEnabled)); PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdTpmLocalityRegsEnabled, (UINT8) ConfigFlags->Flags.TpmLocalityRegsEnabled)); PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdMtrrsInitializedAtLoad, (UINT8) ConfigFlags->Flags.MtrrsInitializedAtLoad)); - PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdVmbusEnabled, ConfigFlags->Flags.VmbusDisabled ? FALSE : TRUE)); + PEI_FAIL_FAST_IF_FAILED(PcdSetBoolS(PcdVmbusEnabled, !ConfigFlags->Flags.VmbusDisabled)); // // If memory protections are enabled, configure the value into the HOB. @@ -1797,8 +1797,9 @@ Return Value: } // - // If VMBus is disabled, MMIO ranges are not required since they are - // VMBus MMIO gaps. + // If VMBus is disabled, MMIO ranges are not required since they describe + // VMBus MMIO gaps. Mark the structure as found so the validation below + // does not fail. // if (!PcdGetBool(PcdVmbusEnabled)) { diff --git a/MsvmPkg/VmbusDxe/VmbusDxe.inf b/MsvmPkg/VmbusDxe/VmbusDxe.inf index 276bbdfa8c..ffa71195fa 100644 --- a/MsvmPkg/VmbusDxe/VmbusDxe.inf +++ b/MsvmPkg/VmbusDxe/VmbusDxe.inf @@ -56,7 +56,7 @@ gInternalEventServicesProtocolGuid ## CONSUMES [Pcd] - gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled ## CONSUMES + gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdVmbusSintVector ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdVmbusSintIndex ## CONSUMES gMsvmPkgTokenSpaceGuid.PcdIsolationSharedGpaBoundary ## CONSUMES From 4a6809d29396ab8aaeb36ddb0556d503c77edac2 Mon Sep 17 00:00:00 2001 From: John Starks Date: Mon, 18 May 2026 09:56:25 -0700 Subject: [PATCH 3/4] Make MMIO blob always required; high MMIO optional by size The MMIO configuration blob is now required regardless of VMBus state, since chipset devices (e.g. TPM) need low MMIO even without VMBus. Key changes: - Remove the VMBus-disabled exemption for MMIO blob requirement - Gate MMIO validation, HOB declarations, DSDT population, and ARM MMU map construction on actual MMIO sizes (zero = not present) rather than VMBus enabled/disabled state - High MMIO size can be zero (optional) even with VMBus enabled - DSDT _CRS always declared; per ACPI 6.5 sec 6.4.3.5, a length-zero resource descriptor is ignored by the OS for allocation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- MsvmPkg/AcpiTables/Dsdt.asl | 62 +++++++-------- MsvmPkg/PlatformPei/AArch64/Mmu.c | 123 +++++++++++++----------------- MsvmPkg/PlatformPei/Config.c | 54 ++++++------- MsvmPkg/PlatformPei/Platform.c | 10 ++- 4 files changed, 116 insertions(+), 133 deletions(-) diff --git a/MsvmPkg/AcpiTables/Dsdt.asl b/MsvmPkg/AcpiTables/Dsdt.asl index 210f439a23..12a6822e50 100644 --- a/MsvmPkg/AcpiTables/Dsdt.asl +++ b/MsvmPkg/AcpiTables/Dsdt.asl @@ -142,46 +142,46 @@ DefinitionBlock ( Name(_HID, "ACPI0004") Name(_UID, 0) - // - // MMIO resources are only needed when VMBus is enabled; they describe - // the VMBus MMIO gaps that the resource arbiter hands out to VMBus - // children (virtual PCI, SR-IOV, synthetic video, etc.). - // - If(LGreater(VCFG, 0)) - { - Name(_CRS, - ResourceTemplate() - { - // MMIO space below 4GB. - DWORDMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, - // Granularity Min Max Translation Range (Length = Max-Min+1) - 0, 0, 0, 0, 0,,, - MEM6) // Name declaration for this descriptor - // MMIO above 4GB - QWORDMemory( ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, - // Granularity Min Max Translation Range (Length = Max-Min+1) - 0, 0, 0, 0, 0,,, - MEM7) - } - ) + Name(_CRS, + ResourceTemplate() + { + // MMIO space below 4GB. + DWORDMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + // Granularity Min Max Translation Range (Length = Max-Min+1) + 0, 0, 0, 0, 0,,, + MEM6) // Name declaration for this descriptor + // MMIO above 4GB + QWORDMemory( ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + // Granularity Min Max Translation Range (Length = Max-Min+1) + 0, 0, 0, 0, 0,,, + MEM7) + } + ) - CreateDwordField(_CRS, MEM6._MIN, MIN6) // Min - CreateDwordField(_CRS, MEM6._MAX, MAX6) // Max - CreateDwordField(_CRS, MEM6._LEN, LEN6) // Memory length + CreateDwordField(_CRS, MEM6._MIN, MIN6) // Min + CreateDwordField(_CRS, MEM6._MAX, MAX6) // Max + CreateDwordField(_CRS, MEM6._LEN, LEN6) // Memory length - CreateQwordField(_CRS, MEM7._MIN, MIN7) // Min - CreateQwordField(_CRS, MEM7._MAX, MAX7) // Max - CreateQwordField(_CRS, MEM7._LEN, LEN7) // Memory length + CreateQwordField(_CRS, MEM7._MIN, MIN7) // Min + CreateQwordField(_CRS, MEM7._MAX, MAX7) // Max + CreateQwordField(_CRS, MEM7._LEN, LEN7) // Memory length - Method(_INI, 0) + Method(_INI, 0) + { + // Update the DWORDMemory descriptor with the low MMIO region + // only if the region has nonzero size. + If(LGreater(MG2L, 0)) { - // Update the DWORDMemory resource descriptor with the low MMIO region. Store(MG2B, MIN6) Store(MG2L, LEN6) Store(MG2L, Local0) Add(MIN6, Decrement(Local0), MAX6) + } - // Update the QWORDMemory resource descriptor with the high MMIO region. + // Update the QWORDMemory descriptor with the high MMIO region + // only if the region has nonzero size. + If(LGreater(HMIL, 0)) + { ShiftLeft (HMIB, 20, Local1) ShiftLeft (HMIL, 20, Local2) Store(Local1, MIN7) diff --git a/MsvmPkg/PlatformPei/AArch64/Mmu.c b/MsvmPkg/PlatformPei/AArch64/Mmu.c index c4578a5af0..898adafb02 100644 --- a/MsvmPkg/PlatformPei/AArch64/Mmu.c +++ b/MsvmPkg/PlatformPei/AArch64/Mmu.c @@ -404,30 +404,7 @@ ConfigureMmu( UINT64 highMmioSize; #define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 6 ARM_MEMORY_REGION_DESCRIPTOR virtualMemoryTable[MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS]; - - // - // When VMBus is disabled, there are no MMIO gaps to carve out. Use a - // simple flat memory map covering the entire address space as write-back. - // This is safe because the hypervisor's stage-2 page tables enforce the - // correct memory type for device regions regardless of stage-1 attributes. - // TODO: Consider adopting a more precise strategy (similar to QEMU virt) - // that only maps known RAM and leaves device regions unmapped or marked - // as DEVICE in stage-1. - // - if (!PcdGetBool(PcdVmbusEnabled)) - { - virtualMemoryTable[0].PhysicalBase = 0; - virtualMemoryTable[0].VirtualBase = 0; - virtualMemoryTable[0].Length = MaxAddress + 1; - virtualMemoryTable[0].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; - - virtualMemoryTable[1].PhysicalBase = 0; - virtualMemoryTable[1].VirtualBase = 0; - virtualMemoryTable[1].Length = 0; - virtualMemoryTable[1].Attributes = 0; - - goto SetupMmu; - } + UINTN index = 0; // // Convert PCD page counts to byte addresses/sizes using safe @@ -447,10 +424,8 @@ ConfigureMmu( // // Validate that MMIO regions fit within the physical address space. - // The host may provide MMIO ranges that extend beyond the CPU's - // physical address width, which would cause page table entries for - // unmappable addresses. // + if (highMmioSize > 0) { UINT64 highMmioEnd; if (RETURN_ERROR(SafeUint64Add(highMmioBaseAddress, highMmioSize, &highMmioEnd))) @@ -471,64 +446,72 @@ ConfigureMmu( } // - // Fill table that drives the mmu setup functions. + // Build the memory map based on which MMIO gaps are present. // - // From zero to beginning of low MMIO gap. - virtualMemoryTable[0].PhysicalBase = 0; - virtualMemoryTable[0].VirtualBase = virtualMemoryTable[0].PhysicalBase; - virtualMemoryTable[0].Length = (SIZE_4GB - lowMmioSize); - virtualMemoryTable[0].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; - - // First MMIO gap. - virtualMemoryTable[1].PhysicalBase = virtualMemoryTable[0].PhysicalBase + virtualMemoryTable[0].Length; - virtualMemoryTable[1].VirtualBase = virtualMemoryTable[1].PhysicalBase; - virtualMemoryTable[1].Length = lowMmioSize; - virtualMemoryTable[1].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; - - // From 4GB to beginning of high MMIO gap. - virtualMemoryTable[2].PhysicalBase = virtualMemoryTable[1].PhysicalBase + virtualMemoryTable[1].Length; - virtualMemoryTable[2].VirtualBase = virtualMemoryTable[2].PhysicalBase; - - if (RETURN_ERROR(SafeUint64Sub(highMmioBaseAddress, virtualMemoryTable[2].PhysicalBase, &virtualMemoryTable[2].Length))) + + // From zero to beginning of low MMIO gap (or to 4GB if no low gap). + virtualMemoryTable[index].PhysicalBase = 0; + virtualMemoryTable[index].VirtualBase = 0; + virtualMemoryTable[index].Length = (SIZE_4GB - lowMmioSize); + virtualMemoryTable[index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + index++; + + // Low MMIO gap (only if nonzero size). + if (lowMmioSize > 0) { - DEBUG((DEBUG_ERROR, "ConfigureMmu: highMmioBaseAddress (0x%lx) < PhysicalBase (0x%lx)\n", - highMmioBaseAddress, virtualMemoryTable[2].PhysicalBase)); - ASSERT(FALSE); - return EFI_INVALID_PARAMETER; + virtualMemoryTable[index].PhysicalBase = virtualMemoryTable[index - 1].PhysicalBase + virtualMemoryTable[index - 1].Length; + virtualMemoryTable[index].VirtualBase = virtualMemoryTable[index].PhysicalBase; + virtualMemoryTable[index].Length = lowMmioSize; + virtualMemoryTable[index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; + index++; } - virtualMemoryTable[2].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + if (highMmioSize > 0) + { + // From end of low gap (or 4GB) to beginning of high MMIO gap. + virtualMemoryTable[index].PhysicalBase = virtualMemoryTable[index - 1].PhysicalBase + virtualMemoryTable[index - 1].Length; + virtualMemoryTable[index].VirtualBase = virtualMemoryTable[index].PhysicalBase; + + if (RETURN_ERROR(SafeUint64Sub(highMmioBaseAddress, virtualMemoryTable[index].PhysicalBase, &virtualMemoryTable[index].Length))) + { + DEBUG((DEBUG_ERROR, "ConfigureMmu: highMmioBaseAddress (0x%lx) < PhysicalBase (0x%lx)\n", + highMmioBaseAddress, virtualMemoryTable[index].PhysicalBase)); + ASSERT(FALSE); + return EFI_INVALID_PARAMETER; + } - // Second MMIO gap. - virtualMemoryTable[3].PhysicalBase = virtualMemoryTable[2].PhysicalBase + virtualMemoryTable[2].Length; - virtualMemoryTable[3].VirtualBase = virtualMemoryTable[3].PhysicalBase; - virtualMemoryTable[3].Length = highMmioSize; - virtualMemoryTable[3].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; + virtualMemoryTable[index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + index++; + + // High MMIO gap. + virtualMemoryTable[index].PhysicalBase = virtualMemoryTable[index - 1].PhysicalBase + virtualMemoryTable[index - 1].Length; + virtualMemoryTable[index].VirtualBase = virtualMemoryTable[index].PhysicalBase; + virtualMemoryTable[index].Length = highMmioSize; + virtualMemoryTable[index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; + index++; + } // To top of address space. - virtualMemoryTable[4].PhysicalBase = virtualMemoryTable[3].PhysicalBase + virtualMemoryTable[3].Length; - virtualMemoryTable[4].VirtualBase = virtualMemoryTable[4].PhysicalBase; + virtualMemoryTable[index].PhysicalBase = virtualMemoryTable[index - 1].PhysicalBase + virtualMemoryTable[index - 1].Length; + virtualMemoryTable[index].VirtualBase = virtualMemoryTable[index].PhysicalBase; - // - // Validate that the final region does not underflow. This should - // not happen given the MMIO validation above, but check defensively. - // - if (virtualMemoryTable[4].PhysicalBase > MaxAddress) + if (virtualMemoryTable[index].PhysicalBase > MaxAddress) { DEBUG((DEBUG_ERROR, "ConfigureMmu: PhysicalBase (0x%lx) > MaxAddress (0x%lx)\n", - virtualMemoryTable[4].PhysicalBase, MaxAddress)); + virtualMemoryTable[index].PhysicalBase, MaxAddress)); FAIL_FAST_UNEXPECTED_HOST_BEHAVIOR(); } - virtualMemoryTable[4].Length = (MaxAddress - virtualMemoryTable[4].PhysicalBase) + 1; - virtualMemoryTable[4].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + virtualMemoryTable[index].Length = (MaxAddress - virtualMemoryTable[index].PhysicalBase) + 1; + virtualMemoryTable[index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + index++; - virtualMemoryTable[5].PhysicalBase = 0; - virtualMemoryTable[5].VirtualBase = 0; - virtualMemoryTable[5].Length = 0; - virtualMemoryTable[5].Attributes = 0; + // End-of-table sentinel. + virtualMemoryTable[index].PhysicalBase = 0; + virtualMemoryTable[index].VirtualBase = 0; + virtualMemoryTable[index].Length = 0; + virtualMemoryTable[index].Attributes = 0; -SetupMmu: // Lookup the Table Level to get the information LookupAddresstoRootTable(MaxAddress, &T0SZ, &RootTableEntryCount); diff --git a/MsvmPkg/PlatformPei/Config.c b/MsvmPkg/PlatformPei/Config.c index 41c8331f17..fedec2e69d 100644 --- a/MsvmPkg/PlatformPei/Config.c +++ b/MsvmPkg/PlatformPei/Config.c @@ -1587,35 +1587,37 @@ Return Value: UINT64 highGapEnd; // - // Low gap size (in pages) must not exceed 4GB worth of pages, - // and the low gap must end at or before the 4GB boundary. + // Low gap: if size is nonzero, it must not exceed 4GB worth + // of pages, and must end at or before the 4GB boundary. // - if ((lowGapSize > (SIZE_4GB / SIZE_4KB)) || - RETURN_ERROR(SafeUint64Add(lowGapBase, lowGapSize, &lowGapEnd)) || - (lowGapEnd > (SIZE_4GB / SIZE_4KB))) + if (lowGapSize > 0) { - DEBUG((DEBUG_ERROR, "***Invalid low MMIO gap range\n")); - FAIL_FAST_UNEXPECTED_HOST_BEHAVIOR(); + if ((lowGapSize > (SIZE_4GB / SIZE_4KB)) || + RETURN_ERROR(SafeUint64Add(lowGapBase, lowGapSize, &lowGapEnd)) || + (lowGapEnd > (SIZE_4GB / SIZE_4KB))) + { + DEBUG((DEBUG_ERROR, "***Invalid low MMIO gap range\n")); + FAIL_FAST_UNEXPECTED_HOST_BEHAVIOR(); + } } // - // High gap must start at or above the 4GB boundary (in pages) - // to avoid unsigned underflow when computing memory region - // lengths in ConfigureMmu(). + // High gap: if size is nonzero, it must start at or above + // the 4GB boundary and must not overflow the address space. // - if (highGapBase < (SIZE_4GB / SIZE_4KB)) + if (highGapSize > 0) { - DEBUG((DEBUG_ERROR, "***Invalid high MMIO gap base below 4GB\n")); - FAIL_FAST_UNEXPECTED_HOST_BEHAVIOR(); - } + if (highGapBase < (SIZE_4GB / SIZE_4KB)) + { + DEBUG((DEBUG_ERROR, "***Invalid high MMIO gap base below 4GB\n")); + FAIL_FAST_UNEXPECTED_HOST_BEHAVIOR(); + } - // - // High gap must not overflow the address space. - // - if (RETURN_ERROR(SafeUint64Add(highGapBase, highGapSize, &highGapEnd))) - { - DEBUG((DEBUG_ERROR, "***High MMIO gap range overflow\n")); - FAIL_FAST_UNEXPECTED_HOST_BEHAVIOR(); + if (RETURN_ERROR(SafeUint64Add(highGapBase, highGapSize, &highGapEnd))) + { + DEBUG((DEBUG_ERROR, "***High MMIO gap range overflow\n")); + FAIL_FAST_UNEXPECTED_HOST_BEHAVIOR(); + } } } @@ -1796,15 +1798,7 @@ Return Value: header = (UEFI_CONFIG_HEADER*) ((UINT64) header + header->Length); } - // - // If VMBus is disabled, MMIO ranges are not required since they describe - // VMBus MMIO gaps. Mark the structure as found so the validation below - // does not fail. - // - if (!PcdGetBool(PcdVmbusEnabled)) - { - requiredStructures.UefiConfigMmioRanges = 1; - } + if (requiredStructures.AsUINT64 != AllStructuresFound) { diff --git a/MsvmPkg/PlatformPei/Platform.c b/MsvmPkg/PlatformPei/Platform.c index 5bf08e5dd2..fcdd8c78c7 100644 --- a/MsvmPkg/PlatformPei/Platform.c +++ b/MsvmPkg/PlatformPei/Platform.c @@ -701,9 +701,11 @@ Return Value: #endif // - // Low and high MMIO range. Only present when VMBus is enabled. + // Low and high MMIO ranges. Declared based on nonzero size rather than + // VMBus state, since chipset devices (e.g. TPM) may need low MMIO even + // without VMBus. // - if (PcdGetBool(PcdVmbusEnabled)) + if (PcdGet64(PcdLowMmioGapSizeInPages) > 0) { #if defined (MDE_CPU_X64) HobAddMmioRange( @@ -738,6 +740,10 @@ Return Value: SecondRangeSize ); #endif + } + + if (PcdGet64(PcdHighMmioGapSizeInPages) > 0) + { HobAddMmioRange( PcdGet64(PcdHighMmioGapBasePageNumber) * SIZE_4KB, PcdGet64(PcdHighMmioGapSizeInPages) * SIZE_4KB From 2001333854b0f1e08b7bf1e3c3bb9fde37e47bf9 Mon Sep 17 00:00:00 2001 From: John Starks Date: Wed, 20 May 2026 22:45:54 -0700 Subject: [PATCH 4/4] Fix no high MMIO and quiet vmbus noise --- .../DeviceBootManagerLib/DeviceBootManagerLib.c | 4 ++++ .../DeviceBootManagerLib/DeviceBootManagerLib.inf | 1 + MsvmPkg/PlatformPei/Config.c | 14 +++++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/MsvmPkg/Library/DeviceBootManagerLib/DeviceBootManagerLib.c b/MsvmPkg/Library/DeviceBootManagerLib/DeviceBootManagerLib.c index 470c4388b5..ca787830d9 100644 --- a/MsvmPkg/Library/DeviceBootManagerLib/DeviceBootManagerLib.c +++ b/MsvmPkg/Library/DeviceBootManagerLib/DeviceBootManagerLib.c @@ -425,6 +425,10 @@ DeviceBootManagerBeforeConsole ( *DevicePath = NULL; *PlatformConsoles = NULL; + if (!PcdGetBool(PcdVmbusEnabled)) { + goto Exit; + } + Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiVmbusProtocolGuid, diff --git a/MsvmPkg/Library/DeviceBootManagerLib/DeviceBootManagerLib.inf b/MsvmPkg/Library/DeviceBootManagerLib/DeviceBootManagerLib.inf index 40d7a5e73b..f52f9c937d 100644 --- a/MsvmPkg/Library/DeviceBootManagerLib/DeviceBootManagerLib.inf +++ b/MsvmPkg/Library/DeviceBootManagerLib/DeviceBootManagerLib.inf @@ -69,6 +69,7 @@ CONSTRUCTOR = DeviceBootManagerConstructor gMsvmPkgTokenSpaceGuid.PcdIsVmbfsBoot gMsvmPkgTokenSpaceGuid.PcdLogoFile gMsvmPkgTokenSpaceGuid.PcdPxeIpV6 + gMsvmPkgTokenSpaceGuid.PcdVmbusEnabled gMsvmPkgTokenSpaceGuid.PcdVpciBootEnabled [Depex] diff --git a/MsvmPkg/PlatformPei/Config.c b/MsvmPkg/PlatformPei/Config.c index fedec2e69d..2bb05c554c 100644 --- a/MsvmPkg/PlatformPei/Config.c +++ b/MsvmPkg/PlatformPei/Config.c @@ -1560,16 +1560,20 @@ Return Value: // // Figure out which entry is the low gap, and which is the high. + // Use base >= 4GB as the indicator for the high gap. When an + // entry is empty (size=0) its base is typically 0, so it will + // naturally fall into the "low" bucket and be skipped downstream. // - if (mmioRanges->Ranges[0].MmioPageNumberStart < mmioRanges->Ranges[1].MmioPageNumberStart) + if (mmioRanges->Ranges[0].MmioPageNumberStart >= (SIZE_4GB / SIZE_4KB) && + mmioRanges->Ranges[0].MmioSizeInPages > 0) { - lowGap = 0; - highGap = 1; + highGap = 0; + lowGap = 1; } else { - lowGap = 1; - highGap = 0; + lowGap = 0; + highGap = 1; } //