]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg: Introduce XenPlatformPei
authorAnthony PERARD <anthony.perard@citrix.com>
Tue, 13 Aug 2019 11:30:48 +0000 (12:30 +0100)
committerLaszlo Ersek <lersek@redhat.com>
Wed, 21 Aug 2019 16:03:49 +0000 (18:03 +0200)
Introduce XenPlatformPei, a copy of OvmfPkg/PlatformPei without some
of QEMU specific initialization, Xen does not support QemuFwCfg.

This new module will be adjusted to accommodate Xen PVH.

fw_cfg dependents that have been removed, which are dynamically skipped
when running PlatformPei on Xen:
- GetFirstNonAddress(): controlling the 64-bit PCI MMIO aperture via the
(experimental) "opt/ovmf/X-PciMmio64Mb" file
- GetFirstNonAddress(): honoring the hotplug DIMM area
("etc/reserved-memory-end") in the placement of the 64-bit PCI MMIO
aperture
- NoexecDxeInitialization() is removed, so PcdPropertiesTableEnable and
PcdSetNxForStack are left constant FALSE (not set dynamically from
fw_cfg "opt/ovmf/PcdXxxx")
- MaxCpuCountInitialization(), PublishPeiMemory(): the max CPU count is
not taken from the QemuFwCfgItemSmpCpuCount fw_cfg key;
PcdCpuMaxLogicalProcessorNumber is used intact and
PcdCpuApInitTimeOutInMicroSeconds is never changed or used.
- InitializeXenPlatform(), S3Verification(): S3 is assumed disabled (not
consulting "etc/system-states" via QemuFwCfgS3Enabled()).
- InstallFeatureControlCallback(): the feature control MSR is not set
from "etc/msr_feature_control"
(also removed FeatureControl.c as there is nothing been executed)

Also removed:
- SMRAM/TSEG-related low mem size adjusting (PcdSmmSmramRequire is
assumed FALSE) in PublishPeiMemory(),
- QemuInitializeRam() entirely,

Xen related changes:
- Have removed the module variable mXen, as it should be always true.
- Have the platform PEI initialization fails if Xen has not been
  detected.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1689
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20190813113119.14804-5-anthony.perard@citrix.com>

14 files changed:
Maintainers.txt
OvmfPkg/OvmfXen.dsc
OvmfPkg/OvmfXen.fdf
OvmfPkg/XenPlatformPei/AmdSev.c [new file with mode: 0644]
OvmfPkg/XenPlatformPei/ClearCache.c [new file with mode: 0644]
OvmfPkg/XenPlatformPei/Cmos.c [new file with mode: 0644]
OvmfPkg/XenPlatformPei/Cmos.h [new file with mode: 0644]
OvmfPkg/XenPlatformPei/Fv.c [new file with mode: 0644]
OvmfPkg/XenPlatformPei/MemDetect.c [new file with mode: 0644]
OvmfPkg/XenPlatformPei/Platform.c [new file with mode: 0644]
OvmfPkg/XenPlatformPei/Platform.h [new file with mode: 0644]
OvmfPkg/XenPlatformPei/Xen.c [new file with mode: 0644]
OvmfPkg/XenPlatformPei/Xen.h [new file with mode: 0644]
OvmfPkg/XenPlatformPei/XenPlatformPei.inf [new file with mode: 0644]

