]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/PlatformPei/MemDetect.c
MdeModulePkg/dsc: add SmiHandlerProfile to dsc.
[mirror_edk2.git] / OvmfPkg / PlatformPei / MemDetect.c
index 455fcbb49d13a590b7a118e3a7fbcf3efed00f9a..af96a04d194aae3fecb5a22534201f47ee83d79d 100644 (file)
@@ -1,7 +1,7 @@
 /**@file\r
   Memory Detection for Virtual Machines.\r
 \r
-  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -32,12 +32,16 @@ Module Name:
 #include <Library/PeimEntryPoint.h>\r
 #include <Library/ResourcePublicationLib.h>\r
 #include <Library/MtrrLib.h>\r
+#include <Library/QemuFwCfgLib.h>\r
 \r
 #include "Platform.h"\r
 #include "Cmos.h"\r
 \r
 UINT8 mPhysMemAddressWidth;\r
 \r
+STATIC UINT32 mS3AcpiReservedMemoryBase;\r
+STATIC UINT32 mS3AcpiReservedMemorySize;\r
+\r
 UINT32\r
 GetSystemMemorySizeBelow4gb (\r
   VOID\r
@@ -87,6 +91,136 @@ GetSystemMemorySizeAbove4gb (
 }\r
 \r
 \r
+/**\r
+  Return the highest address that DXE could possibly use, plus one.\r
+**/\r
+STATIC\r
+UINT64\r
+GetFirstNonAddress (\r
+  VOID\r
+  )\r
+{\r
+  UINT64               FirstNonAddress;\r
+  UINT64               Pci64Base, Pci64Size;\r
+  CHAR8                MbString[7 + 1];\r
+  EFI_STATUS           Status;\r
+  FIRMWARE_CONFIG_ITEM FwCfgItem;\r
+  UINTN                FwCfgSize;\r
+  UINT64               HotPlugMemoryEnd;\r
+  RETURN_STATUS        PcdStatus;\r
+\r
+  FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();\r
+\r
+  //\r
+  // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO\r
+  // resources to 32-bit anyway. See DegradeResource() in\r
+  // "PciResourceSupport.c".\r
+  //\r
+#ifdef MDE_CPU_IA32\r
+  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
+    return FirstNonAddress;\r
+  }\r
+#endif\r
+\r
+  //\r
+  // Otherwise, in order to calculate the highest address plus one, we must\r
+  // consider the 64-bit PCI host aperture too. Fetch the default size.\r
+  //\r
+  Pci64Size = PcdGet64 (PcdPciMmio64Size);\r
+\r
+  //\r
+  // See if the user specified the number of megabytes for the 64-bit PCI host\r
+  // aperture. The number of non-NUL characters in MbString allows for\r
+  // 9,999,999 MB, which is approximately 10 TB.\r
+  //\r
+  // As signaled by the "X-" prefix, this knob is experimental, and might go\r
+  // away at any time.\r
+  //\r
+  Status = QemuFwCfgFindFile ("opt/ovmf/X-PciMmio64Mb", &FwCfgItem,\r
+             &FwCfgSize);\r
+  if (!EFI_ERROR (Status)) {\r
+    if (FwCfgSize >= sizeof MbString) {\r
+      DEBUG ((EFI_D_WARN,\r
+        "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",\r
+        __FUNCTION__));\r
+    } else {\r
+      QemuFwCfgSelectItem (FwCfgItem);\r
+      QemuFwCfgReadBytes (FwCfgSize, MbString);\r
+      MbString[FwCfgSize] = '\0';\r
+      Pci64Size = LShiftU64 (AsciiStrDecimalToUint64 (MbString), 20);\r
+    }\r
+  }\r
+\r
+  if (Pci64Size == 0) {\r
+    if (mBootMode != BOOT_ON_S3_RESUME) {\r
+      DEBUG ((EFI_D_INFO, "%a: disabling 64-bit PCI host aperture\n",\r
+        __FUNCTION__));\r
+      PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);\r
+      ASSERT_RETURN_ERROR (PcdStatus);\r
+    }\r
+\r
+    //\r
+    // There's nothing more to do; the amount of memory above 4GB fully\r
+    // 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
+  }\r
+\r
+  //\r
+  // The "etc/reserved-memory-end" fw_cfg file, when present, contains an\r
+  // absolute, exclusive end address for the memory hotplug area. This area\r
+  // starts right at the end of the memory above 4GB. The 64-bit PCI host\r
+  // aperture must be placed above it.\r
+  //\r
+  Status = QemuFwCfgFindFile ("etc/reserved-memory-end", &FwCfgItem,\r
+             &FwCfgSize);\r
+  if (!EFI_ERROR (Status) && FwCfgSize == sizeof HotPlugMemoryEnd) {\r
+    QemuFwCfgSelectItem (FwCfgItem);\r
+    QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);\r
+\r
+    ASSERT (HotPlugMemoryEnd >= FirstNonAddress);\r
+    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
+  Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);\r
+  Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);\r
+\r
+  //\r
+  // The 64-bit PCI host aperture should also be "naturally" aligned. The\r
+  // alignment is determined by rounding the size of the aperture down to the\r
+  // next smaller or equal power of two. That is, align the aperture by the\r
+  // largest BAR size that can fit into it.\r
+  //\r
+  Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));\r
+\r
+  if (mBootMode != BOOT_ON_S3_RESUME) {\r
+    //\r
+    // The core PciHostBridgeDxe driver will automatically add this range to\r
+    // the GCD memory space map through our PciHostBridgeLib instance; here we\r
+    // only need to set the PCDs.\r
+    //\r
+    PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
+    PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+    DEBUG ((EFI_D_INFO, "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",\r
+      __FUNCTION__, Pci64Base, Pci64Size));\r
+  }\r
+\r
+  //\r
+  // The useful address space ends with the 64-bit PCI host aperture.\r
+  //\r
+  FirstNonAddress = Pci64Base + Pci64Size;\r
+  return FirstNonAddress;\r
+}\r
+\r
+\r
 /**\r
   Initialize the mPhysMemAddressWidth variable, based on guest RAM size.\r
 **/\r
