diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c index e890e36408..d451989f31 100644 --- a/OvmfPkg/PlatformPei/MemDetect.c +++ b/OvmfPkg/PlatformPei/MemDetect.c @@ -14,6 +14,7 @@ Module Name: // The package level header files this module uses // #include +#include #include #include @@ -42,6 +43,8 @@ STATIC UINT32 mS3AcpiReservedMemorySize; STATIC UINT16 mQ35TsegMbytes; +UINT32 mQemuUc32Base; + VOID Q35TsegMbytesInitialization ( VOID @@ -98,6 +101,54 @@ Q35TsegMbytesInitialization ( } +VOID +QemuUc32BaseInitialization ( + VOID + ) +{ + UINT32 LowerMemorySize; + UINT32 Uc32Size; + + if (mXen) { + return; + } + + if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { + // + // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs, + // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for + // setting PcdPciExpressBaseAddress such that describing the + // [PcdPciExpressBaseAddress, 4GB) range require a very small number of + // variable MTRRs (preferably 1 or 2). + // + ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32); + mQemuUc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress); + return; + } + + ASSERT (mHostBridgeDevId == INTEL_82441_DEVICE_ID); + // + // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one + // variable MTRR suffices by truncating the size to a whole power of two, + // while keeping the end affixed to 4GB. This will round the base up. + // + LowerMemorySize = GetSystemMemorySizeBelow4gb (); + Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize)); + mQemuUc32Base = (UINT32)(SIZE_4GB - Uc32Size); + // + // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB. + // Therefore mQemuUc32Base is at least 2GB. + // + ASSERT (mQemuUc32Base >= BASE_2GB); + + if (mQemuUc32Base != LowerMemorySize) { + DEBUG ((DEBUG_VERBOSE, "%a: rounded UC32 base from 0x%x up to 0x%x, for " + "an UC32 size of 0x%x\n", __FUNCTION__, LowerMemorySize, mQemuUc32Base, + Uc32Size)); + } +} + + /** Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside of the 32-bit address range. @@ -688,11 +739,11 @@ QemuInitializeRam ( ASSERT_EFI_ERROR (Status); // - // Set memory range from the "top of lower RAM" (RAM below 4GB) to 4GB as - // uncacheable + // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI + // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable. // - Status = MtrrSetMemoryAttribute (LowerMemorySize, - SIZE_4GB - LowerMemorySize, CacheUncacheable); + Status = MtrrSetMemoryAttribute (mQemuUc32Base, SIZE_4GB - mQemuUc32Base, + CacheUncacheable); ASSERT_EFI_ERROR (Status); } } diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c index 0876316eef..3ba2459872 100644 --- a/OvmfPkg/PlatformPei/Platform.c +++ b/OvmfPkg/PlatformPei/Platform.c @@ -191,7 +191,8 @@ MemMapInitialization ( ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB); PciBase = (UINT32)(PciExBarBase + SIZE_256MB); } else { - PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam; + ASSERT (TopOfLowRam <= mQemuUc32Base); + PciBase = mQemuUc32Base; } // @@ -650,6 +651,8 @@ InitializePlatform ( PublishPeiMemory (); + QemuUc32BaseInitialization (); + InitializeRamRegions (); if (mXen) { diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h index 81af8b7148..2f3cebcd3a 100644 --- a/OvmfPkg/PlatformPei/Platform.h +++ b/OvmfPkg/PlatformPei/Platform.h @@ -62,6 +62,11 @@ GetSystemMemorySizeBelow4gb ( VOID ); +VOID +QemuUc32BaseInitialization ( + VOID + ); + VOID InitializeRamRegions ( VOID @@ -114,4 +119,6 @@ extern UINT32 mMaxCpuCount; extern UINT16 mHostBridgeDevId; +extern UINT32 mQemuUc32Base; + #endif // _PLATFORM_PEI_H_INCLUDED_