#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
));\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
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
}\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