@@ -103,7 +237,7 @@ AddressWidthInitialization (
   // 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      = BASE_4GB + GetSystemMemorySizeAbove4gb ();\r
+  FirstNonAddress      = GetFirstNonAddress ();\r
   mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);\r
 \r
   //\r
@@ -206,21 +340,34 @@ PublishPeiMemory (
   EFI_STATUS                  Status;\r
   EFI_PHYSICAL_ADDRESS        MemoryBase;\r
   UINT64                      MemorySize;\r
-  UINT64                      LowerMemorySize;\r
+  UINT32                      LowerMemorySize;\r
   UINT32                      PeiMemoryCap;\r
 \r
+  LowerMemorySize = GetSystemMemorySizeBelow4gb ();\r
+  if (FeaturePcdGet (PcdSmmSmramRequire)) {\r
+    //\r
+    // TSEG is chipped from the end of low RAM\r
+    //\r
+    LowerMemorySize -= FixedPcdGet8 (PcdQ35TsegMbytes) * SIZE_1MB;\r
+  }\r
+\r
+  //\r
+  // If S3 is supported, then the S3 permanent PEI memory is placed next,\r
+  // downwards. Its size is primarily dictated by CpuMpPei. The formula below\r
+  // is an approximation.\r
+  //\r
+  if (mS3Supported) {\r
+    mS3AcpiReservedMemorySize = SIZE_512KB +\r
+      mMaxCpuCount *\r
+      PcdGet32 (PcdCpuApStackSize);\r
+    mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;\r
+    LowerMemorySize = mS3AcpiReservedMemoryBase;\r
+  }\r
+\r
   if (mBootMode == BOOT_ON_S3_RESUME) {\r
-    MemoryBase = PcdGet32 (PcdS3AcpiReservedMemoryBase);\r
-    MemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize);\r
+    MemoryBase = mS3AcpiReservedMemoryBase;\r
+    MemorySize = mS3AcpiReservedMemorySize;\r
   } else {\r
-    LowerMemorySize = GetSystemMemorySizeBelow4gb ();\r
-    if (FeaturePcdGet (PcdSmmSmramRequire)) {\r
-      //\r
-      // TSEG is chipped from the end of low RAM\r
-      //\r
-      LowerMemorySize -= FixedPcdGet8 (PcdQ35TsegMbytes) * SIZE_1MB;\r
-    }\r
-\r
     PeiMemoryCap = GetPeiMemoryCap ();\r
     DEBUG ((EFI_D_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",\r
       __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));\r
@@ -278,7 +425,29 @@ QemuInitializeRam (
   LowerMemorySize = GetSystemMemorySizeBelow4gb ();\r
   UpperMemorySize = GetSystemMemorySizeAbove4gb ();\r
 \r
-  if (mBootMode != BOOT_ON_S3_RESUME) {\r
+  if (mBootMode == BOOT_ON_S3_RESUME) {\r
+    //\r
+    // Create the following memory HOB as an exception on the S3 boot path.\r
+    //\r
+    // Normally we'd create memory HOBs only on the normal boot path. However,\r
+    // CpuMpPei specifically needs such a low-memory HOB on the S3 path as\r
+    // well, for "borrowing" a subset of it temporarily, for the AP startup\r
+    // vector.\r
+    //\r
+    // CpuMpPei saves the original contents of the borrowed area in permanent\r
+    // PEI RAM, in a backup buffer allocated with the normal PEI services.\r
+    // CpuMpPei restores the original contents ("returns" the borrowed area) at\r
+    // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before\r
+    // transferring control to the OS's wakeup vector in the FACS.\r
+    //\r
+    // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to\r
+    // restore the original contents. Furthermore, we expect all such PEIMs\r
+    // (CpuMpPei included) to claim the borrowed areas by producing memory\r
+    // allocation HOBs, and to honor preexistent memory allocation HOBs when\r
+    // looking for an area to borrow.\r
+    //\r
+    AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);\r
+  } else {\r
     //\r
     // Create memory HOBs\r
     //\r
@@ -296,7 +465,7 @@ QemuInitializeRam (
     }\r
 \r
     if (UpperMemorySize != 0) {\r
-      AddUntestedMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);\r
+      AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);\r
     }\r
   }\r
 \r
@@ -366,8 +535,8 @@ InitializeRamRegions (
     // This is the memory range that will be used for PEI on S3 resume\r
     //\r
     BuildMemoryAllocationHob (\r
-      (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdS3AcpiReservedMemoryBase),\r
-      (UINT64)(UINTN) PcdGet32 (PcdS3AcpiReservedMemorySize),\r
+      mS3AcpiReservedMemoryBase,\r
+      mS3AcpiReservedMemorySize,\r
       EfiACPIMemoryNVS\r
       );\r
 \r