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