public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Ojeda Leon, Nicolas" <ncoleon@amazon.com>
To: <devel@edk2.groups.io>
Cc: <ardb+tianocore@kernel.org>, <jiewen.yao@intel.com>,
	<jordan.l.justen@intel.com>,
	Nicolas Ojeda Leon <ncoleon@amazon.com>,
	Alexander Graf <graf@amazon.de>,
	Gerd Hoffmann <kraxel@redhat.com>
Subject: [PATCH v6 4/5] Ovmf/PlatformPei: Use host-provided GPA end if available
Date: Tue, 21 Jun 2022 23:38:58 +0200	[thread overview]
Message-ID: <b6cac039137c3d0b19be00af8dbd28a33109fd5b.1655841172.git.ncoleon@amazon.com> (raw)
In-Reply-To: <cover.1655841172.git.ncoleon@amazon.com>

Read the "hardware-info" item from fw-cfg to extract specifications
of PCI host bridges and analyze the 64-bit apertures of them to
find out the highest 64-bit MMIO address required which determines
the address space required by the guest, and, consequently, the
FirstNonAddress used to calculate size of physical addresses.

Using the static PeiHardwareInfoLib, read the fw-cfg file of
hardware information to extract, one by one, all the host
bridges. Find the last 64-bit MMIO address of each host bridge,
using the HardwareInfoPciHostBridgeLib API, and compare it to an
accumulate value to discover the highest address used, which
corresponds to the highest value that must be included in the
guest's physical address space.

Given that platforms with multiple host bridges may provide the PCI
apertures' addresses, the memory detection logic must take into
account that, if the host provided the MMIO windows that can and must
be used, the guest needs to take those values. Therefore, if the
MMIO windows are found in the host-provided fw-cfg file, skip all the
logic calculating the physical address size and just use the value
provided. Since each PCI host bridge corresponds to an element in
the information provided by the host, each of these must be analyzed
looking for the highest address used.

Cc: Alexander Graf <graf@amazon.de>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Nicolas Ojeda Leon <ncoleon@amazon.com>
---
Notes:
  v6:
  Preparation for merge:

  v5:
  - Moved all changes from MemDetect.c into recently created
    PlatformInitLib/MemDetect.c effectively re-basing this patch
    onto latest master
  - Adapted function name to use Platform____ convention without
    any changes in the logic



---
 OvmfPkg/Library/PlatformInitLib/MemDetect.c   | 148 +++++++++++++++++-
 .../PlatformInitLib/PlatformInitLib.inf       |   1 +
 2 files changed, 142 insertions(+), 7 deletions(-)

diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
index c28d7601f8..942eaf89cf 100644
--- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c
+++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
@@ -27,6 +27,7 @@ Module Name:
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
+#include <Library/HardwareInfoLib.h>
 #include <Library/HobLib.h>
 #include <Library/IoLib.h>
 #include <Library/MemEncryptSevLib.h>
@@ -527,6 +528,126 @@ PlatformAddressWidthFromCpuid (
     ));
 }
 