index 34bdb275b4b33a01b52bf7df256cb776cd80f72c..42ec8d54afb0ce1e6a94e4987a70d05e2e8ea86c 100644 (file)
@@ -379,6 +379,7 @@ F: OvmfPkg/PlatformPei/Xen.*
 F: OvmfPkg/SmbiosPlatformDxe/*Xen.c\r
 F: OvmfPkg/XenBusDxe/\r
 F: OvmfPkg/XenIoPciDxe/\r
+F: OvmfPkg/XenPlatformPei/\r
 F: OvmfPkg/XenPvBlkDxe/\r
 F: OvmfPkg/XenResetVector/\r
 R: Anthony Perard <anthony.perard@citrix.com>\r
index 1a0e59f0ccfe3ceb6acd646e47cbfe486700642d..7619a893828e9fc18ea4d5bcb1ec0c34f3ee5758 100644 (file)
   }\r
   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf\r
 \r
-  OvmfPkg/PlatformPei/PlatformPei.inf\r
+  OvmfPkg/XenPlatformPei/XenPlatformPei.inf\r
   UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf\r
   UefiCpuPkg/CpuMpPei/CpuMpPei.inf\r
 \r
index 6fc8479aae9bb1232316a7d3e43a92abdf50f9d6..2ceff7baa2c78f383bb246087a13a1d655281a81 100644 (file)
@@ -152,7 +152,7 @@ INF  MdeModulePkg/Core/Pei/PeiMain.inf
 INF  MdeModulePkg/Universal/PCD/Pei/Pcd.inf\r
 INF  MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf\r
 INF  MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf\r
-INF  OvmfPkg/PlatformPei/PlatformPei.inf\r
+INF  OvmfPkg/XenPlatformPei/XenPlatformPei.inf\r
 INF  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf\r
 INF  UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf\r
 INF  UefiCpuPkg/CpuMpPei/CpuMpPei.inf\r
diff --git a/OvmfPkg/XenPlatformPei/AmdSev.c b/OvmfPkg/XenPlatformPei/AmdSev.c
new file mode 100644 (file)
index 0000000..7ebbb5c
--- /dev/null
@@ -0,0 +1,64 @@
+/**@file\r
+  Initialize Secure Encrypted Virtualization (SEV) support\r
+\r
+  Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <PiPei.h>\r
+#include <Register/Amd/Cpuid.h>\r
+#include <Register/Cpuid.h>\r
+\r
+#include "Platform.h"\r
+\r
+/**\r
+\r
+  Function checks if SEV support is available, if present then it sets\r
+  the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.\r
+\r
+  **/\r
+VOID\r
+AmdSevInitialize (\r
+  VOID\r
+  )\r
+{\r
+  CPUID_MEMORY_ENCRYPTION_INFO_EBX  Ebx;\r
+  UINT64                            EncryptionMask;\r
+  RETURN_STATUS                     PcdStatus;\r
+\r
+  //\r
+  // Check if SEV is enabled\r
+  //\r
+  if (!MemEncryptSevIsEnabled ()) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position)\r
+  //\r
+  AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL);\r
+  EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits);\r
+\r
+  //\r
+  // Set Memory Encryption Mask PCD\r
+  //\r
+  PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+  DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));\r
+\r
+  //\r
+  // Set Pcd to Deny the execution of option ROM when security\r
+  // violation.\r
+  //\r
+  PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+}\r
diff --git a/OvmfPkg/XenPlatformPei/ClearCache.c b/OvmfPkg/XenPlatformPei/ClearCache.c
new file mode 100644 (file)
index 0000000..fab5363
--- /dev/null
@@ -0,0 +1,112 @@
+/**@file\r
+  Install a callback to clear cache on all processors.\r
+  This is for conformance with the TCG "Platform Reset Attack Mitigation\r
+  Specification". Because clearing the CPU caches at boot doesn't impact\r
+  performance significantly, do it unconditionally, for simplicity's\r
+  sake.\r
+\r
+  Copyright (C) 2018, Red Hat, Inc.\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Ppi/MpServices.h>\r
+\r
+#include "Platform.h"\r
+\r
+/**\r
+  Invalidate data & instruction caches.\r
+  All APs execute this function in parallel. The BSP executes the function\r
+  separately.\r
+\r
+  @param[in,out] WorkSpace  Pointer to the input/output argument workspace\r
+                            shared by all processors.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ClearCache (\r
+  IN OUT VOID *WorkSpace\r
+  )\r
+{\r
+  WriteBackInvalidateDataCache ();\r
+  InvalidateInstructionCache ();\r
+}\r
+\r
+/**\r
+  Notification function called when EFI_PEI_MP_SERVICES_PPI becomes available.\r
+\r
+  @param[in] PeiServices      Indirect reference to the PEI Services Table.\r
+  @param[in] NotifyDescriptor Address of the notification descriptor data\r
+                              structure.\r
+  @param[in] Ppi              Address of the PPI that was installed.\r
+\r
+  @return  Status of the notification. The status code returned from this\r
+           function is ignored.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ClearCacheOnMpServicesAvailable (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,\r
+  IN VOID                       *Ppi\r
+  )\r
+{\r
+  EFI_PEI_MP_SERVICES_PPI *MpServices;\r
+  EFI_STATUS              Status;\r
+\r
+  DEBUG ((DEBUG_INFO, "%a: %a\n", gEfiCallerBaseName, __FUNCTION__));\r
+\r
+  //\r
+  // Clear cache on all the APs in parallel.\r
+  //\r
+  MpServices = Ppi;\r
+  Status = MpServices->StartupAllAPs (\r
+                         (CONST EFI_PEI_SERVICES **)PeiServices,\r
+                         MpServices,\r
+                         ClearCache,          // Procedure\r
+                         FALSE,               // SingleThread\r
+                         0,                   // TimeoutInMicroSeconds: inf.\r
+                         NULL                 // ProcedureArgument\r
+                         );\r
+  if (EFI_ERROR (Status) && Status != EFI_NOT_STARTED) {\r
+    DEBUG ((DEBUG_ERROR, "%a: StartupAllAps(): %r\n", __FUNCTION__, Status));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Now clear cache on the BSP too.\r
+  //\r
+  ClearCache (NULL);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// Notification object for registering the callback, for when\r
+// EFI_PEI_MP_SERVICES_PPI becomes available.\r
+//\r
+STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mMpServicesNotify = {\r
+  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | // Flags\r
+  EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+  &gEfiPeiMpServicesPpiGuid,               // Guid\r
+  ClearCacheOnMpServicesAvailable          // Notify\r
+};\r
+\r
+VOID\r
+InstallClearCacheCallback (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+\r
+  Status = PeiServicesNotifyPpi (&mMpServicesNotify);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: failed to set up MP Services callback: %r\n",\r
+      __FUNCTION__, Status));\r
+  }\r
+}\r
diff --git a/OvmfPkg/XenPlatformPei/Cmos.c b/OvmfPkg/XenPlatformPei/Cmos.c
new file mode 100644 (file)
index 0000000..5d9ee67
--- /dev/null
@@ -0,0 +1,60 @@
+/** @file\r
+  PC/AT CMOS access routines\r
+\r
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+\r
+#include "Cmos.h"\r
+#include "Library/IoLib.h"\r
+\r
+/**\r
+  Reads 8-bits of CMOS data.\r
+\r
+  Reads the 8-bits of CMOS data at the location specified by Index.\r
+  The 8-bit read value is returned.\r
+\r
+  @param  Index  The CMOS location to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+CmosRead8 (\r
+  IN      UINTN                     Index\r
+  )\r
+{\r
+  IoWrite8 (0x70, (UINT8) Index);\r
+  return IoRead8 (0x71);\r
+}\r
+\r
+\r
+/**\r
+  Writes 8-bits of CMOS data.\r
+\r
+  Writes 8-bits of CMOS data to the location specified by Index\r
+  with the value specified by Value and returns Value.\r
+\r
+  @param  Index  The CMOS location to write.\r
+  @param  Value  The value to write to CMOS.\r
+\r
+  @return The value written to CMOS.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+CmosWrite8 (\r
+  IN      UINTN                     Index,\r
+  IN      UINT8                     Value\r
+  )\r
+{\r
+  IoWrite8 (0x70, (UINT8) Index);\r
+  IoWrite8 (0x71, Value);\r
+  return Value;\r
+}\r
+\r
diff --git a/OvmfPkg/XenPlatformPei/Cmos.h b/OvmfPkg/XenPlatformPei/Cmos.h
new file mode 100644 (file)
index 0000000..80ffcb0
--- /dev/null
@@ -0,0 +1,52 @@
+/** @file\r
+  PC/AT CMOS access routines\r
+\r
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef __CMOS_H__\r
+#define __CMOS_H__\r
+\r
+/**\r
+  Reads 8-bits of CMOS data.\r
+\r
+  Reads the 8-bits of CMOS data at the location specified by Index.\r
+  The 8-bit read value is returned.\r
+\r
+  @param  Index  The CMOS location to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+CmosRead8 (\r
+  IN      UINTN                     Index\r
+  );\r
+\r
+/**\r
+  Writes 8-bits of CMOS data.\r
+\r
+  Writes 8-bits of CMOS data to the location specified by Index\r
+  with the value specified by Value and returns Value.\r
+\r
+  @param  Index  The CMOS location to write.\r
+  @param  Value  The value to write to CMOS.\r
+\r
+  @return The value written to CMOS.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+CmosWrite8 (\r
+  IN      UINTN                     Index,\r
+  IN      UINT8                     Value\r
+  );\r
+\r
+\r
+#endif\r
+\r
diff --git a/OvmfPkg/XenPlatformPei/Fv.c b/OvmfPkg/XenPlatformPei/Fv.c
new file mode 100644 (file)
index 0000000..70e9b52
--- /dev/null
@@ -0,0 +1,76 @@
+/** @file\r
+  Build FV related hobs for platform.\r
+\r
+  Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "PiPei.h"\r
+#include "Platform.h"\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+\r
+/**\r
+  Publish PEI & DXE (Decompressed) Memory based FVs to let PEI\r
+  and DXE know about them.\r
+\r
+  @retval EFI_SUCCESS   Platform PEI FVs were initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiFvInitialization (\r
+  VOID\r
+  )\r
+{\r
+  DEBUG ((DEBUG_INFO, "Platform PEI Firmware Volume Initialization\n"));\r
+\r
+  //\r
+  // Create a memory allocation HOB for the PEI FV.\r
+  //\r
+  // Allocate as ACPI NVS is S3 is supported\r
+  //\r
+  BuildMemoryAllocationHob (\r
+    PcdGet32 (PcdOvmfPeiMemFvBase),\r
+    PcdGet32 (PcdOvmfPeiMemFvSize),\r
+    EfiBootServicesData\r
+    );\r
+\r
+  //\r
+  // Let DXE know about the DXE FV\r
+  //\r
+  BuildFvHob (PcdGet32 (PcdOvmfDxeMemFvBase), PcdGet32 (PcdOvmfDxeMemFvSize));\r
+\r
+  //\r
+  // Create a memory allocation HOB for the DXE FV.\r
+  //\r
+  // If "secure" S3 is needed, then SEC will decompress both PEI and DXE\r
+  // firmware volumes at S3 resume too, hence we need to keep away the OS from\r
+  // DXEFV as well. Otherwise we only need to keep away DXE itself from the\r
+  // DXEFV area.\r
+  //\r
+  BuildMemoryAllocationHob (\r
+    PcdGet32 (PcdOvmfDxeMemFvBase),\r
+    PcdGet32 (PcdOvmfDxeMemFvSize),\r
+    EfiBootServicesData\r
+    );\r
+\r
+  //\r
+  // Let PEI know about the DXE FV so it can find the DXE Core\r
+  //\r
+  PeiServicesInstallFvInfoPpi (\r
+    NULL,\r
+    (VOID *)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase),\r
+    PcdGet32 (PcdOvmfDxeMemFvSize),\r
+    NULL,\r
+    NULL\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/OvmfPkg/XenPlatformPei/MemDetect.c b/OvmfPkg/XenPlatformPei/MemDetect.c
new file mode 100644 (file)
index 0000000..cf95f9c
--- /dev/null
@@ -0,0 +1,421 @@
+/**@file\r
+  Memory Detection for Virtual Machines.\r
+\r
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+Module Name:\r
+\r
+  MemDetect.c\r
+\r
+**/\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <IndustryStandard/Q35MchIch9.h>\r
+#include <PiPei.h>\r
+\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/ResourcePublicationLib.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
+STATIC UINT16 mQ35TsegMbytes;\r
+\r
+VOID\r
+Q35TsegMbytesInitialization (\r
+  VOID\r
+  )\r
+{\r
+  UINT16        ExtendedTsegMbytes;\r
+  RETURN_STATUS PcdStatus;\r
+\r
+  if (mHostBridgeDevId != INTEL_Q35_MCH_DEVICE_ID) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "\r
+      "only DID=0x%04x (Q35) is supported\n",\r
+      __FUNCTION__,\r
+      mHostBridgeDevId,\r
+      INTEL_Q35_MCH_DEVICE_ID\r
+      ));\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
+\r
+  //\r
+  // Check if QEMU offers an extended TSEG.\r
+  //\r
+  // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB\r
+  // register, and reading back the register.\r
+  //\r
+  // On a QEMU machine type that does not offer an extended TSEG, the initial\r
+  // write overwrites whatever value a malicious guest OS may have placed in\r
+  // the (unimplemented) register, before entering S3 or rebooting.\r
+  // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.\r
+  //\r
+  // On a QEMU machine type that offers an extended TSEG, the initial write\r
+  // triggers an update to the register. Subsequently, the value read back\r
+  // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the\r
+  // number of megabytes.\r
+  //\r
+  PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY);\r
+  ExtendedTsegMbytes = PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB));\r
+  if (ExtendedTsegMbytes == MCH_EXT_TSEG_MB_QUERY) {\r
+    mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);\r
+    return;\r
+  }\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "%a: QEMU offers an extended TSEG (%d MB)\n",\r
+    __FUNCTION__,\r
+    ExtendedTsegMbytes\r
+    ));\r
+  PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+  mQ35TsegMbytes = ExtendedTsegMbytes;\r
+}\r
+\r
+\r
+UINT32\r
+GetSystemMemorySizeBelow4gb (\r
+  VOID\r
+  )\r
+{\r
+  UINT8 Cmos0x34;\r
+  UINT8 Cmos0x35;\r
+\r
+  //\r
+  // CMOS 0x34/0x35 specifies the system memory above 16 MB.\r
+  // * CMOS(0x35) is the high byte\r
+  // * CMOS(0x34) is the low byte\r
+  // * The size is specified in 64kb chunks\r
+  // * Since this is memory above 16MB, the 16MB must be added\r
+  //   into the calculation to get the total memory size.\r
+  //\r
+\r
+  Cmos0x34 = (UINT8) CmosRead8 (0x34);\r
+  Cmos0x35 = (UINT8) CmosRead8 (0x35);\r
+\r
+  return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);\r
+}\r
+\r
+\r
+STATIC\r
+UINT64\r
+GetSystemMemorySizeAbove4gb (\r
+  )\r
+{\r
+  UINT32 Size;\r
+  UINTN  CmosIndex;\r
+\r
+  //\r
+  // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.\r
+  // * CMOS(0x5d) is the most significant size byte\r
+  // * CMOS(0x5c) is the middle size byte\r
+  // * CMOS(0x5b) is the least significant size byte\r
+  // * The size is specified in 64kb chunks\r
+  //\r
+\r
+  Size = 0;\r
+  for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {\r
+    Size = (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex);\r
+  }\r
+\r
+  return LShiftU64 (Size, 16);\r
+}\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
+  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
+  if (Pci64Size == 0) {\r
+    if (mBootMode != BOOT_ON_S3_RESUME) {\r
+      DEBUG ((DEBUG_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
+  // 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 ((DEBUG_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
+VOID\r
+AddressWidthInitialization (\r
+  VOID\r
+  )\r
+{\r
+  UINT64 FirstNonAddress;\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
+  //\r
+  FirstNonAddress      = GetFirstNonAddress ();\r
+  mPhysMemAddressWidth = (UINT8)HighBitSet64 (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
+    ++mPhysMemAddressWidth;\r
+  }\r
+\r
+  //\r
+  // The minimum address width is 36 (covers up to and excluding 64 GB, which\r
+  // is the maximum for Ia32 + PAE). The theoretical architecture maximum for\r
+  // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We\r
+  // can simply assert that here, since 48 bits are good enough for 256 TB.\r
+  //\r
+  if (mPhysMemAddressWidth <= 36) {\r
+    mPhysMemAddressWidth = 36;\r
+  }\r
+  ASSERT (mPhysMemAddressWidth <= 48);\r
+}\r
+\r
+\r
+/**\r
+  Calculate the cap for the permanent PEI memory.\r
+**/\r
+STATIC\r
+UINT32\r
+GetPeiMemoryCap (\r
+  VOID\r
+  )\r
+{\r
+  BOOLEAN Page1GSupport;\r
+  UINT32  RegEax;\r
+  UINT32  RegEdx;\r
+  UINT32  Pml4Entries;\r
+  UINT32  PdpEntries;\r
+  UINTN   TotalPages;\r
+\r
+  //\r
+  // If DXE is 32-bit, then just return the traditional 64 MB cap.\r
+  //\r
+#ifdef MDE_CPU_IA32\r
+  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
+    return SIZE_64MB;\r
+  }\r
+#endif\r
+\r
+  //\r
+  // Dependent on physical address width, PEI memory allocations can be\r
+  // dominated by the page tables built for 64-bit DXE. So we key the cap off\r
+  // of those. The code below is based on CreateIdentityMappingPageTables() in\r
+  // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".\r
+  //\r
+  Page1GSupport = FALSE;\r
+  if (PcdGetBool (PcdUse1GPageTable)) {\r
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+    if (RegEax >= 0x80000001) {\r
+      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
+      if ((RegEdx & BIT26) != 0) {\r
+        Page1GSupport = TRUE;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (mPhysMemAddressWidth <= 39) {\r
+    Pml4Entries = 1;\r
+    PdpEntries = 1 << (mPhysMemAddressWidth - 30);\r
+    ASSERT (PdpEntries <= 0x200);\r
+  } else {\r
+    Pml4Entries = 1 << (mPhysMemAddressWidth - 39);\r
+    ASSERT (Pml4Entries <= 0x200);\r
+    PdpEntries = 512;\r
+  }\r
+\r
+  TotalPages = Page1GSupport ? Pml4Entries + 1 :\r
+                               (PdpEntries + 1) * Pml4Entries + 1;\r
+  ASSERT (TotalPages <= 0x40201);\r
+\r
+  //\r
+  // Add 64 MB for miscellaneous allocations. Note that for\r
+  // mPhysMemAddressWidth values close to 36, the cap will actually be\r
+  // dominated by this increment.\r
+  //\r
+  return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);\r
+}\r
+\r
+\r
+/**\r
+  Publish PEI core memory\r
+\r
+  @return EFI_SUCCESS     The PEIM initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+PublishPeiMemory (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase;\r
+  UINT64                      MemorySize;\r
+  UINT32                      LowerMemorySize;\r
+  UINT32                      PeiMemoryCap;\r
+\r
+  LowerMemorySize = GetSystemMemorySizeBelow4gb ();\r
+\r
+  if (mBootMode == BOOT_ON_S3_RESUME) {\r
+    MemoryBase = mS3AcpiReservedMemoryBase;\r
+    MemorySize = mS3AcpiReservedMemorySize;\r
+  } else {\r
+    PeiMemoryCap = GetPeiMemoryCap ();\r
+    DEBUG ((DEBUG_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",\r
+      __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));\r
+\r
+    //\r
+    // Determine the range of memory to use during PEI\r
+    //\r
+    MemoryBase =\r
+      PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);\r
+    MemorySize = LowerMemorySize - MemoryBase;\r
+    if (MemorySize > PeiMemoryCap) {\r
+      MemoryBase = LowerMemorySize - PeiMemoryCap;\r
+      MemorySize = PeiMemoryCap;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Publish this memory to the PEI Core\r
+  //\r
+  Status = PublishSystemMemory(MemoryBase, MemorySize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Publish system RAM and reserve memory regions\r
+\r
+**/\r
+VOID\r
+InitializeRamRegions (\r
+  VOID\r
+  )\r
+{\r
+  XenPublishRamRegions ();\r
+\r
+  if (mBootMode != BOOT_ON_S3_RESUME) {\r
+    //\r
+    // Reserve the lock box storage area\r
+    //\r
+    // Since this memory range will be used on S3 resume, it must be\r
+    // reserved as ACPI NVS.\r
+    //\r
+    // If S3 is unsupported, then various drivers might still write to the\r
+    // LockBox area. We ought to prevent DXE from serving allocation requests\r
+    // such that they would overlap the LockBox storage.\r
+    //\r
+    ZeroMem (\r
+      (VOID*)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),\r
+      (UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize)\r
+      );\r
+    BuildMemoryAllocationHob (\r
+      (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),\r
+      (UINT64)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize),\r
+      EfiBootServicesData\r
+      );\r
+  }\r
+}\r
diff --git a/OvmfPkg/XenPlatformPei/Platform.c b/OvmfPkg/XenPlatformPei/Platform.c
new file mode 100644 (file)
index 0000000..5809ead
--- /dev/null
@@ -0,0 +1,444 @@
+/**@file\r
+  Platform PEI driver\r
+\r
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiPei.h>\r
+\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/ResourcePublicationLib.h>\r
+#include <Guid/MemoryTypeInformation.h>\r
+#include <Ppi/MasterBootMode.h>\r
+#include <IndustryStandard/Pci22.h>\r
+#include <OvmfPlatforms.h>\r
+\r
+#include "Platform.h"\r
+#include "Cmos.h"\r
+\r
+EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {\r
+  { EfiACPIMemoryNVS,       0x004 },\r
+  { EfiACPIReclaimMemory,   0x008 },\r
+  { EfiReservedMemoryType,  0x004 },\r
+  { EfiRuntimeServicesData, 0x024 },\r
+  { EfiRuntimeServicesCode, 0x030 },\r
+  { EfiBootServicesCode,    0x180 },\r
+  { EfiBootServicesData,    0xF00 },\r
+  { EfiMaxMemoryType,       0x000 }\r
+};\r
+\r
+\r
+EFI_PEI_PPI_DESCRIPTOR   mPpiBootMode[] = {\r
+  {\r
+    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+    &gEfiPeiMasterBootModePpiGuid,\r
+    NULL\r
+  }\r
+};\r
+\r
+\r
+UINT16 mHostBridgeDevId;\r
+\r
+EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;\r
+\r
+\r
+VOID\r
+AddIoMemoryBaseSizeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  UINT64                      MemorySize\r
+  )\r
+{\r
+  BuildResourceDescriptorHob (\r
+    EFI_RESOURCE_MEMORY_MAPPED_IO,\r
+      EFI_RESOURCE_ATTRIBUTE_PRESENT     |\r
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+      EFI_RESOURCE_ATTRIBUTE_TESTED,\r
+    MemoryBase,\r
+    MemorySize\r
+    );\r
+}\r
+\r
+VOID\r
+AddReservedMemoryBaseSizeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  UINT64                      MemorySize,\r
+  BOOLEAN                     Cacheable\r
+  )\r
+{\r
+  BuildResourceDescriptorHob (\r
+    EFI_RESOURCE_MEMORY_RESERVED,\r
+      EFI_RESOURCE_ATTRIBUTE_PRESENT     |\r
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+      (Cacheable ?\r
+       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :\r
+       0\r
+       ) |\r
+      EFI_RESOURCE_ATTRIBUTE_TESTED,\r
+    MemoryBase,\r
+    MemorySize\r
+    );\r
+}\r
+\r
+VOID\r
+AddIoMemoryRangeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  EFI_PHYSICAL_ADDRESS        MemoryLimit\r
+  )\r
+{\r
+  AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));\r
+}\r
+\r
+\r
+VOID\r
+AddMemoryBaseSizeHob (\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
+      EFI_RESOURCE_ATTRIBUTE_TESTED,\r
+    MemoryBase,\r
+    MemorySize\r
+    );\r
+}\r
+\r
+\r
+VOID\r
+AddMemoryRangeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  EFI_PHYSICAL_ADDRESS        MemoryLimit\r
+  )\r
+{\r
+  AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));\r
+}\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
+  BuildGuidDataHob (\r
+    &gEfiMemoryTypeInformationGuid,\r
+    mDefaultMemoryTypeInformation,\r
+    sizeof(mDefaultMemoryTypeInformation)\r
+    );\r
+\r
+  //\r
+  // Video memory + Legacy BIOS region\r
+  //\r
+  AddIoMemoryRangeHob (0x0A0000, BASE_1MB);\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
+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
+  UINT32        PmbaAndVal;\r
+  UINT32        PmbaOrVal;\r
+  UINTN         AcpiCtlReg;\r
+  UINT8         AcpiEnBit;\r
+  RETURN_STATUS PcdStatus;\r
+\r
+  //\r
+  // Disable A20 Mask\r
+  //\r
+  IoOr8 (0x92, BIT1);\r
+\r
+  //\r
+  // Build the CPU HOB with guest RAM size dependent address width and 16-bits\r
+  // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during\r
+  // S3 resume as well, so we build it unconditionally.)\r
+  //\r
+  BuildCpuHob (mPhysMemAddressWidth, 16);\r
+\r
+  //\r
+  // Determine platform type and save Host Bridge DID to PCD\r
+  //\r
+  switch (mHostBridgeDevId) {\r
+    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
+    default:\r
+      DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
+        __FUNCTION__, mHostBridgeDevId));\r
+      ASSERT (FALSE);\r
+      return;\r
+  }\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
+  // has been configured (e.g., by Xen) and skip the setup here.\r
+  // This matches the logic in AcpiTimerLibConstructor ().\r
+  //\r
+  if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {\r
+    //\r
+    // The PEI phase should be exited with fully accessibe ACPI PM IO space:\r
+    // 1. set PMBA\r
+    //\r
+    PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);\r
+\r
+    //\r
+    // 2. set PCICMD/IOSE\r
+    //\r
+    PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);\r
+\r
+    //\r
+    // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)\r
+    //\r
+    PciOr8 (AcpiCtlReg, AcpiEnBit);\r
+  }\r
+\r
+  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {\r
+    //\r
+    // Set Root Complex Register Block BAR\r
+    //\r
+    PciWrite32 (\r
+      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
+\r
+VOID\r
+BootModeInitialization (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  if (CmosRead8 (0xF) == 0xFE) {\r
+    mBootMode = BOOT_ON_S3_RESUME;\r
+  }\r
+  CmosWrite8 (0xF, 0x00);\r
+\r
+  Status = PeiServicesSetBootMode (mBootMode);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = PeiServicesInstallPpi (mPpiBootMode);\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+\r
+VOID\r
+ReserveEmuVariableNvStore (\r
+  )\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
+  // at a consistent address.  Since VM memory is preserved\r
+  // across reboots, this allows the NV variable storage to survive\r
+  // a VM reboot.\r
+  //\r
+  VariableStore =\r
+    (EFI_PHYSICAL_ADDRESS)(UINTN)\r
+      AllocateRuntimePages (\r
+        EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))\r
+        );\r
+  DEBUG ((DEBUG_INFO,\r
+          "Reserved variable store memory: 0x%lX; size: %dkb\n",\r
+          VariableStore,\r
+          (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024\r
+        ));\r
+  PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+}\r
+\r
+\r
+VOID\r
+DebugDumpCmos (\r
+  VOID\r
+  )\r
+{\r
+  UINT32 Loop;\r
+\r
+  DEBUG ((DEBUG_INFO, "CMOS:\n"));\r
+\r
+  for (Loop = 0; Loop < 0x80; Loop++) {\r
+    if ((Loop % 0x10) == 0) {\r
+      DEBUG ((DEBUG_INFO, "%02x:", Loop));\r
+    }\r
+    DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));\r
+    if ((Loop % 0x10) == 0xf) {\r
+      DEBUG ((DEBUG_INFO, "\n"));\r
+    }\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Perform Platform PEI initialization.\r
+\r
+  @param  FileHandle      Handle of the file being invoked.\r
+  @param  PeiServices     Describes the list of possible PEI Services.\r
+\r
+  @return EFI_SUCCESS     The PEIM initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeXenPlatform (\r
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,\r
+  IN CONST EFI_PEI_SERVICES     **PeiServices\r
+  )\r
+{\r
+  DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));\r
+\r
+  DebugDumpCmos ();\r
+\r
+  if (!XenDetect ()) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR: Xen isn't detected\n"));\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
+\r
+  BootModeInitialization ();\r
+  AddressWidthInitialization ();\r
+\r
+  //\r
+  // Query Host Bridge DID\r
+  //\r
+  mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);\r
+\r
+  PublishPeiMemory ();\r
+\r
+  InitializeRamRegions ();\r
+\r
+  InitializeXen ();\r
+\r
+  if (mBootMode != BOOT_ON_S3_RESUME) {\r
+    ReserveEmuVariableNvStore ();\r
+    PeiFvInitialization ();\r
+    MemMapInitialization ();\r
+  }\r
+\r
+  InstallClearCacheCallback ();\r
+  AmdSevInitialize ();\r
+  MiscInitialization ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/OvmfPkg/XenPlatformPei/Platform.h b/OvmfPkg/XenPlatformPei/Platform.h
new file mode 100644 (file)
index 0000000..7742749
--- /dev/null
@@ -0,0 +1,108 @@
+/** @file\r
+  Platform PEI module include file.\r
+\r
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef _PLATFORM_PEI_H_INCLUDED_\r
+#define _PLATFORM_PEI_H_INCLUDED_\r
+\r
+#include <IndustryStandard/E820.h>\r
+\r
+VOID\r
+AddIoMemoryBaseSizeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  UINT64                      MemorySize\r
+  );\r
+\r
+VOID\r
+AddIoMemoryRangeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  EFI_PHYSICAL_ADDRESS        MemoryLimit\r
+  );\r
+\r
+VOID\r
+AddMemoryBaseSizeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  UINT64                      MemorySize\r
+  );\r
+\r
+VOID\r
+AddMemoryRangeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  EFI_PHYSICAL_ADDRESS        MemoryLimit\r
+  );\r
+\r
+VOID\r
+AddReservedMemoryBaseSizeHob (\r
+  EFI_PHYSICAL_ADDRESS        MemoryBase,\r
+  UINT64                      MemorySize,\r
+  BOOLEAN                     Cacheable\r
+  );\r
+\r
+VOID\r
+AddressWidthInitialization (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+Q35TsegMbytesInitialization (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+PublishPeiMemory (\r
+  VOID\r
+  );\r
+\r
+UINT32\r
+GetSystemMemorySizeBelow4gb (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+InitializeRamRegions (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+PeiFvInitialization (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+InstallClearCacheCallback (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+InitializeXen (\r
+  VOID\r
+  );\r
+\r
+BOOLEAN\r
+XenDetect (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+AmdSevInitialize (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+XenPublishRamRegions (\r
+  VOID\r
+  );\r
+\r
+extern EFI_BOOT_MODE mBootMode;\r
+\r
+extern UINT8 mPhysMemAddressWidth;\r
+\r
+extern UINT16 mHostBridgeDevId;\r
+\r
+#endif // _PLATFORM_PEI_H_INCLUDED_\r
diff --git a/OvmfPkg/XenPlatformPei/Xen.c b/OvmfPkg/XenPlatformPei/Xen.c
new file mode 100644 (file)
index 0000000..f4d0d1c
--- /dev/null
@@ -0,0 +1,219 @@
+/**@file\r
+  Xen Platform PEI support\r
+\r
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>\r
+  Copyright (c) 2019, Citrix Systems, Inc.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiPei.h>\r
+\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Guid/XenInfo.h>\r
+#include <IndustryStandard/E820.h>\r
+#include <Library/ResourcePublicationLib.h>\r
+#include <Library/MtrrLib.h>\r
+\r
+#include "Platform.h"\r
+#include "Xen.h"\r
+\r
+STATIC UINT32 mXenLeaf = 0;\r
+\r
+EFI_XEN_INFO mXenInfo;\r
+\r
+/**\r
+  Returns E820 map provided by Xen\r
+\r
+  @param Entries      Pointer to E820 map\r
+  @param Count        Number of entries\r
+\r
+  @return EFI_STATUS\r
+**/\r
+EFI_STATUS\r
+XenGetE820Map (\r
+  EFI_E820_ENTRY64 **Entries,\r
+  UINT32 *Count\r
+  )\r
+{\r
+  EFI_XEN_OVMF_INFO *Info =\r
+    (EFI_XEN_OVMF_INFO *)(UINTN) OVMF_INFO_PHYSICAL_ADDRESS;\r
+\r
+  if (AsciiStrCmp ((CHAR8 *) Info->Signature, "XenHVMOVMF")) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ASSERT (Info->E820 < MAX_ADDRESS);\r
+  *Entries = (EFI_E820_ENTRY64 *)(UINTN) Info->E820;\r
+  *Count = Info->E820EntriesCount;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Connects to the Hypervisor.\r
+\r
+  @param  XenLeaf     CPUID index used to connect.\r
+\r
+  @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+XenConnect (\r
+  UINT32 XenLeaf\r
+  )\r
+{\r
+  UINT32 Index;\r
+  UINT32 TransferReg;\r
+  UINT32 TransferPages;\r
+  UINT32 XenVersion;\r
+\r
+  AsmCpuid (XenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL);\r
+  mXenInfo.HyperPages = AllocatePages (TransferPages);\r
+  if (!mXenInfo.HyperPages) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Index = 0; Index < TransferPages; Index++) {\r
+    AsmWriteMsr64 (TransferReg,\r
+                   (UINTN) mXenInfo.HyperPages +\r
+                   (Index << EFI_PAGE_SHIFT) + Index);\r
+  }\r
+\r
+  AsmCpuid (XenLeaf + 1, &XenVersion, NULL, NULL, NULL);\r
+  DEBUG ((DEBUG_ERROR, "Detected Xen version %d.%d\n",\r
+          XenVersion >> 16, XenVersion & 0xFFFF));\r
+  mXenInfo.VersionMajor = (UINT16)(XenVersion >> 16);\r
+  mXenInfo.VersionMinor = (UINT16)(XenVersion & 0xFFFF);\r
+\r
+  /* TBD: Locate hvm_info and reserve it away. */\r
+  mXenInfo.HvmInfo = NULL;\r
+\r
+  BuildGuidDataHob (\r
+    &gEfiXenInfoGuid,\r
+    &mXenInfo,\r
+    sizeof(mXenInfo)\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Figures out if we are running inside Xen HVM.\r
+\r
+  @retval TRUE   Xen was detected\r
+  @retval FALSE  Xen was not detected\r
+\r
+**/\r
+BOOLEAN\r
+XenDetect (\r
+  VOID\r
+  )\r
+{\r
+  UINT8 Signature[13];\r
+\r
+  if (mXenLeaf != 0) {\r
+    return TRUE;\r
+  }\r
+\r
+  Signature[12] = '\0';\r
+  for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) {\r
+    AsmCpuid (mXenLeaf,\r
+              NULL,\r
+              (UINT32 *) &Signature[0],\r
+              (UINT32 *) &Signature[4],\r
+              (UINT32 *) &Signature[8]);\r
+\r
+    if (!AsciiStrCmp ((CHAR8 *) Signature, "XenVMMXenVMM")) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  mXenLeaf = 0;\r
+  return FALSE;\r
+}\r
+\r
+\r
+VOID\r
+XenPublishRamRegions (\r
+  VOID\r
+  )\r
+{\r
+  EFI_E820_ENTRY64  *E820Map;\r
+  UINT32            E820EntriesCount;\r
+  EFI_STATUS        Status;\r
+\r
+  DEBUG ((DEBUG_INFO, "Using memory map provided by Xen\n"));\r
+\r
+  //\r
+  // Parse RAM in E820 map\r
+  //\r
+  E820EntriesCount = 0;\r
+  Status = XenGetE820Map (&E820Map, &E820EntriesCount);\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (E820EntriesCount > 0) {\r
+    EFI_E820_ENTRY64 *Entry;\r
+    UINT32 Loop;\r
+\r
+    for (Loop = 0; Loop < E820EntriesCount; Loop++) {\r
+      Entry = E820Map + Loop;\r
+\r
+      //\r
+      // Only care about RAM\r
+      //\r
+      if (Entry->Type != EfiAcpiAddressRangeMemory) {\r
+        continue;\r
+      }\r
+\r
+      AddMemoryBaseSizeHob (Entry->BaseAddr, Entry->Length);\r
+\r
+      MtrrSetMemoryAttribute (Entry->BaseAddr, Entry->Length, CacheWriteBack);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Perform Xen PEI initialization.\r
+\r
+  @return EFI_SUCCESS     Xen initialized successfully\r
+  @return EFI_NOT_FOUND   Not running under Xen\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeXen (\r
+  VOID\r
+  )\r
+{\r
+  RETURN_STATUS PcdStatus;\r
+\r
+  if (mXenLeaf == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  XenConnect (mXenLeaf);\r
+\r
+  //\r
+  // Reserve away HVMLOADER reserved memory [0xFC000000,0xFD000000).\r
+  // This needs to match HVMLOADER RESERVED_MEMBASE/RESERVED_MEMSIZE.\r
+  //\r
+  AddReservedMemoryBaseSizeHob (0xFC000000, 0x1000000, FALSE);\r
+\r
+  PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, TRUE);\r
+  ASSERT_RETURN_ERROR (PcdStatus);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/OvmfPkg/XenPlatformPei/Xen.h b/OvmfPkg/XenPlatformPei/Xen.h
new file mode 100644 (file)
index 0000000..2605481
--- /dev/null
@@ -0,0 +1,39 @@
+/** @file\r
+  Ovmf info structure passed by Xen\r
+\r
+Copyright (c) 2013, Citrix Systems UK Ltd.<BR>\r
+\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef __XEN_H__\r
+#define __XEN_H__\r
+\r
+#include <PiPei.h>\r
+\r
+// Physical address of OVMF info\r
+#define OVMF_INFO_PHYSICAL_ADDRESS 0x00001000\r
+\r
+// This structure must match the definition on Xen side\r
+#pragma pack(1)\r
+typedef struct {\r
+  CHAR8 Signature[14]; // XenHVMOVMF\0\r
+  UINT8 Length;        // Length of this structure\r
+  UINT8 Checksum;      // Set such that the sum over bytes 0..length == 0\r
+  //\r
+  // Physical address of an array of TablesCount elements.\r
+  //\r
+  // Each element contains the physical address of a BIOS table.\r
+  //\r
+  EFI_PHYSICAL_ADDRESS Tables;\r
+  UINT32 TablesCount;\r
+  //\r
+  // Physical address of the E820 table, contains E820EntriesCount entries.\r
+  //\r
+  EFI_PHYSICAL_ADDRESS E820;\r
+  UINT32 E820EntriesCount;\r
+} EFI_XEN_OVMF_INFO;\r
+#pragma pack()\r
+\r
+#endif /* __XEN_H__ */\r
diff --git a/OvmfPkg/XenPlatformPei/XenPlatformPei.inf b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf
new file mode 100644 (file)
index 0000000..d1265c3
--- /dev/null
@@ -0,0 +1,96 @@
+## @file\r
+#  Platform PEI driver\r
+#\r
+#  This module provides platform specific function to detect boot mode.\r
+#  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2019, Citrix Systems, Inc.\r
+#\r
+#  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = XenPlatformPei\r
+  FILE_GUID                      = f112a6ee-993a-4f0b-8295-e52029d9b4ba\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeXenPlatform\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 EBC\r
+#\r
+\r
+[Sources]\r
+  AmdSev.c\r
+  ClearCache.c\r
+  Cmos.c\r
+  Cmos.h\r
+  Fv.c\r
+  MemDetect.c\r
+  Platform.c\r
+  Platform.h\r
+  Xen.c\r
+  Xen.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+  UefiCpuPkg/UefiCpuPkg.dec\r
+  OvmfPkg/OvmfPkg.dec\r
+\r
+[Guids]\r
+  gEfiMemoryTypeInformationGuid\r
+  gEfiXenInfoGuid\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  CacheMaintenanceLib\r
+  DebugLib\r
+  HobLib\r
+  IoLib\r
+  PciLib\r
+  ResourcePublicationLib\r
+  PeiServicesLib\r
+  PeimEntryPoint\r
+  MtrrLib\r
+  MemEncryptSevLib\r
+  PcdLib\r
+\r
+[Pcd]\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy\r
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress\r
+\r
+[FixedPcd]\r
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress\r
+\r
+[Ppis]\r
+  gEfiPeiMasterBootModePpiGuid\r
+  gEfiPeiMpServicesPpiGuid\r
+\r
+[Depex]\r
+  TRUE\r
+\r