]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/PlatformPei/Platform.c
OvmfPkg/PlatformPei: align EmuVariableNvStore at any page boundary
[mirror_edk2.git] / OvmfPkg / PlatformPei / Platform.c
index 7d0941209f252bb5db0c1e0341081f567f1cf9a5..3e9fda7c7ab019c11fe4b32b5ca75d7a33a88196 100644 (file)
@@ -1,7 +1,7 @@
 /**@file\r
   Platform PEI driver\r
 \r
-  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
   Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>\r
 \r
   This program and the accompanying materials\r
@@ -32,6 +32,7 @@
 #include <Library/PeimEntryPoint.h>\r
 #include <Library/PeiServicesLib.h>\r
 #include <Library/QemuFwCfgLib.h>\r
+#include <Library/QemuFwCfgS3Lib.h>\r
 #include <Library/ResourcePublicationLib.h>\r
 #include <Guid/MemoryTypeInformation.h>\r
 #include <Ppi/MasterBootMode.h>\r
@@ -68,6 +69,7 @@ EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
 \r
 BOOLEAN mS3Supported = FALSE;\r
 \r
+UINT32 mMaxCpuCount;\r
 \r
 VOID\r
 AddIoMemoryBaseSizeHob (\r
@@ -151,40 +153,18 @@ AddMemoryRangeHob (
 }\r
 \r
 \r
-VOID\r
-AddUntestedMemoryBaseSizeHob (\r
-  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
-  UINT64                      MemorySize\r
-  )\r
-{\r
-  BuildResourceDescriptorHob (\r
-    EFI_RESOURCE_SYSTEM_MEMORY,\r
-      EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
-      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
-      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
-      EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
-      EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
-      EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE,\r
-    MemoryBase,\r
-    MemorySize\r
-    );\r
-}\r
-\r
-\r
-VOID\r
-AddUntestedMemoryRangeHob (\r
-  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
-  EFI_PHYSICAL_ADDRESS        MemoryLimit\r
-  )\r
-{\r
-  AddUntestedMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));\r
-}\r
-\r
 VOID\r
 MemMapInitialization (\r
   VOID\r
   )\r
 {\r
+  UINT64        PciIoBase;\r
+  UINT64        PciIoSize;\r
+  RETURN_STATUS PcdStatus;\r
+\r
+  PciIoBase = 0xC000;\r
+  PciIoSize = 0x4000;\r
+\r
   //\r
   // Create Memory Type Information HOB\r
   //\r
@@ -194,17 +174,6 @@ MemMapInitialization (
     sizeof(mDefaultMemoryTypeInformation)\r
     );\r
 \r
-  //\r
-  // Add PCI IO Port space available for PCI resource allocations.\r
-  //\r
-  BuildResourceDescriptorHob (\r
-    EFI_RESOURCE_IO,\r
-    EFI_RESOURCE_ATTRIBUTE_PRESENT     |\r
-    EFI_RESOURCE_ATTRIBUTE_INITIALIZED,\r
-    PcdGet64 (PcdPciIoBase),\r
-    PcdGet64 (PcdPciIoSize)\r
-    );\r
-\r
   //\r
   // Video memory + Legacy BIOS region\r
   //\r
@@ -212,18 +181,21 @@ MemMapInitialization (
 \r
   if (!mXen) {\r
     UINT32  TopOfLowRam;\r
+    UINT64  PciExBarBase;\r
     UINT32  PciBase;\r
     UINT32  PciSize;\r
 \r
     TopOfLowRam = GetSystemMemorySizeBelow4gb ();\r
+    PciExBarBase = 0;\r
     if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
       //\r
-      // A 3GB base will always fall into Q35's 32-bit PCI host aperture,\r
-      // regardless of the Q35 MMCONFIG BAR. Correspondingly, QEMU never lets\r
-      // the RAM below 4 GB exceed it.\r
+      // The MMCONFIG area is expected to fall between the top of low RAM and\r
+      // the base of the 32-bit PCI host aperture.\r
       //\r
-      PciBase = BASE_2GB + BASE_1GB;\r
-      ASSERT (TopOfLowRam <= PciBase);\r
+      PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);\r
+      ASSERT (TopOfLowRam <= PciExBarBase);\r
+      ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);\r
+      PciBase = (UINT32)(PciExBarBase + SIZE_256MB);\r
     } else {\r
       PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;\r
     }\r
@@ -243,15 +215,67 @@ MemMapInitialization (
     //\r
     PciSize = 0xFC000000 - PciBase;\r
     AddIoMemoryBaseSizeHob (PciBase, PciSize);\r
-    PcdSet64 (PcdPciMmio32Base, PciBase);\r
-    PcdSet64 (PcdPciMmio32Size, PciSize);\r
+    PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
+    PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);\r
+    ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
     AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);\r
     AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);\r
     if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
       AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);\r
+      //\r
+      // Note: there should be an\r
+      //\r
+      //   AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);\r
+      //\r
+      // call below, just like the one above for RCBA. However, Linux insists\r
+      // that the MMCONFIG area be marked in the E820 or UEFI memory map as\r
+      // "reserved memory" -- Linux does not content itself with a simple gap\r
+      // in the memory map wherever the MCFG ACPI table points to.\r
+      //\r
+      // This appears to be a safety measure. The PCI Firmware Specification\r
+      // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can\r
+      // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory\r
+      // [...]". (Emphasis added here.)\r
+      //\r
+      // Normally we add memory resource descriptor HOBs in\r
+      // QemuInitializeRam(), and pre-allocate from those with memory\r
+      // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area\r
+      // is most definitely not RAM; so, as an exception, cover it with\r
+      // uncacheable reserved memory right here.\r
+      //\r
+      AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);\r
+      BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,\r
+        EfiReservedMemoryType);\r
     }\r
     AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB);\r
+\r
+    //\r
+    // On Q35, the IO Port space is available for PCI resource allocations from\r
+    // 0x6000 up.\r
+    //\r
+    if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
+      PciIoBase = 0x6000;\r
+      PciIoSize = 0xA000;\r
+      ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);\r
+    }\r
   }\r
+\r
+  //\r
+  // Add PCI IO Port space available for PCI resource allocations.\r
+  //\r
+  BuildResourceDescriptorHob (\r
+    EFI_RESOURCE_IO,\r
+    EFI_RESOURCE_ATTRIBUTE_PRESENT     |\r
+    EFI_RESOURCE_ATTRIBUTE_INITIALIZED,\r
+    PciIoBase,\r
+    PciIoSize\r
+    );\r
+  PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+  PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
 }\r
 \r
 EFI_STATUS\r
@@ -300,11 +324,13 @@ GetNamedFwCfgBoolean (
 \r
 #define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName)                   \\r
           do {                                                      \\r
-            BOOLEAN Setting;                                        \\r
+            BOOLEAN       Setting;                                  \\r
+            RETURN_STATUS PcdStatus;                                \\r
                                                                     \\r
             if (!EFI_ERROR (GetNamedFwCfgBoolean (                  \\r
                               "opt/ovmf/" #TokenName, &Setting))) { \\r
-              PcdSetBool (TokenName, Setting);                      \\r
+              PcdStatus = PcdSetBoolS (TokenName, Setting);         \\r
+              ASSERT_RETURN_ERROR (PcdStatus);                      \\r
             }                                                       \\r
           } while (0)\r
 \r
@@ -317,15 +343,59 @@ NoexecDxeInitialization (
   UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack);\r
 }\r
 \r
+VOID\r
+PciExBarInitialization (\r
+  VOID\r
+  )\r
+{\r
+  union {\r
+    UINT64 Uint64;\r
+    UINT32 Uint32[2];\r
+  } PciExBarBase;\r
+\r
+  //\r
+  // We only support the 256MB size for the MMCONFIG area:\r
+  // 256 buses * 32 devices * 8 functions * 4096 bytes config space.\r
+  //\r
+  // The masks used below enforce the Q35 requirements that the MMCONFIG area\r
+  // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.\r
+  //\r
+  // Note that (b) also ensures that the minimum address width we have\r
+  // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice\r
+  // for DXE's page tables to cover the MMCONFIG area.\r
+  //\r
+  PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);\r
+  ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);\r
+  ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);\r
+\r
+  //\r
+  // Clear the PCIEXBAREN bit first, before programming the high register.\r
+  //\r
+  PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);\r
+\r
+  //\r
+  // Program the high register. Then program the low register, setting the\r
+  // MMCONFIG area size and enabling decoding at once.\r
+  //\r
+  PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);\r
+  PciWrite32 (\r
+    DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),\r
+    PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN\r
+    );\r
+}\r
+\r
 VOID\r
 MiscInitialization (\r
   VOID\r
   )\r
 {\r
-  UINTN  PmCmd;\r
-  UINTN  Pmba;\r
-  UINTN  AcpiCtlReg;\r
-  UINT8  AcpiEnBit;\r
+  UINTN         PmCmd;\r
+  UINTN         Pmba;\r
+  UINT32        PmbaAndVal;\r
+  UINT32        PmbaOrVal;\r
+  UINTN         AcpiCtlReg;\r
+  UINT8         AcpiEnBit;\r
+  RETURN_STATUS PcdStatus;\r
 \r
   //\r
   // Disable A20 Mask\r
@@ -346,12 +416,16 @@ MiscInitialization (
     case INTEL_82441_DEVICE_ID:\r
       PmCmd      = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);\r
       Pmba       = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\r
+      PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;\r
+      PmbaOrVal  = PIIX4_PMBA_VALUE;\r
       AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);\r
       AcpiEnBit  = PIIX4_PMREGMISC_PMIOSE;\r
       break;\r
     case INTEL_Q35_MCH_DEVICE_ID:\r
       PmCmd      = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);\r
       Pmba       = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);\r
+      PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;\r
+      PmbaOrVal  = ICH9_PMBASE_VALUE;\r
       AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);\r
       AcpiEnBit  = ICH9_ACPI_CNTL_ACPI_EN;\r
       break;\r
@@ -361,7 +435,8 @@ MiscInitialization (
       ASSERT (FALSE);\r
       return;\r
   }\r
-  PcdSet16 (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);\r
+  PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
 \r
   //\r
   // If the appropriate IOspace enable bit is set, assume the ACPI PMBA\r
@@ -373,7 +448,7 @@ MiscInitialization (
     // The PEI phase should be exited with fully accessibe ACPI PM IO space:\r
     // 1. set PMBA\r
     //\r
-    PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress));\r
+    PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);\r
 \r
     //\r
     // 2. set PCICMD/IOSE\r
@@ -394,6 +469,11 @@ MiscInitialization (
       POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),\r
       ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN\r
       );\r
+\r
+    //\r
+    // Set PCI Express Register Range Base Address\r
+    //\r
+    PciExBarInitialization ();\r
   }\r
 }\r
 \r
@@ -423,6 +503,7 @@ ReserveEmuVariableNvStore (
   )\r
 {\r
   EFI_PHYSICAL_ADDRESS VariableStore;\r
+  RETURN_STATUS        PcdStatus;\r
 \r
   //\r
   // Allocate storage for NV variables early on so it will be\r
@@ -432,16 +513,16 @@ ReserveEmuVariableNvStore (
   //\r
   VariableStore =\r
     (EFI_PHYSICAL_ADDRESS)(UINTN)\r
-      AllocateAlignedRuntimePages (\r
-        EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)),\r
-        PcdGet32 (PcdFlashNvStorageFtwSpareSize)\r
+      AllocateRuntimePages (\r
+        EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))\r
         );\r
   DEBUG ((EFI_D_INFO,\r
           "Reserved variable store memory: 0x%lX; size: %dkb\n",\r
           VariableStore,\r
           (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024\r
         ));\r
-  PcdSet64 (PcdEmuVariableNvStoreReserved, VariableStore);\r
+  PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
 }\r
 \r
 \r
@@ -487,6 +568,47 @@ S3Verification (
 }\r
 \r
 \r
+/**\r
+  Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modules.\r
+  Set the mMaxCpuCount variable.\r
+**/\r
+VOID\r
+MaxCpuCountInitialization (\r
+  VOID\r
+  )\r
+{\r
+  UINT16        ProcessorCount;\r
+  RETURN_STATUS PcdStatus;\r
+\r
+  QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);\r
+  ProcessorCount = QemuFwCfgRead16 ();\r
+  //\r
+  // If the fw_cfg key or fw_cfg entirely is unavailable, load mMaxCpuCount\r
+  // from the PCD default. No change to PCDs.\r
+  //\r
+  if (ProcessorCount == 0) {\r
+    mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
+    return;\r
+  }\r
+  //\r
+  // Otherwise, set mMaxCpuCount to the value reported by QEMU.\r
+  //\r
+  mMaxCpuCount = ProcessorCount;\r
+  //\r
+  // Additionally, tell UefiCpuPkg modules (a) the exact number of VCPUs, (b)\r
+  // to wait, in the initial AP bringup, exactly as long as it takes for all of\r
+  // the APs to report in. For this, we set the longest representable timeout\r
+  // (approx. 71 minutes).\r
+  //\r
+  PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, ProcessorCount);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+  PcdStatus = PcdSet32S (PcdCpuApInitTimeOutInMicroSeconds, MAX_UINT32);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+  DEBUG ((DEBUG_INFO, "%a: QEMU reports %d processor(s)\n", __FUNCTION__,\r
+    ProcessorCount));\r
+}\r
+\r
+\r
 /**\r
   Perform Platform PEI initialization.\r
 \r
@@ -503,6 +625,8 @@ InitializePlatform (
   IN CONST EFI_PEI_SERVICES     **PeiServices\r
   )\r
 {\r
+  EFI_STATUS    Status;\r
+\r
   DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n"));\r
 \r
   DebugDumpCmos ();\r
@@ -512,11 +636,14 @@ InitializePlatform (
   if (QemuFwCfgS3Enabled ()) {\r
     DEBUG ((EFI_D_INFO, "S3 support was detected on QEMU\n"));\r
     mS3Supported = TRUE;\r
+    Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);\r
+    ASSERT_EFI_ERROR (Status);\r
   }\r
 \r
   S3Verification ();\r
   BootModeInitialization ();\r
   AddressWidthInitialization ();\r
+  MaxCpuCountInitialization ();\r
 \r
   PublishPeiMemory ();\r
 \r
@@ -533,13 +660,16 @@ InitializePlatform (
   mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);\r
 \r
   if (mBootMode != BOOT_ON_S3_RESUME) {\r
-    ReserveEmuVariableNvStore ();\r
+    if (!FeaturePcdGet (PcdSmmSmramRequire)) {\r
+      ReserveEmuVariableNvStore ();\r
+    }\r
     PeiFvInitialization ();\r
     MemMapInitialization ();\r
     NoexecDxeInitialization ();\r
   }\r
 \r
   MiscInitialization ();\r
+  InstallFeatureControlCallback ();\r
 \r
   return EFI_SUCCESS;\r
 }\r