]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/PlatformInitLib/MemDetect.c
OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB
[mirror_edk2.git] / OvmfPkg / Library / PlatformInitLib / MemDetect.c
index 882805269b3e14e6dc2936b6eb3861b9ad0393e7..fdfe134247bf6f9e237c9392a854ffa16bf3c39d 100644 (file)
@@ -251,6 +251,84 @@ PlatformScanOrAdd64BitE820Ram (
   return EFI_SUCCESS;\r
 }\r
 \r
+typedef VOID (*E820_SCAN_CALLBACK) (\r
+  EFI_E820_ENTRY64       *E820Entry,\r
+  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob\r
+  );\r
+\r
+/**\r
+  Store first address not used by e820 RAM entries in\r
+  PlatformInfoHob->FirstNonAddress\r
+**/\r
+STATIC\r
+VOID\r
+PlatformGetFirstNonAddressCB (\r
+  IN     EFI_E820_ENTRY64       *E820Entry,\r
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob\r
+  )\r
+{\r
+  UINT64  Candidate;\r
+\r
+  if (E820Entry->Type != EfiAcpiAddressRangeMemory) {\r
+    return;\r
+  }\r
+\r
+  Candidate = E820Entry->BaseAddr + E820Entry->Length;\r
+  if (PlatformInfoHob->FirstNonAddress < Candidate) {\r
+    DEBUG ((DEBUG_INFO, "%a: FirstNonAddress=0x%Lx\n", __FUNCTION__, Candidate));\r
+    PlatformInfoHob->FirstNonAddress = Candidate;\r
+  }\r
+}\r
+\r
+/**\r
+  Iterate over the entries in QEMU's fw_cfg E820 RAM map, call the\r
+  passed callback for each entry.\r
+\r
+  @param[in] Callback              The callback function to be called.\r
+\r
+  @param[in out]  PlatformInfoHob  PlatformInfo struct which is passed\r
+                                   through to the callback.\r
+\r
+  @retval EFI_SUCCESS              The fw_cfg E820 RAM map was found and processed.\r
+\r
+  @retval EFI_PROTOCOL_ERROR       The RAM map was found, but its size wasn't a\r
+                                   whole multiple of sizeof(EFI_E820_ENTRY64). No\r
+                                   RAM entry was processed.\r
+\r
+  @return                          Error codes from QemuFwCfgFindFile(). No RAM\r
+                                   entry was processed.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+PlatformScanE820 (\r
+  IN      E820_SCAN_CALLBACK     Callback,\r
+  IN OUT  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  FIRMWARE_CONFIG_ITEM  FwCfgItem;\r
+  UINTN                 FwCfgSize;\r
+  EFI_E820_ENTRY64      E820Entry;\r
+  UINTN                 Processed;\r
+\r
+  Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (FwCfgSize % sizeof E820Entry != 0) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  QemuFwCfgSelectItem (FwCfgItem);\r
+  for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) {\r
+    QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry);\r
+    Callback (&E820Entry, PlatformInfoHob);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Returns PVH memmap\r
 \r
@@ -384,23 +462,17 @@ PlatformGetSystemMemorySizeAbove4gb (
   Return the highest address that DXE could possibly use, plus one.\r
 **/\r
 STATIC\r
-UINT64\r
+VOID\r
 PlatformGetFirstNonAddress (\r
   IN OUT  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob\r
   )\r
 {\r
-  UINT64                FirstNonAddress;\r
   UINT32                FwCfgPciMmio64Mb;\r
   EFI_STATUS            Status;\r
   FIRMWARE_CONFIG_ITEM  FwCfgItem;\r
   UINTN                 FwCfgSize;\r
   UINT64                HotPlugMemoryEnd;\r
 \r
-  //\r
-  // set FirstNonAddress to suppress incorrect compiler/analyzer warnings\r
-  //\r
-  FirstNonAddress = 0;\r
-\r
   //\r
   // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM\r
   // address from it. This can express an address >= 4GB+1TB.\r
@@ -408,9 +480,10 @@ PlatformGetFirstNonAddress (
   // Otherwise, get the flat size of the memory above 4GB from the CMOS (which\r
   // can only express a size smaller than 1TB), and add it to 4GB.\r
   //\r
-  Status = PlatformScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);\r
+  PlatformInfoHob->FirstNonAddress = BASE_4GB;\r
+  Status                           = PlatformScanE820 (PlatformGetFirstNonAddressCB, PlatformInfoHob);\r
   if (EFI_ERROR (Status)) {\r
-    FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb ();\r
+    PlatformInfoHob->FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb ();\r
   }\r
 \r
   //\r
@@ -420,7 +493,7 @@ PlatformGetFirstNonAddress (
   //\r
  #ifdef MDE_CPU_IA32\r
   if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
-    return FirstNonAddress;\r
+    return;\r
   }\r
 \r
  #endif\r
@@ -473,7 +546,7 @@ PlatformGetFirstNonAddress (
     // determines the highest address plus one. The memory hotplug area (see\r
     // below) plays no role for the firmware in this case.\r
     //\r
-    return FirstNonAddress;\r
+    return;\r
   }\r
 \r
   //\r
@@ -497,15 +570,15 @@ PlatformGetFirstNonAddress (
       HotPlugMemoryEnd\r
       ));\r
 \r
-    ASSERT (HotPlugMemoryEnd >= FirstNonAddress);\r
-    FirstNonAddress = HotPlugMemoryEnd;\r
+    ASSERT (HotPlugMemoryEnd >= PlatformInfoHob->FirstNonAddress);\r
+    PlatformInfoHob->FirstNonAddress = HotPlugMemoryEnd;\r
   }\r
 \r
   //\r
   // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so\r
   // that the host can map it with 1GB hugepages. Follow suit.\r
   //\r
-  PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);\r
+  PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->FirstNonAddress, (UINT64)SIZE_1GB);\r
   PlatformInfoHob->PcdPciMmio64Size = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Size, (UINT64)SIZE_1GB);\r
 \r
   //\r
@@ -519,8 +592,8 @@ PlatformGetFirstNonAddress (
   //\r
   // The useful address space ends with the 64-bit PCI host aperture.\r
   //\r
-  FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size;\r
-  return FirstNonAddress;\r
+  PlatformInfoHob->FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size;\r
+  return;\r
 }\r
 \r
 /*\r
@@ -781,7 +854,6 @@ PlatformAddressWidthInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob\r
   )\r
 {\r
-  UINT64      FirstNonAddress;\r
   UINT8       PhysMemAddressWidth;\r
   EFI_STATUS  Status;\r
 \r
@@ -794,7 +866,7 @@ PlatformAddressWidthInitialization (
   // 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
-  Status = PlatformScanHostProvided64BitPciMmioEnd (&FirstNonAddress);\r
+  Status = PlatformScanHostProvided64BitPciMmioEnd (&PlatformInfoHob->FirstNonAddress);\r
 \r
   if (EFI_ERROR (Status)) {\r
     //\r
@@ -806,13 +878,12 @@ PlatformAddressWidthInitialization (
     // 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
+    PlatformGetFirstNonAddress (PlatformInfoHob);\r
   }\r
 \r
   PlatformAddressWidthFromCpuid (PlatformInfoHob, TRUE);\r
   if (PlatformInfoHob->PhysMemAddressWidth != 0) {\r
     // physical address width is known\r
-    PlatformInfoHob->FirstNonAddress = FirstNonAddress;\r
     PlatformDynamicMmioWindow (PlatformInfoHob);\r
     return;\r
   }\r
@@ -823,13 +894,13 @@ PlatformAddressWidthInitialization (
   //   -> try be conservstibe to stay below the guaranteed minimum of\r
   //      36 phys bits (aka 64 GB).\r
   //\r
-  PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);\r
+  PhysMemAddressWidth = (UINT8)HighBitSet64 (PlatformInfoHob->FirstNonAddress);\r
 \r
   //\r
   // If FirstNonAddress is not an integral power of two, then we need an\r
   // additional bit.\r
   //\r
-  if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {\r
+  if ((PlatformInfoHob->FirstNonAddress & (PlatformInfoHob->FirstNonAddress - 1)) != 0) {\r
     ++PhysMemAddressWidth;\r
   }\r
 \r
@@ -857,7 +928,6 @@ PlatformAddressWidthInitialization (
   ASSERT (PhysMemAddressWidth <= 48);\r
  #endif\r
 \r
-  PlatformInfoHob->FirstNonAddress     = FirstNonAddress;\r
   PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth;\r
 }\r
 \r