+/**
+  Iterate over the PCI host bridges resources information optionally provided
+  in fw-cfg and find the highest address contained in the PCI MMIO windows. If
+  the information is found, return the exclusive end; one past the last usable
+  address.
+
+  @param[out] PciMmioAddressEnd Pointer to one-after End Address updated with
+                                information extracted from host-provided data
+                                or zero if no information available or an
+                                error happened
+
+  @retval EFI_SUCCESS               PCI information was read and the output
+                                    parameter updated with the last valid
+                                    address in the 64-bit MMIO range.
+  @retval EFI_INVALID_PARAMETER     Pointer parameter is invalid
+  @retval EFI_INCOMPATIBLE_VERSION  Hardware information found in fw-cfg
+                                    has an incompatible format
+  @retval EFI_UNSUPPORTED           Fw-cfg is not supported, thus host
+                                    provided information, if any, cannot be
+                                    read
+  @retval EFI_NOT_FOUND             No PCI host bridge information provided
+                                    by the host.
+**/
+STATIC
+EFI_STATUS
+PlatformScanHostProvided64BitPciMmioEnd (
+  OUT UINT64  *PciMmioAddressEnd
+  )
+{
+  EFI_STATUS            Status;
+  HOST_BRIDGE_INFO      HostBridge;
+  FIRMWARE_CONFIG_ITEM  FwCfgItem;
+  UINTN                 FwCfgSize;
+  UINTN                 FwCfgReadIndex;
+  UINTN                 ReadDataSize;
+  UINT64                Above4GMmioEnd;
+
+  if (PciMmioAddressEnd == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *PciMmioAddressEnd = 0;
+  Above4GMmioEnd     = 0;
+
+  Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  QemuFwCfgSelectItem (FwCfgItem);
+
+  FwCfgReadIndex = 0;
+  while (FwCfgReadIndex < FwCfgSize) {
+    Status = QemuFwCfgReadNextHardwareInfoByType (
+               HardwareInfoTypeHostBridge,
+               sizeof (HostBridge),
+               FwCfgSize,
+               &HostBridge,
+               &ReadDataSize,
+               &FwCfgReadIndex
+               );
+
+    if (Status != EFI_SUCCESS) {
+      //
+      // No more data available to read in the file, break
+      // loop and finish process
+      //
+      break;
+    }
+
+    Status = HardwareInfoPciHostBridgeLastMmioAddress (
+               &HostBridge,
+               ReadDataSize,
+               TRUE,
+               &Above4GMmioEnd
+               );
+
+    if (Status != EFI_SUCCESS) {
+      //
+      // Error parsing MMIO apertures and extracting last MMIO
+      // address, reset PciMmioAddressEnd as if no information was
+      // found, to avoid moving forward with incomplete data, and
+      // bail out
+      //
+      DEBUG ((
+        DEBUG_ERROR,
+        "%a: ignoring malformed hardware information from fw_cfg\n",
+        __FUNCTION__
+        ));
+      *PciMmioAddressEnd = 0;
+      return Status;
+    }
+
+    if (Above4GMmioEnd > *PciMmioAddressEnd) {
+      *PciMmioAddressEnd = Above4GMmioEnd;
+    }
+  }
+
+  if (*PciMmioAddressEnd > 0) {
+    //
+    // Host-provided PCI information was found and a MMIO window end
+    // derived from it.
+    // Increase the End address by one to have the output pointing to
+    // one after the address in use (exclusive end).
+    //
+    *PciMmioAddressEnd += 1;
+
+    DEBUG ((
+      DEBUG_INFO,
+      "%a: Pci64End=0x%Lx\n",
+      __FUNCTION__,
+      *PciMmioAddressEnd
+      ));
+
+    return EFI_SUCCESS;
+  }
+
+  return EFI_NOT_FOUND;
+}
+
 /**
   Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
 **/
@@ -536,8 +657,9 @@ PlatformAddressWidthInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
-  UINT64  FirstNonAddress;
-  UINT8   PhysMemAddressWidth;
+  UINT64      FirstNonAddress;
+  UINT8       PhysMemAddressWidth;
+  EFI_STATUS  Status;
 
   if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
     PlatformAddressWidthFromCpuid (PlatformInfoHob);
@@ -545,12 +667,24 @@ PlatformAddressWidthInitialization (
   }
 
   //
-  // As guest-physical memory size grows, the permanent PEI RAM requirements
-  // are dominated by the identity-mapping page tables built by the DXE IPL.
-  // The DXL IPL keys off of the physical address bits advertized in the CPU
-  // HOB. To conserve memory, we calculate the minimum address width here.
+  // First scan host-provided hardware information to assess if the address
+  // space is already known. If so, guest must use those values.
   //
-  FirstNonAddress     = PlatformGetFirstNonAddress (PlatformInfoHob);
+  Status = PlatformScanHostProvided64BitPciMmioEnd (&FirstNonAddress);
+
+  if (EFI_ERROR (Status)) {
+    //
+    // If the host did not provide valid hardware information leading to a
+    // hard-defined 64-bit MMIO end, fold back to calculating the minimum range
+    // needed.
+    // As guest-physical memory size grows, the permanent PEI RAM requirements
+    // are dominated by the identity-mapping page tables built by the DXE IPL.
+    // The DXL IPL keys off of the physical address bits advertized in the CPU
+    // HOB. To conserve memory, we calculate the minimum address width here.
+    //
+    FirstNonAddress = PlatformGetFirstNonAddress (PlatformInfoHob);
+  }
+
   PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
 
   //
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index d2a0bec434..d2fa2d998d 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -50,6 +50,7 @@
   MtrrLib
   PcdLib
   PciLib
+  PeiHardwareInfoLib
 
 [LibraryClasses.X64]
   TdxLib
-- 
2.17.1




Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879




  parent reply	other threads:[~2022-06-21 21:39 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-21 21:27 [PATCH v6 0/5] Handling of multiple PCI Ojeda Leon, Nicolas
2022-06-21 21:31 ` [PATCH v6 1/5] OvmfPkg/Library: Create base HardwareInfoLib for PCI Host Bridges Ojeda Leon, Nicolas
2022-06-21 21:34 ` [PATCH v6 2/5] Ovmf/HardwareInfoLib: Create Pei lib to parse directly from fw-cfg Ojeda Leon, Nicolas
2022-06-21 21:37 ` [PATCH v6 3/5] Ovmf/HardwareInfoLib: Add Dxe lib to dynamically parse heterogenous data Ojeda Leon, Nicolas
2022-06-21 21:38 ` Ojeda Leon, Nicolas [this message]
2022-06-21 21:40 ` [PATCH v6 5/5] OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with spec Ojeda Leon, Nicolas
2022-06-22 15:35 ` [PATCH v6 0/5] Handling of multiple PCI Ard Biesheuvel
2022-06-23 11:00   ` Ard Biesheuvel
2022-06-23 14:14     ` Ojeda Leon, Nicolas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b6cac039137c3d0b19be00af8dbd28a33109fd5b.1655841172.git.ncoleon@amazon.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox