Blame SOURCES/edk2-OvmfPkg-PlatformPei-set-32-bit-UC-area-at-PciBase-Pc.patch

fcd20d
From 71c39f0fb0b9a3e9856cebc58ef3812752fd07cc Mon Sep 17 00:00:00 2001
fcd20d
From: Laszlo Ersek <lersek@redhat.com>
fcd20d
Date: Tue, 4 Jun 2019 11:06:45 +0200
fcd20d
Subject: [PATCH 3/3] OvmfPkg/PlatformPei: set 32-bit UC area at PciBase /
fcd20d
 PciExBarBase (pc/q35)
fcd20d
MIME-Version: 1.0
fcd20d
Content-Type: text/plain; charset=UTF-8
fcd20d
Content-Transfer-Encoding: 8bit
fcd20d
fcd20d
Message-id: <20190604090645.2847-4-lersek@redhat.com>
fcd20d
Patchwork-id: 88483
fcd20d
O-Subject:  [RHEL-8.1.0 edk2 PATCH v2 3/3] OvmfPkg/PlatformPei: set 32-bit UC
fcd20d
	area at PciBase / PciExBarBase (pc/q35)
fcd20d
Bugzilla: 1666941
fcd20d
Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
fcd20d
Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
fcd20d
fcd20d
(This is a replacement for commit 39b9a5ffe661 ("OvmfPkg/PlatformPei: fix
fcd20d
MTRR for low-RAM sizes that have many bits clear", 2019-05-16).)
fcd20d
fcd20d
Reintroduce the same logic as seen in commit 39b9a5ffe661 for the pc
fcd20d
(i440fx) board type.
fcd20d
fcd20d
For q35, the same approach doesn't work any longer, given that (a) we'd
fcd20d
like to keep the PCIEXBAR in the platform DSC a fixed-at-build PCD, and
fcd20d
(b) QEMU expects the PCIEXBAR to reside at a lower address than the 32-bit
fcd20d
PCI MMIO aperture.
fcd20d
fcd20d
Therefore, introduce a helper function for determining the 32-bit
fcd20d
"uncacheable" (MMIO) area base address:
fcd20d
fcd20d
- On q35, this function behaves statically. Furthermore, the MTRR setup
fcd20d
  exploits that the range [0xB000_0000, 0xFFFF_FFFF] can be marked UC with
fcd20d
  just two variable MTRRs (one at 0xB000_0000 (size 256MB), another at
fcd20d
  0xC000_0000 (size 1GB)).
fcd20d
fcd20d
- On pc (i440fx), the function behaves dynamically, implementing the same
fcd20d
  logic as commit 39b9a5ffe661 did. The PciBase value is adjusted to the
fcd20d
  value calculated, similarly to commit 39b9a5ffe661. A further
fcd20d
  simplification is that we show that the UC32 area size truncation to a
fcd20d
  whole power of two automatically guarantees a >=2GB base address.
fcd20d
fcd20d
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
fcd20d
Cc: Gerd Hoffmann <kraxel@redhat.com>
fcd20d
Cc: Jordan Justen <jordan.l.justen@intel.com>
fcd20d
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1859
fcd20d
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
fcd20d
Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>
fcd20d
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
fcd20d
(cherry picked from commit 49edde15230a5bfd6746225eb95535eaa2ec1ba4)
fcd20d
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
fcd20d
---
fcd20d
 OvmfPkg/PlatformPei/MemDetect.c | 59 ++++++++++++++++++++++++++++++++++++++---
fcd20d
 OvmfPkg/PlatformPei/Platform.c  |  5 +++-
fcd20d
 OvmfPkg/PlatformPei/Platform.h  |  7 +++++
fcd20d
 3 files changed, 66 insertions(+), 5 deletions(-)
fcd20d
fcd20d
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
fcd20d
index 2f9e835..0c38b70 100644
fcd20d
--- a/OvmfPkg/PlatformPei/MemDetect.c
fcd20d
+++ b/OvmfPkg/PlatformPei/MemDetect.c
fcd20d
@@ -20,6 +20,7 @@ Module Name:
fcd20d
 // The package level header files this module uses
fcd20d
 //
fcd20d
 #include <IndustryStandard/E820.h>
fcd20d
+#include <IndustryStandard/I440FxPiix4.h>
fcd20d
 #include <IndustryStandard/Q35MchIch9.h>
fcd20d
 #include <PiPei.h>
fcd20d
 
fcd20d
@@ -48,6 +49,8 @@ STATIC UINT32 mS3AcpiReservedMemorySize;
fcd20d
 
fcd20d
 STATIC UINT16 mQ35TsegMbytes;
fcd20d
 
fcd20d
+UINT32 mQemuUc32Base;
fcd20d
+
fcd20d
 VOID
fcd20d
 Q35TsegMbytesInitialization (
fcd20d
   VOID
fcd20d
@@ -104,6 +107,54 @@ Q35TsegMbytesInitialization (
fcd20d
 }
fcd20d
 
fcd20d
 
fcd20d
+VOID
fcd20d
+QemuUc32BaseInitialization (
fcd20d
+  VOID
fcd20d
+  )
fcd20d
+{
fcd20d
+  UINT32 LowerMemorySize;
fcd20d
+  UINT32 Uc32Size;
fcd20d
+
fcd20d
+  if (mXen) {
fcd20d
+    return;
fcd20d
+  }
fcd20d
+
fcd20d
+  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
fcd20d
+    //
fcd20d
+    // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
fcd20d
+    // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
fcd20d
+    // setting PcdPciExpressBaseAddress such that describing the
fcd20d
+    // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
fcd20d
+    // variable MTRRs (preferably 1 or 2).
fcd20d
+    //
fcd20d
+    ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);
fcd20d
+    mQemuUc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
fcd20d
+    return;
fcd20d
+  }
fcd20d
+
fcd20d
+  ASSERT (mHostBridgeDevId == INTEL_82441_DEVICE_ID);
fcd20d
+  //
fcd20d
+  // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
fcd20d
+  // variable MTRR suffices by truncating the size to a whole power of two,
fcd20d
+  // while keeping the end affixed to 4GB. This will round the base up.
fcd20d
+  //
fcd20d
+  LowerMemorySize = GetSystemMemorySizeBelow4gb ();
fcd20d
+  Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
fcd20d
+  mQemuUc32Base = (UINT32)(SIZE_4GB - Uc32Size);
fcd20d
+  //
fcd20d
+  // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
fcd20d
+  // Therefore mQemuUc32Base is at least 2GB.
fcd20d
+  //
fcd20d
+  ASSERT (mQemuUc32Base >= BASE_2GB);
fcd20d
+
fcd20d
+  if (mQemuUc32Base != LowerMemorySize) {
fcd20d
+    DEBUG ((DEBUG_VERBOSE, "%a: rounded UC32 base from 0x%x up to 0x%x, for "
fcd20d
+      "an UC32 size of 0x%x\n", __FUNCTION__, LowerMemorySize, mQemuUc32Base,
fcd20d
+      Uc32Size));
fcd20d
+  }
fcd20d
+}
fcd20d
+
fcd20d
+
fcd20d
 /**
fcd20d
   Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
fcd20d
   of the 32-bit address range.
fcd20d
@@ -694,11 +745,11 @@ QemuInitializeRam (
fcd20d
     ASSERT_EFI_ERROR (Status);
fcd20d
 
fcd20d
     //
fcd20d
-    // Set memory range from the "top of lower RAM" (RAM below 4GB) to 4GB as
fcd20d
-    // uncacheable
fcd20d
+    // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
fcd20d
+    // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
fcd20d
     //
fcd20d
-    Status = MtrrSetMemoryAttribute (LowerMemorySize,
fcd20d
-               SIZE_4GB - LowerMemorySize, CacheUncacheable);
fcd20d
+    Status = MtrrSetMemoryAttribute (mQemuUc32Base, SIZE_4GB - mQemuUc32Base,
fcd20d
+               CacheUncacheable);
fcd20d
     ASSERT_EFI_ERROR (Status);
fcd20d
   }
fcd20d
 }
fcd20d
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
fcd20d
index 64b8034..de19f5c 100644
fcd20d
--- a/OvmfPkg/PlatformPei/Platform.c
fcd20d
+++ b/OvmfPkg/PlatformPei/Platform.c
fcd20d
@@ -197,7 +197,8 @@ MemMapInitialization (
fcd20d
       ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
fcd20d
       PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
fcd20d
     } else {
fcd20d
-      PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
fcd20d
+      ASSERT (TopOfLowRam <= mQemuUc32Base);
fcd20d
+      PciBase = mQemuUc32Base;
fcd20d
     }
fcd20d
 
fcd20d
     //
fcd20d
@@ -656,6 +657,8 @@ InitializePlatform (
fcd20d
 
fcd20d
   PublishPeiMemory ();
fcd20d
 
fcd20d
+  QemuUc32BaseInitialization ();
fcd20d
+
fcd20d
   InitializeRamRegions ();
fcd20d
 
fcd20d
   if (mXen) {
fcd20d
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
fcd20d
index b12a5c1..2b486ce 100644
fcd20d
--- a/OvmfPkg/PlatformPei/Platform.h
fcd20d
+++ b/OvmfPkg/PlatformPei/Platform.h
fcd20d
@@ -69,6 +69,11 @@ GetSystemMemorySizeBelow4gb (
fcd20d
   );
fcd20d
 
fcd20d
 VOID
fcd20d
+QemuUc32BaseInitialization (
fcd20d
+  VOID
fcd20d
+  );
fcd20d
+
fcd20d
+VOID
fcd20d
 InitializeRamRegions (
fcd20d
   VOID
fcd20d
   );
fcd20d
@@ -120,4 +125,6 @@ extern UINT32 mMaxCpuCount;
fcd20d
 
fcd20d
 extern UINT16 mHostBridgeDevId;
fcd20d
 
fcd20d
+extern UINT32 mQemuUc32Base;
fcd20d
+
fcd20d
 #endif // _PLATFORM_PEI_H_INCLUDED_
fcd20d
-- 
fcd20d
1.8.3.1
fcd20d