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

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