diff mbox

[RFC,04/14] OvmfPkg: Introduce XenPlatformPei

Message ID 20161208153340.2285-5-anthony.perard@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Anthony PERARD Dec. 8, 2016, 3:33 p.m. UTC
A copy of OvmfPkg/PlatformPei without some of QEMU specific
initialization, Xen does not support QemuFwCfg.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
---
 OvmfPkg/XenOvmf.dsc                       |   2 +-
 OvmfPkg/XenOvmf.fdf                       |   2 +-
 OvmfPkg/XenPlatformPei/Cmos.c             |  64 ++++
 OvmfPkg/XenPlatformPei/Cmos.h             |  56 ++++
 OvmfPkg/XenPlatformPei/Fv.c               | 100 ++++++
 OvmfPkg/XenPlatformPei/MemDetect.c        | 449 +++++++++++++++++++++++++
 OvmfPkg/XenPlatformPei/Platform.c         | 536 ++++++++++++++++++++++++++++++
 OvmfPkg/XenPlatformPei/Platform.h         | 104 ++++++
 OvmfPkg/XenPlatformPei/Xen.c              | 231 +++++++++++++
 OvmfPkg/XenPlatformPei/Xen.h              |  45 +++
 OvmfPkg/XenPlatformPei/XenPlatformPei.inf | 110 ++++++
 11 files changed, 1697 insertions(+), 2 deletions(-)
 create mode 100644 OvmfPkg/XenPlatformPei/Cmos.c
 create mode 100644 OvmfPkg/XenPlatformPei/Cmos.h
 create mode 100644 OvmfPkg/XenPlatformPei/Fv.c
 create mode 100644 OvmfPkg/XenPlatformPei/MemDetect.c
 create mode 100644 OvmfPkg/XenPlatformPei/Platform.c
 create mode 100644 OvmfPkg/XenPlatformPei/Platform.h
 create mode 100644 OvmfPkg/XenPlatformPei/Xen.c
 create mode 100644 OvmfPkg/XenPlatformPei/Xen.h
 create mode 100644 OvmfPkg/XenPlatformPei/XenPlatformPei.inf

Comments

Laszlo Ersek Jan. 5, 2017, 9:59 a.m. UTC | #1
On 12/08/16 16:33, Anthony PERARD wrote:
> A copy of OvmfPkg/PlatformPei without some of QEMU specific
> initialization, Xen does not support QemuFwCfg.
> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> ---
>  OvmfPkg/XenOvmf.dsc                       |   2 +-
>  OvmfPkg/XenOvmf.fdf                       |   2 +-
>  OvmfPkg/XenPlatformPei/Cmos.c             |  64 ++++
>  OvmfPkg/XenPlatformPei/Cmos.h             |  56 ++++
>  OvmfPkg/XenPlatformPei/Fv.c               | 100 ++++++
>  OvmfPkg/XenPlatformPei/MemDetect.c        | 449 +++++++++++++++++++++++++
>  OvmfPkg/XenPlatformPei/Platform.c         | 536 ++++++++++++++++++++++++++++++
>  OvmfPkg/XenPlatformPei/Platform.h         | 104 ++++++
>  OvmfPkg/XenPlatformPei/Xen.c              | 231 +++++++++++++
>  OvmfPkg/XenPlatformPei/Xen.h              |  45 +++
>  OvmfPkg/XenPlatformPei/XenPlatformPei.inf | 110 ++++++
>  11 files changed, 1697 insertions(+), 2 deletions(-)
>  create mode 100644 OvmfPkg/XenPlatformPei/Cmos.c
>  create mode 100644 OvmfPkg/XenPlatformPei/Cmos.h
>  create mode 100644 OvmfPkg/XenPlatformPei/Fv.c
>  create mode 100644 OvmfPkg/XenPlatformPei/MemDetect.c
>  create mode 100644 OvmfPkg/XenPlatformPei/Platform.c
>  create mode 100644 OvmfPkg/XenPlatformPei/Platform.h
>  create mode 100644 OvmfPkg/XenPlatformPei/Xen.c
>  create mode 100644 OvmfPkg/XenPlatformPei/Xen.h
>  create mode 100644 OvmfPkg/XenPlatformPei/XenPlatformPei.inf

(1) You might want to add Citrix copyright notices to new files.

(2) This module is a good example where the moved Xen functionality
(even for HVM guests) should be possible to remove from the original
PlatformPei module. (In a later, final patch.) Is that right?

(3) In the commit message, please list the removed fw_cfg-dependent
functionality in more detail (all of which is dynamically skipped when
the current PlatformPei module runs 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
"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:
-  SMRAM/TSEG-related low mem size adjusting (PcdSmmSmramRequire is
assumed FALSE) in PublishPeiMemory(),
- QemuInitializeRam() entirely,

(4) I think the removal of PcdSmmSmramRequire is incomplete. IMO this
PCD should either be removed completely (all uses, including the INF
reference), assuming a FALSE value in its place, or the PCD should not
be touched at all. The FeaturePcdGet() call in PublishPeiMemory() --
gating the "TSEG is chipped from the end of low RAM" stuff -- seems to
be singled out for removal for no good reason.

(5) It would be nice to hint at the reason (which is implemented in a
later patch) why a separate module is a good idea here. That is, why the
expected PVH2 functionality is best not added to the current PlatformPei
module.

Thanks
Laszlo

> 
> diff --git a/OvmfPkg/XenOvmf.dsc b/OvmfPkg/XenOvmf.dsc
> index 0a7ea21..ef32c33 100644
> --- a/OvmfPkg/XenOvmf.dsc
> +++ b/OvmfPkg/XenOvmf.dsc
> @@ -496,7 +496,7 @@
>        PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
>    }
>  
> -  OvmfPkg/PlatformPei/PlatformPei.inf {
> +  OvmfPkg/XenPlatformPei/XenPlatformPei.inf {
>      <LibraryClasses>
>        PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
>    }
> diff --git a/OvmfPkg/XenOvmf.fdf b/OvmfPkg/XenOvmf.fdf
> index f4609b0..c211f61 100644
> --- a/OvmfPkg/XenOvmf.fdf
> +++ b/OvmfPkg/XenOvmf.fdf
> @@ -157,7 +157,7 @@ INF  MdeModulePkg/Core/Pei/PeiMain.inf
>  INF  MdeModulePkg/Universal/PCD/Pei/Pcd.inf
>  INF  MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
>  INF  MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
> -INF  OvmfPkg/PlatformPei/PlatformPei.inf
> +INF  OvmfPkg/XenPlatformPei/XenPlatformPei.inf
>  INF  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>  INF  UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
>  !if $(SMM_REQUIRE) == TRUE
> diff --git a/OvmfPkg/XenPlatformPei/Cmos.c b/OvmfPkg/XenPlatformPei/Cmos.c
> new file mode 100644
> index 0000000..48ed2cb
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/Cmos.c
> @@ -0,0 +1,64 @@
> +/** @file
> +  PC/AT CMOS access routines
> +
> +  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD License
> +  which accompanies this distribution.  The full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +
> +#include "Cmos.h"
> +#include "Library/IoLib.h"
> +
> +/**
> +  Reads 8-bits of CMOS data.
> +
> +  Reads the 8-bits of CMOS data at the location specified by Index.
> +  The 8-bit read value is returned.
> +
> +  @param  Index  The CMOS location to read.
> +
> +  @return The value read.
> +
> +**/
> +UINT8
> +EFIAPI
> +CmosRead8 (
> +  IN      UINTN                     Index
> +  )
> +{
> +  IoWrite8 (0x70, (UINT8) Index);
> +  return IoRead8 (0x71);
> +}
> +
> +
> +/**
> +  Writes 8-bits of CMOS data.
> +
> +  Writes 8-bits of CMOS data to the location specified by Index
> +  with the value specified by Value and returns Value.
> +
> +  @param  Index  The CMOS location to write.
> +  @param  Value  The value to write to CMOS.
> +
> +  @return The value written to CMOS.
> +
> +**/
> +UINT8
> +EFIAPI
> +CmosWrite8 (
> +  IN      UINTN                     Index,
> +  IN      UINT8                     Value
> +  )
> +{
> +  IoWrite8 (0x70, (UINT8) Index);
> +  IoWrite8 (0x71, Value);
> +  return Value;
> +}
> +
> diff --git a/OvmfPkg/XenPlatformPei/Cmos.h b/OvmfPkg/XenPlatformPei/Cmos.h
> new file mode 100644
> index 0000000..949f884
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/Cmos.h
> @@ -0,0 +1,56 @@
> +/** @file
> +  PC/AT CMOS access routines
> +
> +  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD License
> +  which accompanies this distribution.  The full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __CMOS_H__
> +#define __CMOS_H__
> +
> +/**
> +  Reads 8-bits of CMOS data.
> +
> +  Reads the 8-bits of CMOS data at the location specified by Index.
> +  The 8-bit read value is returned.
> +
> +  @param  Index  The CMOS location to read.
> +
> +  @return The value read.
> +
> +**/
> +UINT8
> +EFIAPI
> +CmosRead8 (
> +  IN      UINTN                     Index
> +  );
> +
> +/**
> +  Writes 8-bits of CMOS data.
> +
> +  Writes 8-bits of CMOS data to the location specified by Index
> +  with the value specified by Value and returns Value.
> +
> +  @param  Index  The CMOS location to write.
> +  @param  Value  The value to write to CMOS.
> +
> +  @return The value written to CMOS.
> +
> +**/
> +UINT8
> +EFIAPI
> +CmosWrite8 (
> +  IN      UINTN                     Index,
> +  IN      UINT8                     Value
> +  );
> +
> +
> +#endif
> +
> diff --git a/OvmfPkg/XenPlatformPei/Fv.c b/OvmfPkg/XenPlatformPei/Fv.c
> new file mode 100644
> index 0000000..248c585
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/Fv.c
> @@ -0,0 +1,100 @@
> +/** @file
> +  Build FV related hobs for platform.
> +
> +  Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD License
> +  which accompanies this distribution.  The full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "PiPei.h"
> +#include "Platform.h"
> +#include <Library/DebugLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/PcdLib.h>
> +
> +
> +/**
> +  Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
> +  and DXE know about them.
> +
> +  @retval EFI_SUCCESS   Platform PEI FVs were initialized successfully.
> +
> +**/
> +EFI_STATUS
> +PeiFvInitialization (
> +  VOID
> +  )
> +{
> +  BOOLEAN SecureS3Needed;
> +
> +  DEBUG ((EFI_D_INFO, "Platform PEI Firmware Volume Initialization\n"));
> +
> +  //
> +  // Create a memory allocation HOB for the PEI FV.
> +  //
> +  // Allocate as ACPI NVS is S3 is supported
> +  //
> +  BuildMemoryAllocationHob (
> +    PcdGet32 (PcdOvmfPeiMemFvBase),
> +    PcdGet32 (PcdOvmfPeiMemFvSize),
> +    mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
> +    );
> +
> +  //
> +  // Let DXE know about the DXE FV
> +  //
> +  BuildFvHob (PcdGet32 (PcdOvmfDxeMemFvBase), PcdGet32 (PcdOvmfDxeMemFvSize));
> +
> +  SecureS3Needed = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire);
> +
> +  //
> +  // Create a memory allocation HOB for the DXE FV.
> +  //
> +  // If "secure" S3 is needed, then SEC will decompress both PEI and DXE
> +  // firmware volumes at S3 resume too, hence we need to keep away the OS from
> +  // DXEFV as well. Otherwise we only need to keep away DXE itself from the
> +  // DXEFV area.
> +  //
> +  BuildMemoryAllocationHob (
> +    PcdGet32 (PcdOvmfDxeMemFvBase),
> +    PcdGet32 (PcdOvmfDxeMemFvSize),
> +    SecureS3Needed ? EfiACPIMemoryNVS : EfiBootServicesData
> +    );
> +
> +  //
> +  // Additionally, said decompression will use temporary memory above the end
> +  // of DXEFV, so let's keep away the OS from there too.
> +  //
> +  if (SecureS3Needed) {
> +    UINT32 DxeMemFvEnd;
> +
> +    DxeMemFvEnd = PcdGet32 (PcdOvmfDxeMemFvBase) +
> +                  PcdGet32 (PcdOvmfDxeMemFvSize);
> +    BuildMemoryAllocationHob (
> +      DxeMemFvEnd,
> +      PcdGet32 (PcdOvmfDecompressionScratchEnd) - DxeMemFvEnd,
> +      EfiACPIMemoryNVS
> +      );
> +  }
> +
> +  //
> +  // Let PEI know about the DXE FV so it can find the DXE Core
> +  //
> +  PeiServicesInstallFvInfoPpi (
> +    NULL,
> +    (VOID *)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase),
> +    PcdGet32 (PcdOvmfDxeMemFvSize),
> +    NULL,
> +    NULL
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git a/OvmfPkg/XenPlatformPei/MemDetect.c b/OvmfPkg/XenPlatformPei/MemDetect.c
> new file mode 100644
> index 0000000..4ecdf5e
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/MemDetect.c
> @@ -0,0 +1,449 @@
> +/**@file
> +  Memory Detection for Virtual Machines.
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD License
> +  which accompanies this distribution.  The full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +Module Name:
> +
> +  MemDetect.c
> +
> +**/
> +
> +//
> +// The package level header files this module uses
> +//
> +#include <PiPei.h>
> +
> +//
> +// The Library classes this module consumes
> +//
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PeimEntryPoint.h>
> +#include <Library/ResourcePublicationLib.h>
> +#include <Library/MtrrLib.h>
> +#include <Library/QemuFwCfgLib.h>
> +
> +#include "Platform.h"
> +#include "Cmos.h"
> +
> +UINT8 mPhysMemAddressWidth;
> +
> +STATIC UINT32 mS3AcpiReservedMemoryBase;
> +STATIC UINT32 mS3AcpiReservedMemorySize;
> +
> +UINT32
> +GetSystemMemorySizeBelow4gb (
> +  VOID
> +  )
> +{
> +  UINT8 Cmos0x34;
> +  UINT8 Cmos0x35;
> +
> +  //
> +  // CMOS 0x34/0x35 specifies the system memory above 16 MB.
> +  // * CMOS(0x35) is the high byte
> +  // * CMOS(0x34) is the low byte
> +  // * The size is specified in 64kb chunks
> +  // * Since this is memory above 16MB, the 16MB must be added
> +  //   into the calculation to get the total memory size.
> +  //
> +
> +  Cmos0x34 = (UINT8) CmosRead8 (0x34);
> +  Cmos0x35 = (UINT8) CmosRead8 (0x35);
> +
> +  return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
> +}
> +
> +
> +STATIC
> +UINT64
> +GetSystemMemorySizeAbove4gb (
> +  )
> +{
> +  UINT32 Size;
> +  UINTN  CmosIndex;
> +
> +  //
> +  // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
> +  // * CMOS(0x5d) is the most significant size byte
> +  // * CMOS(0x5c) is the middle size byte
> +  // * CMOS(0x5b) is the least significant size byte
> +  // * The size is specified in 64kb chunks
> +  //
> +
> +  Size = 0;
> +  for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
> +    Size = (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex);
> +  }
> +
> +  return LShiftU64 (Size, 16);
> +}
> +
> +
> +/**
> +  Return the highest address that DXE could possibly use, plus one.
> +**/
> +STATIC
> +UINT64
> +GetFirstNonAddress (
> +  VOID
> +  )
> +{
> +  UINT64               FirstNonAddress;
> +  UINT64               Pci64Base, Pci64Size;
> +  RETURN_STATUS        PcdStatus;
> +
> +  FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
> +
> +  //
> +  // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
> +  // resources to 32-bit anyway. See DegradeResource() in
> +  // "PciResourceSupport.c".
> +  //
> +#ifdef MDE_CPU_IA32
> +  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
> +    return FirstNonAddress;
> +  }
> +#endif
> +
> +  //
> +  // Otherwise, in order to calculate the highest address plus one, we must
> +  // consider the 64-bit PCI host aperture too. Fetch the default size.
> +  //
> +  Pci64Size = PcdGet64 (PcdPciMmio64Size);
> +
> +  if (Pci64Size == 0) {
> +    if (mBootMode != BOOT_ON_S3_RESUME) {
> +      DEBUG ((EFI_D_INFO, "%a: disabling 64-bit PCI host aperture\n",
> +        __FUNCTION__));
> +      PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);
> +      ASSERT_RETURN_ERROR (PcdStatus);
> +    }
> +
> +    //
> +    // There's nothing more to do; the amount of memory above 4GB fully
> +    // determines the highest address plus one. The memory hotplug area (see
> +    // below) plays no role for the firmware in this case.
> +    //
> +    return FirstNonAddress;
> +  }
> +
> +  //
> +  // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
> +  // that the host can map it with 1GB hugepages. Follow suit.
> +  //
> +  Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
> +  Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);
> +
> +  //
> +  // The 64-bit PCI host aperture should also be "naturally" aligned. The
> +  // alignment is determined by rounding the size of the aperture down to the
> +  // next smaller or equal power of two. That is, align the aperture by the
> +  // largest BAR size that can fit into it.
> +  //
> +  Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));
> +
> +  if (mBootMode != BOOT_ON_S3_RESUME) {
> +    //
> +    // The core PciHostBridgeDxe driver will automatically add this range to
> +    // the GCD memory space map through our PciHostBridgeLib instance; here we
> +    // only need to set the PCDs.
> +    //
> +    PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);
> +    ASSERT_RETURN_ERROR (PcdStatus);
> +    PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
> +    ASSERT_RETURN_ERROR (PcdStatus);
> +
> +    DEBUG ((EFI_D_INFO, "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
> +      __FUNCTION__, Pci64Base, Pci64Size));
> +  }
> +
> +  //
> +  // The useful address space ends with the 64-bit PCI host aperture.
> +  //
> +  FirstNonAddress = Pci64Base + Pci64Size;
> +  return FirstNonAddress;
> +}
> +
> +
> +/**
> +  Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
> +**/
> +VOID
> +AddressWidthInitialization (
> +  VOID
> +  )
> +{
> +  UINT64 FirstNonAddress;
> +
> +  //
> +  // As guest-physical memory size grows, the permanent PEI RAM requirements
> +  // are dominated by the identity-mapping page tables built by the DXE IPL.
> +  // The DXL IPL keys off of the physical address bits advertized in the CPU
> +  // HOB. To conserve memory, we calculate the minimum address width here.
> +  //
> +  FirstNonAddress      = GetFirstNonAddress ();
> +  mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
> +
> +  //
> +  // If FirstNonAddress is not an integral power of two, then we need an
> +  // additional bit.
> +  //
> +  if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
> +    ++mPhysMemAddressWidth;
> +  }
> +
> +  //
> +  // The minimum address width is 36 (covers up to and excluding 64 GB, which
> +  // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
> +  // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
> +  // can simply assert that here, since 48 bits are good enough for 256 TB.
> +  //
> +  if (mPhysMemAddressWidth <= 36) {
> +    mPhysMemAddressWidth = 36;
> +  }
> +  ASSERT (mPhysMemAddressWidth <= 48);
> +}
> +
> +
> +/**
> +  Calculate the cap for the permanent PEI memory.
> +**/
> +STATIC
> +UINT32
> +GetPeiMemoryCap (
> +  VOID
> +  )
> +{
> +  BOOLEAN Page1GSupport;
> +  UINT32  RegEax;
> +  UINT32  RegEdx;
> +  UINT32  Pml4Entries;
> +  UINT32  PdpEntries;
> +  UINTN   TotalPages;
> +
> +  //
> +  // If DXE is 32-bit, then just return the traditional 64 MB cap.
> +  //
> +#ifdef MDE_CPU_IA32
> +  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
> +    return SIZE_64MB;
> +  }
> +#endif
> +
> +  //
> +  // Dependent on physical address width, PEI memory allocations can be
> +  // dominated by the page tables built for 64-bit DXE. So we key the cap off
> +  // of those. The code below is based on CreateIdentityMappingPageTables() in
> +  // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
> +  //
> +  Page1GSupport = FALSE;
> +  if (PcdGetBool (PcdUse1GPageTable)) {
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= 0x80000001) {
> +      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> +      if ((RegEdx & BIT26) != 0) {
> +        Page1GSupport = TRUE;
> +      }
> +    }
> +  }
> +
> +  if (mPhysMemAddressWidth <= 39) {
> +    Pml4Entries = 1;
> +    PdpEntries = 1 << (mPhysMemAddressWidth - 30);
> +    ASSERT (PdpEntries <= 0x200);
> +  } else {
> +    Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
> +    ASSERT (Pml4Entries <= 0x200);
> +    PdpEntries = 512;
> +  }
> +
> +  TotalPages = Page1GSupport ? Pml4Entries + 1 :
> +                               (PdpEntries + 1) * Pml4Entries + 1;
> +  ASSERT (TotalPages <= 0x40201);
> +
> +  //
> +  // Add 64 MB for miscellaneous allocations. Note that for
> +  // mPhysMemAddressWidth values close to 36, the cap will actually be
> +  // dominated by this increment.
> +  //
> +  return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);
> +}
> +
> +
> +/**
> +  Publish PEI core memory
> +
> +  @return EFI_SUCCESS     The PEIM initialized successfully.
> +
> +**/
> +EFI_STATUS
> +PublishPeiMemory (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  EFI_PHYSICAL_ADDRESS        MemoryBase;
> +  UINT64                      MemorySize;
> +  UINT32                      LowerMemorySize;
> +  UINT32                      PeiMemoryCap;
> +
> +  LowerMemorySize = GetSystemMemorySizeBelow4gb ();
> +
> +  //
> +  // If S3 is supported, then the S3 permanent PEI memory is placed next,
> +  // downwards. Its size is primarily dictated by CpuMpPei. The formula below
> +  // is an approximation.
> +  //
> +  if (mS3Supported) {
> +    mS3AcpiReservedMemorySize = SIZE_512KB +
> +      PcdGet32 (PcdCpuMaxLogicalProcessorNumber) *
> +      PcdGet32 (PcdCpuApStackSize);
> +    mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;
> +    LowerMemorySize = mS3AcpiReservedMemoryBase;
> +  }
> +
> +  if (mBootMode == BOOT_ON_S3_RESUME) {
> +    MemoryBase = mS3AcpiReservedMemoryBase;
> +    MemorySize = mS3AcpiReservedMemorySize;
> +  } else {
> +    PeiMemoryCap = GetPeiMemoryCap ();
> +    DEBUG ((EFI_D_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
> +      __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));
> +
> +    //
> +    // Determine the range of memory to use during PEI
> +    //
> +    // Technically we could lay the permanent PEI RAM over SEC's temporary
> +    // decompression and scratch buffer even if "secure S3" is needed, since
> +    // their lifetimes don't overlap. However, PeiFvInitialization() will cover
> +    // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory
> +    // allocation HOB, and other allocations served from the permanent PEI RAM
> +    // shouldn't overlap with that HOB.
> +    //
> +    MemoryBase = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ?
> +      PcdGet32 (PcdOvmfDecompressionScratchEnd) :
> +      PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);
> +    MemorySize = LowerMemorySize - MemoryBase;
> +    if (MemorySize > PeiMemoryCap) {
> +      MemoryBase = LowerMemorySize - PeiMemoryCap;
> +      MemorySize = PeiMemoryCap;
> +    }
> +  }
> +
> +  //
> +  // Publish this memory to the PEI Core
> +  //
> +  Status = PublishSystemMemory(MemoryBase, MemorySize);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return Status;
> +}
> +
> +
> +/**
> +  Publish system RAM and reserve memory regions
> +
> +**/
> +VOID
> +InitializeRamRegions (
> +  VOID
> +  )
> +{
> +  XenPublishRamRegions ();
> +
> +  if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
> +    //
> +    // This is the memory range that will be used for PEI on S3 resume
> +    //
> +    BuildMemoryAllocationHob (
> +      mS3AcpiReservedMemoryBase,
> +      mS3AcpiReservedMemorySize,
> +      EfiACPIMemoryNVS
> +      );
> +
> +    //
> +    // Cover the initial RAM area used as stack and temporary PEI heap.
> +    //
> +    // This is reserved as ACPI NVS so it can be used on S3 resume.
> +    //
> +    BuildMemoryAllocationHob (
> +      PcdGet32 (PcdOvmfSecPeiTempRamBase),
> +      PcdGet32 (PcdOvmfSecPeiTempRamSize),
> +      EfiACPIMemoryNVS
> +      );
> +
> +    //
> +    // SEC stores its table of GUIDed section handlers here.
> +    //
> +    BuildMemoryAllocationHob (
> +      PcdGet64 (PcdGuidedExtractHandlerTableAddress),
> +      PcdGet32 (PcdGuidedExtractHandlerTableSize),
> +      EfiACPIMemoryNVS
> +      );
> +
> +#ifdef MDE_CPU_X64
> +    //
> +    // Reserve the initial page tables built by the reset vector code.
> +    //
> +    // Since this memory range will be used by the Reset Vector on S3
> +    // resume, it must be reserved as ACPI NVS.
> +    //
> +    BuildMemoryAllocationHob (
> +      (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecPageTablesBase),
> +      (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),
> +      EfiACPIMemoryNVS
> +      );
> +#endif
> +  }
> +
> +  if (mBootMode != BOOT_ON_S3_RESUME) {
> +    if (!FeaturePcdGet (PcdSmmSmramRequire)) {
> +      //
> +      // Reserve the lock box storage area
> +      //
> +      // Since this memory range will be used on S3 resume, it must be
> +      // reserved as ACPI NVS.
> +      //
> +      // If S3 is unsupported, then various drivers might still write to the
> +      // LockBox area. We ought to prevent DXE from serving allocation requests
> +      // such that they would overlap the LockBox storage.
> +      //
> +      ZeroMem (
> +        (VOID*)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),
> +        (UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize)
> +        );
> +      BuildMemoryAllocationHob (
> +        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),
> +        (UINT64)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize),
> +        mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
> +        );
> +    }
> +
> +    if (FeaturePcdGet (PcdSmmSmramRequire)) {
> +      UINT32 TsegSize;
> +
> +      //
> +      // Make sure the TSEG area that we reported as a reserved memory resource
> +      // cannot be used for reserved memory allocations.
> +      //
> +      TsegSize = FixedPcdGet8 (PcdQ35TsegMbytes) * SIZE_1MB;
> +      BuildMemoryAllocationHob (
> +        GetSystemMemorySizeBelow4gb() - TsegSize,
> +        TsegSize,
> +        EfiReservedMemoryType
> +        );
> +    }
> +  }
> +}
> diff --git a/OvmfPkg/XenPlatformPei/Platform.c b/OvmfPkg/XenPlatformPei/Platform.c
> new file mode 100644
> index 0000000..bf78878
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/Platform.c
> @@ -0,0 +1,536 @@
> +/**@file
> +  Platform PEI driver
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD License
> +  which accompanies this distribution.  The full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +//
> +// The package level header files this module uses
> +//
> +#include <PiPei.h>
> +
> +//
> +// The Library classes this module consumes
> +//
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PciLib.h>
> +#include <Library/PeimEntryPoint.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/QemuFwCfgLib.h>
> +#include <Library/ResourcePublicationLib.h>
> +#include <Guid/MemoryTypeInformation.h>
> +#include <Ppi/MasterBootMode.h>
> +#include <IndustryStandard/Pci22.h>
> +#include <OvmfPlatforms.h>
> +
> +#include "Platform.h"
> +#include "Cmos.h"
> +
> +EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
> +  { EfiACPIMemoryNVS,       0x004 },
> +  { EfiACPIReclaimMemory,   0x008 },
> +  { EfiReservedMemoryType,  0x004 },
> +  { EfiRuntimeServicesData, 0x024 },
> +  { EfiRuntimeServicesCode, 0x030 },
> +  { EfiBootServicesCode,    0x180 },
> +  { EfiBootServicesData,    0xF00 },
> +  { EfiMaxMemoryType,       0x000 }
> +};
> +
> +
> +EFI_PEI_PPI_DESCRIPTOR   mPpiBootMode[] = {
> +  {
> +    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
> +    &gEfiPeiMasterBootModePpiGuid,
> +    NULL
> +  }
> +};
> +
> +
> +UINT16 mHostBridgeDevId;
> +
> +EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
> +
> +BOOLEAN mS3Supported = FALSE;
> +
> +
> +VOID
> +AddIoMemoryBaseSizeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  UINT64                      MemorySize
> +  )
> +{
> +  BuildResourceDescriptorHob (
> +    EFI_RESOURCE_MEMORY_MAPPED_IO,
> +      EFI_RESOURCE_ATTRIBUTE_PRESENT     |
> +      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
> +      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
> +      EFI_RESOURCE_ATTRIBUTE_TESTED,
> +    MemoryBase,
> +    MemorySize
> +    );
> +}
> +
> +VOID
> +AddReservedMemoryBaseSizeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  UINT64                      MemorySize,
> +  BOOLEAN                     Cacheable
> +  )
> +{
> +  BuildResourceDescriptorHob (
> +    EFI_RESOURCE_MEMORY_RESERVED,
> +      EFI_RESOURCE_ATTRIBUTE_PRESENT     |
> +      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
> +      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
> +      (Cacheable ?
> +       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
> +       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
> +       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
> +       0
> +       ) |
> +      EFI_RESOURCE_ATTRIBUTE_TESTED,
> +    MemoryBase,
> +    MemorySize
> +    );
> +}
> +
> +VOID
> +AddIoMemoryRangeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  EFI_PHYSICAL_ADDRESS        MemoryLimit
> +  )
> +{
> +  AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
> +}
> +
> +
> +VOID
> +AddMemoryBaseSizeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  UINT64                      MemorySize
> +  )
> +{
> +  BuildResourceDescriptorHob (
> +    EFI_RESOURCE_SYSTEM_MEMORY,
> +      EFI_RESOURCE_ATTRIBUTE_PRESENT |
> +      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
> +      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
> +      EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
> +      EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
> +      EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
> +      EFI_RESOURCE_ATTRIBUTE_TESTED,
> +    MemoryBase,
> +    MemorySize
> +    );
> +}
> +
> +
> +VOID
> +AddMemoryRangeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  EFI_PHYSICAL_ADDRESS        MemoryLimit
> +  )
> +{
> +  AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
> +}
> +
> +
> +VOID
> +MemMapInitialization (
> +  VOID
> +  )
> +{
> +  UINT64        PciIoBase;
> +  UINT64        PciIoSize;
> +  RETURN_STATUS PcdStatus;
> +
> +  PciIoBase = 0xC000;
> +  PciIoSize = 0x4000;
> +
> +  //
> +  // Create Memory Type Information HOB
> +  //
> +  BuildGuidDataHob (
> +    &gEfiMemoryTypeInformationGuid,
> +    mDefaultMemoryTypeInformation,
> +    sizeof(mDefaultMemoryTypeInformation)
> +    );
> +
> +  //
> +  // Video memory + Legacy BIOS region
> +  //
> +  AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
> +
> +  if (!mXen) {
> +    UINT32  TopOfLowRam;
> +    UINT64  PciExBarBase;
> +    UINT32  PciBase;
> +    UINT32  PciSize;
> +
> +    TopOfLowRam = GetSystemMemorySizeBelow4gb ();
> +    PciExBarBase = 0;
> +    if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
> +      //
> +      // The MMCONFIG area is expected to fall between the top of low RAM and
> +      // the base of the 32-bit PCI host aperture.
> +      //
> +      PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
> +      ASSERT (TopOfLowRam <= PciExBarBase);
> +      ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
> +      PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
> +    } else {
> +      PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
> +    }
> +
> +    //
> +    // address       purpose   size
> +    // ------------  --------  -------------------------
> +    // max(top, 2g)  PCI MMIO  0xFC000000 - max(top, 2g)
> +    // 0xFC000000    gap                           44 MB
> +    // 0xFEC00000    IO-APIC                        4 KB
> +    // 0xFEC01000    gap                         1020 KB
> +    // 0xFED00000    HPET                           1 KB
> +    // 0xFED00400    gap                          111 KB
> +    // 0xFED1C000    gap (PIIX4) / RCRB (ICH9)     16 KB
> +    // 0xFED20000    gap                          896 KB
> +    // 0xFEE00000    LAPIC                          1 MB
> +    //
> +    PciSize = 0xFC000000 - PciBase;
> +    AddIoMemoryBaseSizeHob (PciBase, PciSize);
> +    PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
> +    ASSERT_RETURN_ERROR (PcdStatus);
> +    PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
> +    ASSERT_RETURN_ERROR (PcdStatus);
> +
> +    AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
> +    AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
> +    if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
> +      AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
> +      //
> +      // Note: there should be an
> +      //
> +      //   AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
> +      //
> +      // call below, just like the one above for RCBA. However, Linux insists
> +      // that the MMCONFIG area be marked in the E820 or UEFI memory map as
> +      // "reserved memory" -- Linux does not content itself with a simple gap
> +      // in the memory map wherever the MCFG ACPI table points to.
> +      //
> +      // This appears to be a safety measure. The PCI Firmware Specification
> +      // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
> +      // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
> +      // [...]". (Emphasis added here.)
> +      //
> +      // Normally we add memory resource descriptor HOBs in
> +      // QemuInitializeRam(), and pre-allocate from those with memory
> +      // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
> +      // is most definitely not RAM; so, as an exception, cover it with
> +      // uncacheable reserved memory right here.
> +      //
> +      AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
> +      BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,
> +        EfiReservedMemoryType);
> +    }
> +    AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB);
> +
> +    //
> +    // On Q35, the IO Port space is available for PCI resource allocations from
> +    // 0x6000 up.
> +    //
> +    if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
> +      PciIoBase = 0x6000;
> +      PciIoSize = 0xA000;
> +      ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);
> +    }
> +  }
> +
> +  //
> +  // Add PCI IO Port space available for PCI resource allocations.
> +  //
> +  BuildResourceDescriptorHob (
> +    EFI_RESOURCE_IO,
> +    EFI_RESOURCE_ATTRIBUTE_PRESENT     |
> +    EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
> +    PciIoBase,
> +    PciIoSize
> +    );
> +  PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +  PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +}
> +
> +VOID
> +PciExBarInitialization (
> +  VOID
> +  )
> +{
> +  union {
> +    UINT64 Uint64;
> +    UINT32 Uint32[2];
> +  } PciExBarBase;
> +
> +  //
> +  // We only support the 256MB size for the MMCONFIG area:
> +  // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
> +  //
> +  // The masks used below enforce the Q35 requirements that the MMCONFIG area
> +  // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
> +  //
> +  // Note that (b) also ensures that the minimum address width we have
> +  // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
> +  // for DXE's page tables to cover the MMCONFIG area.
> +  //
> +  PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
> +  ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
> +  ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
> +
> +  //
> +  // Clear the PCIEXBAREN bit first, before programming the high register.
> +  //
> +  PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
> +
> +  //
> +  // Program the high register. Then program the low register, setting the
> +  // MMCONFIG area size and enabling decoding at once.
> +  //
> +  PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
> +  PciWrite32 (
> +    DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
> +    PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
> +    );
> +}
> +
> +VOID
> +MiscInitialization (
> +  VOID
> +  )
> +{
> +  UINTN         PmCmd;
> +  UINTN         Pmba;
> +  UINT32        PmbaAndVal;
> +  UINT32        PmbaOrVal;
> +  UINTN         AcpiCtlReg;
> +  UINT8         AcpiEnBit;
> +  RETURN_STATUS PcdStatus;
> +
> +  //
> +  // Disable A20 Mask
> +  //
> +  IoOr8 (0x92, BIT1);
> +
> +  //
> +  // Build the CPU HOB with guest RAM size dependent address width and 16-bits
> +  // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
> +  // S3 resume as well, so we build it unconditionally.)
> +  //
> +  BuildCpuHob (mPhysMemAddressWidth, 16);
> +
> +  //
> +  // Determine platform type and save Host Bridge DID to PCD
> +  //
> +  switch (mHostBridgeDevId) {
> +    case INTEL_82441_DEVICE_ID:
> +      PmCmd      = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
> +      Pmba       = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
> +      PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
> +      PmbaOrVal  = PIIX4_PMBA_VALUE;
> +      AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
> +      AcpiEnBit  = PIIX4_PMREGMISC_PMIOSE;
> +      break;
> +    case INTEL_Q35_MCH_DEVICE_ID:
> +      PmCmd      = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
> +      Pmba       = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
> +      PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
> +      PmbaOrVal  = ICH9_PMBASE_VALUE;
> +      AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
> +      AcpiEnBit  = ICH9_ACPI_CNTL_ACPI_EN;
> +      break;
> +    default:
> +      DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
> +        __FUNCTION__, mHostBridgeDevId));
> +      ASSERT (FALSE);
> +      return;
> +  }
> +  PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +
> +  //
> +  // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
> +  // has been configured (e.g., by Xen) and skip the setup here.
> +  // This matches the logic in AcpiTimerLibConstructor ().
> +  //
> +  if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
> +    //
> +    // The PEI phase should be exited with fully accessibe ACPI PM IO space:
> +    // 1. set PMBA
> +    //
> +    PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
> +
> +    //
> +    // 2. set PCICMD/IOSE
> +    //
> +    PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
> +
> +    //
> +    // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
> +    //
> +    PciOr8 (AcpiCtlReg, AcpiEnBit);
> +  }
> +
> +  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
> +    //
> +    // Set Root Complex Register Block BAR
> +    //
> +    PciWrite32 (
> +      POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
> +      ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
> +      );
> +
> +    //
> +    // Set PCI Express Register Range Base Address
> +    //
> +    PciExBarInitialization ();
> +  }
> +}
> +
> +
> +VOID
> +BootModeInitialization (
> +  VOID
> +  )
> +{
> +  EFI_STATUS    Status;
> +
> +  if (CmosRead8 (0xF) == 0xFE) {
> +    mBootMode = BOOT_ON_S3_RESUME;
> +  }
> +  CmosWrite8 (0xF, 0x00);
> +
> +  Status = PeiServicesSetBootMode (mBootMode);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  Status = PeiServicesInstallPpi (mPpiBootMode);
> +  ASSERT_EFI_ERROR (Status);
> +}
> +
> +
> +VOID
> +ReserveEmuVariableNvStore (
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS VariableStore;
> +  RETURN_STATUS        PcdStatus;
> +
> +  //
> +  // Allocate storage for NV variables early on so it will be
> +  // at a consistent address.  Since VM memory is preserved
> +  // across reboots, this allows the NV variable storage to survive
> +  // a VM reboot.
> +  //
> +  VariableStore =
> +    (EFI_PHYSICAL_ADDRESS)(UINTN)
> +      AllocateAlignedRuntimePages (
> +        EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)),
> +        PcdGet32 (PcdFlashNvStorageFtwSpareSize)
> +        );
> +  DEBUG ((EFI_D_INFO,
> +          "Reserved variable store memory: 0x%lX; size: %dkb\n",
> +          VariableStore,
> +          (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
> +        ));
> +  PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +}
> +
> +
> +VOID
> +DebugDumpCmos (
> +  VOID
> +  )
> +{
> +  UINT32 Loop;
> +
> +  DEBUG ((EFI_D_INFO, "CMOS:\n"));
> +
> +  for (Loop = 0; Loop < 0x80; Loop++) {
> +    if ((Loop % 0x10) == 0) {
> +      DEBUG ((EFI_D_INFO, "%02x:", Loop));
> +    }
> +    DEBUG ((EFI_D_INFO, " %02x", CmosRead8 (Loop)));
> +    if ((Loop % 0x10) == 0xf) {
> +      DEBUG ((EFI_D_INFO, "\n"));
> +    }
> +  }
> +}
> +
> +
> +
> +/**
> +  Perform Platform PEI initialization.
> +
> +  @param  FileHandle      Handle of the file being invoked.
> +  @param  PeiServices     Describes the list of possible PEI Services.
> +
> +  @return EFI_SUCCESS     The PEIM initialized successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitializeXenPlatform (
> +  IN       EFI_PEI_FILE_HANDLE  FileHandle,
> +  IN CONST EFI_PEI_SERVICES     **PeiServices
> +  )
> +{
> +  DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n"));
> +
> +  DebugDumpCmos ();
> +
> +  XenDetect ();
> +
> +  BootModeInitialization ();
> +  AddressWidthInitialization ();
> +
> +  PublishPeiMemory ();
> +
> +  InitializeRamRegions ();
> +
> +  if (mXen) {
> +    DEBUG ((EFI_D_INFO, "Xen was detected\n"));
> +    InitializeXen ();
> +  } else {
> +    DEBUG ((EFI_D_ERROR, "not running on Xen\n"));
> +    CpuDeadLoop ();
> +  }
> +
> +  //
> +  // Query Host Bridge DID
> +  //
> +  mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
> +
> +  if (mBootMode != BOOT_ON_S3_RESUME) {
> +    ReserveEmuVariableNvStore ();
> +    PeiFvInitialization ();
> +    MemMapInitialization ();
> +  }
> +
> +  MiscInitialization ();
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/OvmfPkg/XenPlatformPei/Platform.h b/OvmfPkg/XenPlatformPei/Platform.h
> new file mode 100644
> index 0000000..eda765b
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/Platform.h
> @@ -0,0 +1,104 @@
> +/** @file
> +  Platform PEI module include file.
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD License
> +  which accompanies this distribution.  The full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef _PLATFORM_PEI_H_INCLUDED_
> +#define _PLATFORM_PEI_H_INCLUDED_
> +
> +#include <IndustryStandard/E820.h>
> +
> +VOID
> +AddIoMemoryBaseSizeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  UINT64                      MemorySize
> +  );
> +
> +VOID
> +AddIoMemoryRangeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  EFI_PHYSICAL_ADDRESS        MemoryLimit
> +  );
> +
> +VOID
> +AddMemoryBaseSizeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  UINT64                      MemorySize
> +  );
> +
> +VOID
> +AddMemoryRangeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  EFI_PHYSICAL_ADDRESS        MemoryLimit
> +  );
> +
> +VOID
> +AddReservedMemoryBaseSizeHob (
> +  EFI_PHYSICAL_ADDRESS        MemoryBase,
> +  UINT64                      MemorySize,
> +  BOOLEAN                     Cacheable
> +  );
> +
> +VOID
> +AddressWidthInitialization (
> +  VOID
> +  );
> +
> +EFI_STATUS
> +PublishPeiMemory (
> +  VOID
> +  );
> +
> +UINT32
> +GetSystemMemorySizeBelow4gb (
> +  VOID
> +  );
> +
> +VOID
> +InitializeRamRegions (
> +  VOID
> +  );
> +
> +EFI_STATUS
> +PeiFvInitialization (
> +  VOID
> +  );
> +
> +VOID
> +InstallFeatureControlCallback (
> +  VOID
> +  );
> +
> +EFI_STATUS
> +InitializeXen (
> +  VOID
> +  );
> +
> +BOOLEAN
> +XenDetect (
> +  VOID
> +  );
> +
> +extern BOOLEAN mXen;
> +
> +VOID
> +XenPublishRamRegions (
> +  VOID
> +  );
> +
> +extern EFI_BOOT_MODE mBootMode;
> +
> +extern BOOLEAN mS3Supported;
> +
> +extern UINT8 mPhysMemAddressWidth;
> +
> +#endif // _PLATFORM_PEI_H_INCLUDED_
> diff --git a/OvmfPkg/XenPlatformPei/Xen.c b/OvmfPkg/XenPlatformPei/Xen.c
> new file mode 100644
> index 0000000..ab38f97
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/Xen.c
> @@ -0,0 +1,231 @@
> +/**@file
> +  Xen Platform PEI support
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD License
> +  which accompanies this distribution.  The full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +//
> +// The package level header files this module uses
> +//
> +#include <PiPei.h>
> +
> +//
> +// The Library classes this module consumes
> +//
> +#include <Library/DebugLib.h>
> +#include <Library/HobLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Guid/XenInfo.h>
> +#include <IndustryStandard/E820.h>
> +#include <Library/ResourcePublicationLib.h>
> +#include <Library/MtrrLib.h>
> +
> +#include "Platform.h"
> +#include "Xen.h"
> +
> +BOOLEAN mXen = FALSE;
> +
> +STATIC UINT32 mXenLeaf = 0;
> +
> +EFI_XEN_INFO mXenInfo;
> +
> +/**
> +  Returns E820 map provided by Xen
> +
> +  @param Entries      Pointer to E820 map
> +  @param Count        Number of entries
> +
> +  @return EFI_STATUS
> +**/
> +EFI_STATUS
> +XenGetE820Map (
> +  EFI_E820_ENTRY64 **Entries,
> +  UINT32 *Count
> +  )
> +{
> +  EFI_XEN_OVMF_INFO *Info =
> +    (EFI_XEN_OVMF_INFO *)(UINTN) OVMF_INFO_PHYSICAL_ADDRESS;
> +
> +  if (AsciiStrCmp ((CHAR8 *) Info->Signature, "XenHVMOVMF")) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  ASSERT (Info->E820 < MAX_ADDRESS);
> +  *Entries = (EFI_E820_ENTRY64 *)(UINTN) Info->E820;
> +  *Count = Info->E820EntriesCount;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Connects to the Hypervisor.
> + 
> +  @param  XenLeaf     CPUID index used to connect.
> +
> +  @return EFI_STATUS
> +
> +**/
> +EFI_STATUS
> +XenConnect (
> +  UINT32 XenLeaf
> +  )
> +{
> +  UINT32 Index;
> +  UINT32 TransferReg;
> +  UINT32 TransferPages;
> +  UINT32 XenVersion;
> +
> +  AsmCpuid (XenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL);
> +  mXenInfo.HyperPages = AllocatePages (TransferPages);
> +  if (!mXenInfo.HyperPages) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  for (Index = 0; Index < TransferPages; Index++) {
> +    AsmWriteMsr64 (TransferReg,
> +                   (UINTN) mXenInfo.HyperPages +
> +                   (Index << EFI_PAGE_SHIFT) + Index);
> +  }
> +
> +  AsmCpuid (XenLeaf + 1, &XenVersion, NULL, NULL, NULL);
> +  DEBUG ((EFI_D_ERROR, "Detected Xen version %d.%d\n",
> +          XenVersion >> 16, XenVersion & 0xFFFF));
> +  mXenInfo.VersionMajor = (UINT16)(XenVersion >> 16);
> +  mXenInfo.VersionMinor = (UINT16)(XenVersion & 0xFFFF);
> +
> +  /* TBD: Locate hvm_info and reserve it away. */
> +  mXenInfo.HvmInfo = NULL;
> +
> +  BuildGuidDataHob (
> +    &gEfiXenInfoGuid,
> +    &mXenInfo,
> +    sizeof(mXenInfo)
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Figures out if we are running inside Xen HVM.
> +
> +  @retval TRUE   Xen was detected
> +  @retval FALSE  Xen was not detected
> +
> +**/
> +BOOLEAN
> +XenDetect (
> +  VOID
> +  )
> +{
> +  UINT8 Signature[13];
> +
> +  if (mXenLeaf != 0) {
> +    return TRUE;
> +  }
> +
> +  Signature[12] = '\0';
> +  for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) {
> +    AsmCpuid (mXenLeaf,
> +              NULL,
> +              (UINT32 *) &Signature[0],
> +              (UINT32 *) &Signature[4],
> +              (UINT32 *) &Signature[8]);
> +
> +    if (!AsciiStrCmp ((CHAR8 *) Signature, "XenVMMXenVMM")) {
> +      mXen = TRUE;
> +      return TRUE;
> +    }
> +  }
> +
> +  mXenLeaf = 0;
> +  return FALSE;
> +}
> +
> +
> +VOID
> +XenPublishRamRegions (
> +  VOID
> +  )
> +{
> +  EFI_E820_ENTRY64  *E820Map;
> +  UINT32            E820EntriesCount;
> +  EFI_STATUS        Status;
> +
> +  if (!mXen) {
> +    return;
> +  }
> +
> +  DEBUG ((EFI_D_INFO, "Using memory map provided by Xen\n"));
> +
> +  //
> +  // Parse RAM in E820 map
> +  //
> +  E820EntriesCount = 0;
> +  Status = XenGetE820Map (&E820Map, &E820EntriesCount);
> +
> +  ASSERT_EFI_ERROR (Status);
> +
> +  if (E820EntriesCount > 0) {
> +    EFI_E820_ENTRY64 *Entry;
> +    UINT32 Loop;
> +
> +    for (Loop = 0; Loop < E820EntriesCount; Loop++) {
> +      Entry = E820Map + Loop;
> +
> +      //
> +      // Only care about RAM
> +      //
> +      if (Entry->Type != EfiAcpiAddressRangeMemory) {
> +        continue;
> +      }
> +
> +      AddMemoryBaseSizeHob (Entry->BaseAddr, Entry->Length);
> +
> +      MtrrSetMemoryAttribute (Entry->BaseAddr, Entry->Length, CacheWriteBack);
> +    }
> +  }
> +}
> +
> +
> +/**
> +  Perform Xen PEI initialization.
> +
> +  @return EFI_SUCCESS     Xen initialized successfully
> +  @return EFI_NOT_FOUND   Not running under Xen
> +
> +**/
> +EFI_STATUS
> +InitializeXen (
> +  VOID
> +  )
> +{
> +  RETURN_STATUS PcdStatus;
> +
> +  if (mXenLeaf == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  XenConnect (mXenLeaf);
> +
> +  //
> +  // Reserve away HVMLOADER reserved memory [0xFC000000,0xFD000000).
> +  // This needs to match HVMLOADER RESERVED_MEMBASE/RESERVED_MEMSIZE.
> +  //
> +  AddReservedMemoryBaseSizeHob (0xFC000000, 0x1000000, FALSE);
> +
> +  PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, TRUE);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/OvmfPkg/XenPlatformPei/Xen.h b/OvmfPkg/XenPlatformPei/Xen.h
> new file mode 100644
> index 0000000..2a8a32b
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/Xen.h
> @@ -0,0 +1,45 @@
> +/** @file
> +  Ovmf info structure passed by Xen
> +
> +Copyright (c) 2013, Citrix Systems UK Ltd.<BR>
> +
> +This program and the accompanying materials are licensed and made available under
> +the terms and conditions of the BSD License that accompanies this distribution.
> +The full text of the license may be found at
> +http://opensource.org/licenses/bsd-license.php.
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __XEN_H__
> +#define __XEN_H__
> +
> +#include <PiPei.h>
> +
> +// Physical address of OVMF info
> +#define OVMF_INFO_PHYSICAL_ADDRESS 0x00001000
> +
> +// This structure must match the definition on Xen side
> +#pragma pack(1)
> +typedef struct {
> +  CHAR8 Signature[14]; // XenHVMOVMF\0
> +  UINT8 Length;        // Length of this structure
> +  UINT8 Checksum;      // Set such that the sum over bytes 0..length == 0
> +  //
> +  // Physical address of an array of TablesCount elements.
> +  //
> +  // Each element contains the physical address of a BIOS table.
> +  //
> +  EFI_PHYSICAL_ADDRESS Tables;
> +  UINT32 TablesCount;
> +  //
> +  // Physical address of the E820 table, contains E820EntriesCount entries.
> +  //
> +  EFI_PHYSICAL_ADDRESS E820;
> +  UINT32 E820EntriesCount;
> +} EFI_XEN_OVMF_INFO;
> +#pragma pack()
> +
> +#endif /* __XEN_H__ */
> diff --git a/OvmfPkg/XenPlatformPei/XenPlatformPei.inf b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf
> new file mode 100644
> index 0000000..dfa7d85
> --- /dev/null
> +++ b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf
> @@ -0,0 +1,110 @@
> +## @file
> +#  Platform PEI driver
> +#
> +#  This module provides platform specific function to detect boot mode.
> +#  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the BSD License
> +#  which accompanies this distribution. The full text of the license may be found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = XenPlatformPei
> +  FILE_GUID                      = f112a6ee-993a-4f0b-8295-e52029d9b4ba
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = InitializeXenPlatform
> +
> +#
> +# The following information is for reference only and not required by the build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
> +#
> +
> +[Sources]
> +  Cmos.c
> +  Fv.c
> +  MemDetect.c
> +  Platform.c
> +  Xen.c
> +
> +[Packages]
> +  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
> +  OvmfPkg/OvmfPkg.dec
> +
> +[Guids]
> +  gEfiMemoryTypeInformationGuid
> +  gEfiXenInfoGuid
> +
> +[LibraryClasses]
> +  BaseLib
> +  DebugLib
> +  HobLib
> +  IoLib
> +  PciLib
> +  PeiResourcePublicationLib
> +  PeiServicesLib
> +  PeiServicesTablePointerLib
> +  PeimEntryPoint
> +  MtrrLib
> +  PcdLib
> +
> +[Pcd]
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size
> +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
> +  gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes
> +  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
> +
> +[FixedPcd]
> +  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
> +
> +[FeaturePcd]
> +  gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
> +
> +[Ppis]
> +  gEfiPeiMasterBootModePpiGuid
> +  gEfiPeiMpServicesPpiGuid
> +
> +[Depex]
> +  TRUE
> +
>
Anthony PERARD Jan. 10, 2017, 4:08 p.m. UTC | #2
On Thu, Jan 05, 2017 at 10:59:24AM +0100, Laszlo Ersek wrote:
> On 12/08/16 16:33, Anthony PERARD wrote:
> > A copy of OvmfPkg/PlatformPei without some of QEMU specific
> > initialization, Xen does not support QemuFwCfg.
> > 
> > Contributed-under: TianoCore Contribution Agreement 1.0
> > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> > ---
> >  OvmfPkg/XenOvmf.dsc                       |   2 +-
> >  OvmfPkg/XenOvmf.fdf                       |   2 +-
> >  OvmfPkg/XenPlatformPei/Cmos.c             |  64 ++++
> >  OvmfPkg/XenPlatformPei/Cmos.h             |  56 ++++
> >  OvmfPkg/XenPlatformPei/Fv.c               | 100 ++++++
> >  OvmfPkg/XenPlatformPei/MemDetect.c        | 449 +++++++++++++++++++++++++
> >  OvmfPkg/XenPlatformPei/Platform.c         | 536 ++++++++++++++++++++++++++++++
> >  OvmfPkg/XenPlatformPei/Platform.h         | 104 ++++++
> >  OvmfPkg/XenPlatformPei/Xen.c              | 231 +++++++++++++
> >  OvmfPkg/XenPlatformPei/Xen.h              |  45 +++
> >  OvmfPkg/XenPlatformPei/XenPlatformPei.inf | 110 ++++++
> >  11 files changed, 1697 insertions(+), 2 deletions(-)
> >  create mode 100644 OvmfPkg/XenPlatformPei/Cmos.c
> >  create mode 100644 OvmfPkg/XenPlatformPei/Cmos.h
> >  create mode 100644 OvmfPkg/XenPlatformPei/Fv.c
> >  create mode 100644 OvmfPkg/XenPlatformPei/MemDetect.c
> >  create mode 100644 OvmfPkg/XenPlatformPei/Platform.c
> >  create mode 100644 OvmfPkg/XenPlatformPei/Platform.h
> >  create mode 100644 OvmfPkg/XenPlatformPei/Xen.c
> >  create mode 100644 OvmfPkg/XenPlatformPei/Xen.h
> >  create mode 100644 OvmfPkg/XenPlatformPei/XenPlatformPei.inf
> 
> (1) You might want to add Citrix copyright notices to new files.
> 
> (2) This module is a good example where the moved Xen functionality
> (even for HVM guests) should be possible to remove from the original
> PlatformPei module. (In a later, final patch.) Is that right?

Yes, that should be possible.

> (3) In the commit message, please list the removed fw_cfg-dependent
> functionality in more detail (all of which is dynamically skipped when
> the current PlatformPei module runs on Xen):

Will do.

> - 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
> "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:
> -  SMRAM/TSEG-related low mem size adjusting (PcdSmmSmramRequire is
> assumed FALSE) in PublishPeiMemory(),
> - QemuInitializeRam() entirely,
> 
> (4) I think the removal of PcdSmmSmramRequire is incomplete. IMO this
> PCD should either be removed completely (all uses, including the INF
> reference), assuming a FALSE value in its place, or the PCD should not
> be touched at all. The FeaturePcdGet() call in PublishPeiMemory() --
> gating the "TSEG is chipped from the end of low RAM" stuff -- seems to
> be singled out for removal for no good reason.

Yes, I think I will remove all of if. There is not much reason to keep
something that is not tested, and I don't know if it can work on Xen. I
guess SMM can be readded later.

> (5) It would be nice to hint at the reason (which is implemented in a
> later patch) why a separate module is a good idea here. That is, why the
> expected PVH2 functionality is best not added to the current PlatformPei
> module.

Will do.
diff mbox

Patch

diff --git a/OvmfPkg/XenOvmf.dsc b/OvmfPkg/XenOvmf.dsc
index 0a7ea21..ef32c33 100644
--- a/OvmfPkg/XenOvmf.dsc
+++ b/OvmfPkg/XenOvmf.dsc
@@ -496,7 +496,7 @@ 
       PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
   }
 
-  OvmfPkg/PlatformPei/PlatformPei.inf {
+  OvmfPkg/XenPlatformPei/XenPlatformPei.inf {
     <LibraryClasses>
       PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
   }
diff --git a/OvmfPkg/XenOvmf.fdf b/OvmfPkg/XenOvmf.fdf
index f4609b0..c211f61 100644
--- a/OvmfPkg/XenOvmf.fdf
+++ b/OvmfPkg/XenOvmf.fdf
@@ -157,7 +157,7 @@  INF  MdeModulePkg/Core/Pei/PeiMain.inf
 INF  MdeModulePkg/Universal/PCD/Pei/Pcd.inf
 INF  MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
 INF  MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
-INF  OvmfPkg/PlatformPei/PlatformPei.inf
+INF  OvmfPkg/XenPlatformPei/XenPlatformPei.inf
 INF  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
 INF  UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
 !if $(SMM_REQUIRE) == TRUE
diff --git a/OvmfPkg/XenPlatformPei/Cmos.c b/OvmfPkg/XenPlatformPei/Cmos.c
new file mode 100644
index 0000000..48ed2cb
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Cmos.c
@@ -0,0 +1,64 @@ 
+/** @file
+  PC/AT CMOS access routines
+
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "Cmos.h"
+#include "Library/IoLib.h"
+
+/**
+  Reads 8-bits of CMOS data.
+
+  Reads the 8-bits of CMOS data at the location specified by Index.
+  The 8-bit read value is returned.
+
+  @param  Index  The CMOS location to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+CmosRead8 (
+  IN      UINTN                     Index
+  )
+{
+  IoWrite8 (0x70, (UINT8) Index);
+  return IoRead8 (0x71);
+}
+
+
+/**
+  Writes 8-bits of CMOS data.
+
+  Writes 8-bits of CMOS data to the location specified by Index
+  with the value specified by Value and returns Value.
+
+  @param  Index  The CMOS location to write.
+  @param  Value  The value to write to CMOS.
+
+  @return The value written to CMOS.
+
+**/
+UINT8
+EFIAPI
+CmosWrite8 (
+  IN      UINTN                     Index,
+  IN      UINT8                     Value
+  )
+{
+  IoWrite8 (0x70, (UINT8) Index);
+  IoWrite8 (0x71, Value);
+  return Value;
+}
+
diff --git a/OvmfPkg/XenPlatformPei/Cmos.h b/OvmfPkg/XenPlatformPei/Cmos.h
new file mode 100644
index 0000000..949f884
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Cmos.h
@@ -0,0 +1,56 @@ 
+/** @file
+  PC/AT CMOS access routines
+
+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __CMOS_H__
+#define __CMOS_H__
+
+/**
+  Reads 8-bits of CMOS data.
+
+  Reads the 8-bits of CMOS data at the location specified by Index.
+  The 8-bit read value is returned.
+
+  @param  Index  The CMOS location to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+CmosRead8 (
+  IN      UINTN                     Index
+  );
+
+/**
+  Writes 8-bits of CMOS data.
+
+  Writes 8-bits of CMOS data to the location specified by Index
+  with the value specified by Value and returns Value.
+
+  @param  Index  The CMOS location to write.
+  @param  Value  The value to write to CMOS.
+
+  @return The value written to CMOS.
+
+**/
+UINT8
+EFIAPI
+CmosWrite8 (
+  IN      UINTN                     Index,
+  IN      UINT8                     Value
+  );
+
+
+#endif
+
diff --git a/OvmfPkg/XenPlatformPei/Fv.c b/OvmfPkg/XenPlatformPei/Fv.c
new file mode 100644
index 0000000..248c585
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Fv.c
@@ -0,0 +1,100 @@ 
+/** @file
+  Build FV related hobs for platform.
+
+  Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PiPei.h"
+#include "Platform.h"
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+
+
+/**
+  Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
+  and DXE know about them.
+
+  @retval EFI_SUCCESS   Platform PEI FVs were initialized successfully.
+
+**/
+EFI_STATUS
+PeiFvInitialization (
+  VOID
+  )
+{
+  BOOLEAN SecureS3Needed;
+
+  DEBUG ((EFI_D_INFO, "Platform PEI Firmware Volume Initialization\n"));
+
+  //
+  // Create a memory allocation HOB for the PEI FV.
+  //
+  // Allocate as ACPI NVS is S3 is supported
+  //
+  BuildMemoryAllocationHob (
+    PcdGet32 (PcdOvmfPeiMemFvBase),
+    PcdGet32 (PcdOvmfPeiMemFvSize),
+    mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+    );
+
+  //
+  // Let DXE know about the DXE FV
+  //
+  BuildFvHob (PcdGet32 (PcdOvmfDxeMemFvBase), PcdGet32 (PcdOvmfDxeMemFvSize));
+
+  SecureS3Needed = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire);
+
+  //
+  // Create a memory allocation HOB for the DXE FV.
+  //
+  // If "secure" S3 is needed, then SEC will decompress both PEI and DXE
+  // firmware volumes at S3 resume too, hence we need to keep away the OS from
+  // DXEFV as well. Otherwise we only need to keep away DXE itself from the
+  // DXEFV area.
+  //
+  BuildMemoryAllocationHob (
+    PcdGet32 (PcdOvmfDxeMemFvBase),
+    PcdGet32 (PcdOvmfDxeMemFvSize),
+    SecureS3Needed ? EfiACPIMemoryNVS : EfiBootServicesData
+    );
+
+  //
+  // Additionally, said decompression will use temporary memory above the end
+  // of DXEFV, so let's keep away the OS from there too.
+  //
+  if (SecureS3Needed) {
+    UINT32 DxeMemFvEnd;
+
+    DxeMemFvEnd = PcdGet32 (PcdOvmfDxeMemFvBase) +
+                  PcdGet32 (PcdOvmfDxeMemFvSize);
+    BuildMemoryAllocationHob (
+      DxeMemFvEnd,
+      PcdGet32 (PcdOvmfDecompressionScratchEnd) - DxeMemFvEnd,
+      EfiACPIMemoryNVS
+      );
+  }
+
+  //
+  // Let PEI know about the DXE FV so it can find the DXE Core
+  //
+  PeiServicesInstallFvInfoPpi (
+    NULL,
+    (VOID *)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase),
+    PcdGet32 (PcdOvmfDxeMemFvSize),
+    NULL,
+    NULL
+    );
+
+  return EFI_SUCCESS;
+}
+
diff --git a/OvmfPkg/XenPlatformPei/MemDetect.c b/OvmfPkg/XenPlatformPei/MemDetect.c
new file mode 100644
index 0000000..4ecdf5e
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/MemDetect.c
@@ -0,0 +1,449 @@ 
+/**@file
+  Memory Detection for Virtual Machines.
+
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+  MemDetect.c
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/QemuFwCfgLib.h>
+
+#include "Platform.h"
+#include "Cmos.h"
+
+UINT8 mPhysMemAddressWidth;
+
+STATIC UINT32 mS3AcpiReservedMemoryBase;
+STATIC UINT32 mS3AcpiReservedMemorySize;
+
+UINT32
+GetSystemMemorySizeBelow4gb (
+  VOID
+  )
+{
+  UINT8 Cmos0x34;
+  UINT8 Cmos0x35;
+
+  //
+  // CMOS 0x34/0x35 specifies the system memory above 16 MB.
+  // * CMOS(0x35) is the high byte
+  // * CMOS(0x34) is the low byte
+  // * The size is specified in 64kb chunks
+  // * Since this is memory above 16MB, the 16MB must be added
+  //   into the calculation to get the total memory size.
+  //
+
+  Cmos0x34 = (UINT8) CmosRead8 (0x34);
+  Cmos0x35 = (UINT8) CmosRead8 (0x35);
+
+  return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
+}
+
+
+STATIC
+UINT64
+GetSystemMemorySizeAbove4gb (
+  )
+{
+  UINT32 Size;
+  UINTN  CmosIndex;
+
+  //
+  // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
+  // * CMOS(0x5d) is the most significant size byte
+  // * CMOS(0x5c) is the middle size byte
+  // * CMOS(0x5b) is the least significant size byte
+  // * The size is specified in 64kb chunks
+  //
+
+  Size = 0;
+  for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
+    Size = (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex);
+  }
+
+  return LShiftU64 (Size, 16);
+}
+
+
+/**
+  Return the highest address that DXE could possibly use, plus one.
+**/
+STATIC
+UINT64
+GetFirstNonAddress (
+  VOID
+  )
+{
+  UINT64               FirstNonAddress;
+  UINT64               Pci64Base, Pci64Size;
+  RETURN_STATUS        PcdStatus;
+
+  FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
+
+  //
+  // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
+  // resources to 32-bit anyway. See DegradeResource() in
+  // "PciResourceSupport.c".
+  //
+#ifdef MDE_CPU_IA32
+  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+    return FirstNonAddress;
+  }
+#endif
+
+  //
+  // Otherwise, in order to calculate the highest address plus one, we must
+  // consider the 64-bit PCI host aperture too. Fetch the default size.
+  //
+  Pci64Size = PcdGet64 (PcdPciMmio64Size);
+
+  if (Pci64Size == 0) {
+    if (mBootMode != BOOT_ON_S3_RESUME) {
+      DEBUG ((EFI_D_INFO, "%a: disabling 64-bit PCI host aperture\n",
+        __FUNCTION__));
+      PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);
+      ASSERT_RETURN_ERROR (PcdStatus);
+    }
+
+    //
+    // There's nothing more to do; the amount of memory above 4GB fully
+    // determines the highest address plus one. The memory hotplug area (see
+    // below) plays no role for the firmware in this case.
+    //
+    return FirstNonAddress;
+  }
+
+  //
+  // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
+  // that the host can map it with 1GB hugepages. Follow suit.
+  //
+  Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
+  Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);
+
+  //
+  // The 64-bit PCI host aperture should also be "naturally" aligned. The
+  // alignment is determined by rounding the size of the aperture down to the
+  // next smaller or equal power of two. That is, align the aperture by the
+  // largest BAR size that can fit into it.
+  //
+  Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));
+
+  if (mBootMode != BOOT_ON_S3_RESUME) {
+    //
+    // The core PciHostBridgeDxe driver will automatically add this range to
+    // the GCD memory space map through our PciHostBridgeLib instance; here we
+    // only need to set the PCDs.
+    //
+    PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);
+    ASSERT_RETURN_ERROR (PcdStatus);
+    PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
+    ASSERT_RETURN_ERROR (PcdStatus);
+
+    DEBUG ((EFI_D_INFO, "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
+      __FUNCTION__, Pci64Base, Pci64Size));
+  }
+
+  //
+  // The useful address space ends with the 64-bit PCI host aperture.
+  //
+  FirstNonAddress = Pci64Base + Pci64Size;
+  return FirstNonAddress;
+}
+
+
+/**
+  Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
+**/
+VOID
+AddressWidthInitialization (
+  VOID
+  )
+{
+  UINT64 FirstNonAddress;
+
+  //
+  // As guest-physical memory size grows, the permanent PEI RAM requirements
+  // are dominated by the identity-mapping page tables built by the DXE IPL.
+  // The DXL IPL keys off of the physical address bits advertized in the CPU
+  // HOB. To conserve memory, we calculate the minimum address width here.
+  //
+  FirstNonAddress      = GetFirstNonAddress ();
+  mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
+
+  //
+  // If FirstNonAddress is not an integral power of two, then we need an
+  // additional bit.
+  //
+  if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
+    ++mPhysMemAddressWidth;
+  }
+
+  //
+  // The minimum address width is 36 (covers up to and excluding 64 GB, which
+  // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
+  // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
+  // can simply assert that here, since 48 bits are good enough for 256 TB.
+  //
+  if (mPhysMemAddressWidth <= 36) {
+    mPhysMemAddressWidth = 36;
+  }
+  ASSERT (mPhysMemAddressWidth <= 48);
+}
+
+
+/**
+  Calculate the cap for the permanent PEI memory.
+**/
+STATIC
+UINT32
+GetPeiMemoryCap (
+  VOID
+  )
+{
+  BOOLEAN Page1GSupport;
+  UINT32  RegEax;
+  UINT32  RegEdx;
+  UINT32  Pml4Entries;
+  UINT32  PdpEntries;
+  UINTN   TotalPages;
+
+  //
+  // If DXE is 32-bit, then just return the traditional 64 MB cap.
+  //
+#ifdef MDE_CPU_IA32
+  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+    return SIZE_64MB;
+  }
+#endif
+
+  //
+  // Dependent on physical address width, PEI memory allocations can be
+  // dominated by the page tables built for 64-bit DXE. So we key the cap off
+  // of those. The code below is based on CreateIdentityMappingPageTables() in
+  // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
+  //
+  Page1GSupport = FALSE;
+  if (PcdGetBool (PcdUse1GPageTable)) {
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+    if (RegEax >= 0x80000001) {
+      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+      if ((RegEdx & BIT26) != 0) {
+        Page1GSupport = TRUE;
+      }
+    }
+  }
+
+  if (mPhysMemAddressWidth <= 39) {
+    Pml4Entries = 1;
+    PdpEntries = 1 << (mPhysMemAddressWidth - 30);
+    ASSERT (PdpEntries <= 0x200);
+  } else {
+    Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
+    ASSERT (Pml4Entries <= 0x200);
+    PdpEntries = 512;
+  }
+
+  TotalPages = Page1GSupport ? Pml4Entries + 1 :
+                               (PdpEntries + 1) * Pml4Entries + 1;
+  ASSERT (TotalPages <= 0x40201);
+
+  //
+  // Add 64 MB for miscellaneous allocations. Note that for
+  // mPhysMemAddressWidth values close to 36, the cap will actually be
+  // dominated by this increment.
+  //
+  return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);
+}
+
+
+/**
+  Publish PEI core memory
+
+  @return EFI_SUCCESS     The PEIM initialized successfully.
+
+**/
+EFI_STATUS
+PublishPeiMemory (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_PHYSICAL_ADDRESS        MemoryBase;
+  UINT64                      MemorySize;
+  UINT32                      LowerMemorySize;
+  UINT32                      PeiMemoryCap;
+
+  LowerMemorySize = GetSystemMemorySizeBelow4gb ();
+
+  //
+  // If S3 is supported, then the S3 permanent PEI memory is placed next,
+  // downwards. Its size is primarily dictated by CpuMpPei. The formula below
+  // is an approximation.
+  //
+  if (mS3Supported) {
+    mS3AcpiReservedMemorySize = SIZE_512KB +
+      PcdGet32 (PcdCpuMaxLogicalProcessorNumber) *
+      PcdGet32 (PcdCpuApStackSize);
+    mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;
+    LowerMemorySize = mS3AcpiReservedMemoryBase;
+  }
+
+  if (mBootMode == BOOT_ON_S3_RESUME) {
+    MemoryBase = mS3AcpiReservedMemoryBase;
+    MemorySize = mS3AcpiReservedMemorySize;
+  } else {
+    PeiMemoryCap = GetPeiMemoryCap ();
+    DEBUG ((EFI_D_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
+      __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));
+
+    //
+    // Determine the range of memory to use during PEI
+    //
+    // Technically we could lay the permanent PEI RAM over SEC's temporary
+    // decompression and scratch buffer even if "secure S3" is needed, since
+    // their lifetimes don't overlap. However, PeiFvInitialization() will cover
+    // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory
+    // allocation HOB, and other allocations served from the permanent PEI RAM
+    // shouldn't overlap with that HOB.
+    //
+    MemoryBase = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ?
+      PcdGet32 (PcdOvmfDecompressionScratchEnd) :
+      PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);
+    MemorySize = LowerMemorySize - MemoryBase;
+    if (MemorySize > PeiMemoryCap) {
+      MemoryBase = LowerMemorySize - PeiMemoryCap;
+      MemorySize = PeiMemoryCap;
+    }
+  }
+
+  //
+  // Publish this memory to the PEI Core
+  //
+  Status = PublishSystemMemory(MemoryBase, MemorySize);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+
+/**
+  Publish system RAM and reserve memory regions
+
+**/
+VOID
+InitializeRamRegions (
+  VOID
+  )
+{
+  XenPublishRamRegions ();
+
+  if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
+    //
+    // This is the memory range that will be used for PEI on S3 resume
+    //
+    BuildMemoryAllocationHob (
+      mS3AcpiReservedMemoryBase,
+      mS3AcpiReservedMemorySize,
+      EfiACPIMemoryNVS
+      );
+
+    //
+    // Cover the initial RAM area used as stack and temporary PEI heap.
+    //
+    // This is reserved as ACPI NVS so it can be used on S3 resume.
+    //
+    BuildMemoryAllocationHob (
+      PcdGet32 (PcdOvmfSecPeiTempRamBase),
+      PcdGet32 (PcdOvmfSecPeiTempRamSize),
+      EfiACPIMemoryNVS
+      );
+
+    //
+    // SEC stores its table of GUIDed section handlers here.
+    //
+    BuildMemoryAllocationHob (
+      PcdGet64 (PcdGuidedExtractHandlerTableAddress),
+      PcdGet32 (PcdGuidedExtractHandlerTableSize),
+      EfiACPIMemoryNVS
+      );
+
+#ifdef MDE_CPU_X64
+    //
+    // Reserve the initial page tables built by the reset vector code.
+    //
+    // Since this memory range will be used by the Reset Vector on S3
+    // resume, it must be reserved as ACPI NVS.
+    //
+    BuildMemoryAllocationHob (
+      (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecPageTablesBase),
+      (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),
+      EfiACPIMemoryNVS
+      );
+#endif
+  }
+
+  if (mBootMode != BOOT_ON_S3_RESUME) {
+    if (!FeaturePcdGet (PcdSmmSmramRequire)) {
+      //
+      // Reserve the lock box storage area
+      //
+      // Since this memory range will be used on S3 resume, it must be
+      // reserved as ACPI NVS.
+      //
+      // If S3 is unsupported, then various drivers might still write to the
+      // LockBox area. We ought to prevent DXE from serving allocation requests
+      // such that they would overlap the LockBox storage.
+      //
+      ZeroMem (
+        (VOID*)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),
+        (UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize)
+        );
+      BuildMemoryAllocationHob (
+        (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),
+        (UINT64)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize),
+        mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+        );
+    }
+
+    if (FeaturePcdGet (PcdSmmSmramRequire)) {
+      UINT32 TsegSize;
+
+      //
+      // Make sure the TSEG area that we reported as a reserved memory resource
+      // cannot be used for reserved memory allocations.
+      //
+      TsegSize = FixedPcdGet8 (PcdQ35TsegMbytes) * SIZE_1MB;
+      BuildMemoryAllocationHob (
+        GetSystemMemorySizeBelow4gb() - TsegSize,
+        TsegSize,
+        EfiReservedMemoryType
+        );
+    }
+  }
+}
diff --git a/OvmfPkg/XenPlatformPei/Platform.c b/OvmfPkg/XenPlatformPei/Platform.c
new file mode 100644
index 0000000..bf78878
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Platform.c
@@ -0,0 +1,536 @@ 
+/**@file
+  Platform PEI driver
+
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Ppi/MasterBootMode.h>
+#include <IndustryStandard/Pci22.h>
+#include <OvmfPlatforms.h>
+
+#include "Platform.h"
+#include "Cmos.h"
+
+EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
+  { EfiACPIMemoryNVS,       0x004 },
+  { EfiACPIReclaimMemory,   0x008 },
+  { EfiReservedMemoryType,  0x004 },
+  { EfiRuntimeServicesData, 0x024 },
+  { EfiRuntimeServicesCode, 0x030 },
+  { EfiBootServicesCode,    0x180 },
+  { EfiBootServicesData,    0xF00 },
+  { EfiMaxMemoryType,       0x000 }
+};
+
+
+EFI_PEI_PPI_DESCRIPTOR   mPpiBootMode[] = {
+  {
+    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+    &gEfiPeiMasterBootModePpiGuid,
+    NULL
+  }
+};
+
+
+UINT16 mHostBridgeDevId;
+
+EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
+
+BOOLEAN mS3Supported = FALSE;
+
+
+VOID
+AddIoMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_MEMORY_MAPPED_IO,
+      EFI_RESOURCE_ATTRIBUTE_PRESENT     |
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_TESTED,
+    MemoryBase,
+    MemorySize
+    );
+}
+
+VOID
+AddReservedMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize,
+  BOOLEAN                     Cacheable
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_MEMORY_RESERVED,
+      EFI_RESOURCE_ATTRIBUTE_PRESENT     |
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+      (Cacheable ?
+       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
+       0
+       ) |
+      EFI_RESOURCE_ATTRIBUTE_TESTED,
+    MemoryBase,
+    MemorySize
+    );
+}
+
+VOID
+AddIoMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  )
+{
+  AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
+
+
+VOID
+AddMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_SYSTEM_MEMORY,
+      EFI_RESOURCE_ATTRIBUTE_PRESENT |
+      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+      EFI_RESOURCE_ATTRIBUTE_TESTED,
+    MemoryBase,
+    MemorySize
+    );
+}
+
+
+VOID
+AddMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  )
+{
+  AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
+
+
+VOID
+MemMapInitialization (
+  VOID
+  )
+{
+  UINT64        PciIoBase;
+  UINT64        PciIoSize;
+  RETURN_STATUS PcdStatus;
+
+  PciIoBase = 0xC000;
+  PciIoSize = 0x4000;
+
+  //
+  // Create Memory Type Information HOB
+  //
+  BuildGuidDataHob (
+    &gEfiMemoryTypeInformationGuid,
+    mDefaultMemoryTypeInformation,
+    sizeof(mDefaultMemoryTypeInformation)
+    );
+
+  //
+  // Video memory + Legacy BIOS region
+  //
+  AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+
+  if (!mXen) {
+    UINT32  TopOfLowRam;
+    UINT64  PciExBarBase;
+    UINT32  PciBase;
+    UINT32  PciSize;
+
+    TopOfLowRam = GetSystemMemorySizeBelow4gb ();
+    PciExBarBase = 0;
+    if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+      //
+      // The MMCONFIG area is expected to fall between the top of low RAM and
+      // the base of the 32-bit PCI host aperture.
+      //
+      PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
+      ASSERT (TopOfLowRam <= PciExBarBase);
+      ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
+      PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
+    } else {
+      PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
+    }
+
+    //
+    // address       purpose   size
+    // ------------  --------  -------------------------
+    // max(top, 2g)  PCI MMIO  0xFC000000 - max(top, 2g)
+    // 0xFC000000    gap                           44 MB
+    // 0xFEC00000    IO-APIC                        4 KB
+    // 0xFEC01000    gap                         1020 KB
+    // 0xFED00000    HPET                           1 KB
+    // 0xFED00400    gap                          111 KB
+    // 0xFED1C000    gap (PIIX4) / RCRB (ICH9)     16 KB
+    // 0xFED20000    gap                          896 KB
+    // 0xFEE00000    LAPIC                          1 MB
+    //
+    PciSize = 0xFC000000 - PciBase;
+    AddIoMemoryBaseSizeHob (PciBase, PciSize);
+    PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
+    ASSERT_RETURN_ERROR (PcdStatus);
+    PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
+    ASSERT_RETURN_ERROR (PcdStatus);
+
+    AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
+    AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
+    if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+      AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
+      //
+      // Note: there should be an
+      //
+      //   AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
+      //
+      // call below, just like the one above for RCBA. However, Linux insists
+      // that the MMCONFIG area be marked in the E820 or UEFI memory map as
+      // "reserved memory" -- Linux does not content itself with a simple gap
+      // in the memory map wherever the MCFG ACPI table points to.
+      //
+      // This appears to be a safety measure. The PCI Firmware Specification
+      // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
+      // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
+      // [...]". (Emphasis added here.)
+      //
+      // Normally we add memory resource descriptor HOBs in
+      // QemuInitializeRam(), and pre-allocate from those with memory
+      // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
+      // is most definitely not RAM; so, as an exception, cover it with
+      // uncacheable reserved memory right here.
+      //
+      AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
+      BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,
+        EfiReservedMemoryType);
+    }
+    AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB);
+
+    //
+    // On Q35, the IO Port space is available for PCI resource allocations from
+    // 0x6000 up.
+    //
+    if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+      PciIoBase = 0x6000;
+      PciIoSize = 0xA000;
+      ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);
+    }
+  }
+
+  //
+  // Add PCI IO Port space available for PCI resource allocations.
+  //
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_IO,
+    EFI_RESOURCE_ATTRIBUTE_PRESENT     |
+    EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
+    PciIoBase,
+    PciIoSize
+    );
+  PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
+  ASSERT_RETURN_ERROR (PcdStatus);
+  PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
+  ASSERT_RETURN_ERROR (PcdStatus);
+}
+
+VOID
+PciExBarInitialization (
+  VOID
+  )
+{
+  union {
+    UINT64 Uint64;
+    UINT32 Uint32[2];
+  } PciExBarBase;
+
+  //
+  // We only support the 256MB size for the MMCONFIG area:
+  // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
+  //
+  // The masks used below enforce the Q35 requirements that the MMCONFIG area
+  // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
+  //
+  // Note that (b) also ensures that the minimum address width we have
+  // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
+  // for DXE's page tables to cover the MMCONFIG area.
+  //
+  PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
+  ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
+  ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
+
+  //
+  // Clear the PCIEXBAREN bit first, before programming the high register.
+  //
+  PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
+
+  //
+  // Program the high register. Then program the low register, setting the
+  // MMCONFIG area size and enabling decoding at once.
+  //
+  PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
+  PciWrite32 (
+    DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
+    PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
+    );
+}
+
+VOID
+MiscInitialization (
+  VOID
+  )
+{
+  UINTN         PmCmd;
+  UINTN         Pmba;
+  UINT32        PmbaAndVal;
+  UINT32        PmbaOrVal;
+  UINTN         AcpiCtlReg;
+  UINT8         AcpiEnBit;
+  RETURN_STATUS PcdStatus;
+
+  //
+  // Disable A20 Mask
+  //
+  IoOr8 (0x92, BIT1);
+
+  //
+  // Build the CPU HOB with guest RAM size dependent address width and 16-bits
+  // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
+  // S3 resume as well, so we build it unconditionally.)
+  //
+  BuildCpuHob (mPhysMemAddressWidth, 16);
+
+  //
+  // Determine platform type and save Host Bridge DID to PCD
+  //
+  switch (mHostBridgeDevId) {
+    case INTEL_82441_DEVICE_ID:
+      PmCmd      = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
+      Pmba       = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
+      PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
+      PmbaOrVal  = PIIX4_PMBA_VALUE;
+      AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
+      AcpiEnBit  = PIIX4_PMREGMISC_PMIOSE;
+      break;
+    case INTEL_Q35_MCH_DEVICE_ID:
+      PmCmd      = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
+      Pmba       = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
+      PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
+      PmbaOrVal  = ICH9_PMBASE_VALUE;
+      AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
+      AcpiEnBit  = ICH9_ACPI_CNTL_ACPI_EN;
+      break;
+    default:
+      DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
+        __FUNCTION__, mHostBridgeDevId));
+      ASSERT (FALSE);
+      return;
+  }
+  PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  //
+  // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
+  // has been configured (e.g., by Xen) and skip the setup here.
+  // This matches the logic in AcpiTimerLibConstructor ().
+  //
+  if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
+    //
+    // The PEI phase should be exited with fully accessibe ACPI PM IO space:
+    // 1. set PMBA
+    //
+    PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
+
+    //
+    // 2. set PCICMD/IOSE
+    //
+    PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
+
+    //
+    // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
+    //
+    PciOr8 (AcpiCtlReg, AcpiEnBit);
+  }
+
+  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+    //
+    // Set Root Complex Register Block BAR
+    //
+    PciWrite32 (
+      POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
+      ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
+      );
+
+    //
+    // Set PCI Express Register Range Base Address
+    //
+    PciExBarInitialization ();
+  }
+}
+
+
+VOID
+BootModeInitialization (
+  VOID
+  )
+{
+  EFI_STATUS    Status;
+
+  if (CmosRead8 (0xF) == 0xFE) {
+    mBootMode = BOOT_ON_S3_RESUME;
+  }
+  CmosWrite8 (0xF, 0x00);
+
+  Status = PeiServicesSetBootMode (mBootMode);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = PeiServicesInstallPpi (mPpiBootMode);
+  ASSERT_EFI_ERROR (Status);
+}
+
+
+VOID
+ReserveEmuVariableNvStore (
+  )
+{
+  EFI_PHYSICAL_ADDRESS VariableStore;
+  RETURN_STATUS        PcdStatus;
+
+  //
+  // Allocate storage for NV variables early on so it will be
+  // at a consistent address.  Since VM memory is preserved
+  // across reboots, this allows the NV variable storage to survive
+  // a VM reboot.
+  //
+  VariableStore =
+    (EFI_PHYSICAL_ADDRESS)(UINTN)
+      AllocateAlignedRuntimePages (
+        EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)),
+        PcdGet32 (PcdFlashNvStorageFtwSpareSize)
+        );
+  DEBUG ((EFI_D_INFO,
+          "Reserved variable store memory: 0x%lX; size: %dkb\n",
+          VariableStore,
+          (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
+        ));
+  PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
+  ASSERT_RETURN_ERROR (PcdStatus);
+}
+
+
+VOID
+DebugDumpCmos (
+  VOID
+  )
+{
+  UINT32 Loop;
+
+  DEBUG ((EFI_D_INFO, "CMOS:\n"));
+
+  for (Loop = 0; Loop < 0x80; Loop++) {
+    if ((Loop % 0x10) == 0) {
+      DEBUG ((EFI_D_INFO, "%02x:", Loop));
+    }
+    DEBUG ((EFI_D_INFO, " %02x", CmosRead8 (Loop)));
+    if ((Loop % 0x10) == 0xf) {
+      DEBUG ((EFI_D_INFO, "\n"));
+    }
+  }
+}
+
+
+
+/**
+  Perform Platform PEI initialization.
+
+  @param  FileHandle      Handle of the file being invoked.
+  @param  PeiServices     Describes the list of possible PEI Services.
+
+  @return EFI_SUCCESS     The PEIM initialized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeXenPlatform (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n"));
+
+  DebugDumpCmos ();
+
+  XenDetect ();
+
+  BootModeInitialization ();
+  AddressWidthInitialization ();
+
+  PublishPeiMemory ();
+
+  InitializeRamRegions ();
+
+  if (mXen) {
+    DEBUG ((EFI_D_INFO, "Xen was detected\n"));
+    InitializeXen ();
+  } else {
+    DEBUG ((EFI_D_ERROR, "not running on Xen\n"));
+    CpuDeadLoop ();
+  }
+
+  //
+  // Query Host Bridge DID
+  //
+  mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
+
+  if (mBootMode != BOOT_ON_S3_RESUME) {
+    ReserveEmuVariableNvStore ();
+    PeiFvInitialization ();
+    MemMapInitialization ();
+  }
+
+  MiscInitialization ();
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/XenPlatformPei/Platform.h b/OvmfPkg/XenPlatformPei/Platform.h
new file mode 100644
index 0000000..eda765b
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Platform.h
@@ -0,0 +1,104 @@ 
+/** @file
+  Platform PEI module include file.
+
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PLATFORM_PEI_H_INCLUDED_
+#define _PLATFORM_PEI_H_INCLUDED_
+
+#include <IndustryStandard/E820.h>
+
+VOID
+AddIoMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  );
+
+VOID
+AddIoMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  );
+
+VOID
+AddMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  );
+
+VOID
+AddMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  );
+
+VOID
+AddReservedMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize,
+  BOOLEAN                     Cacheable
+  );
+
+VOID
+AddressWidthInitialization (
+  VOID
+  );
+
+EFI_STATUS
+PublishPeiMemory (
+  VOID
+  );
+
+UINT32
+GetSystemMemorySizeBelow4gb (
+  VOID
+  );
+
+VOID
+InitializeRamRegions (
+  VOID
+  );
+
+EFI_STATUS
+PeiFvInitialization (
+  VOID
+  );
+
+VOID
+InstallFeatureControlCallback (
+  VOID
+  );
+
+EFI_STATUS
+InitializeXen (
+  VOID
+  );
+
+BOOLEAN
+XenDetect (
+  VOID
+  );
+
+extern BOOLEAN mXen;
+
+VOID
+XenPublishRamRegions (
+  VOID
+  );
+
+extern EFI_BOOT_MODE mBootMode;
+
+extern BOOLEAN mS3Supported;
+
+extern UINT8 mPhysMemAddressWidth;
+
+#endif // _PLATFORM_PEI_H_INCLUDED_
diff --git a/OvmfPkg/XenPlatformPei/Xen.c b/OvmfPkg/XenPlatformPei/Xen.c
new file mode 100644
index 0000000..ab38f97
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Xen.c
@@ -0,0 +1,231 @@ 
+/**@file
+  Xen Platform PEI support
+
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Guid/XenInfo.h>
+#include <IndustryStandard/E820.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Library/MtrrLib.h>
+
+#include "Platform.h"
+#include "Xen.h"
+
+BOOLEAN mXen = FALSE;
+
+STATIC UINT32 mXenLeaf = 0;
+
+EFI_XEN_INFO mXenInfo;
+
+/**
+  Returns E820 map provided by Xen
+
+  @param Entries      Pointer to E820 map
+  @param Count        Number of entries
+
+  @return EFI_STATUS
+**/
+EFI_STATUS
+XenGetE820Map (
+  EFI_E820_ENTRY64 **Entries,
+  UINT32 *Count
+  )
+{
+  EFI_XEN_OVMF_INFO *Info =
+    (EFI_XEN_OVMF_INFO *)(UINTN) OVMF_INFO_PHYSICAL_ADDRESS;
+
+  if (AsciiStrCmp ((CHAR8 *) Info->Signature, "XenHVMOVMF")) {
+    return EFI_NOT_FOUND;
+  }
+
+  ASSERT (Info->E820 < MAX_ADDRESS);
+  *Entries = (EFI_E820_ENTRY64 *)(UINTN) Info->E820;
+  *Count = Info->E820EntriesCount;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Connects to the Hypervisor.
+ 
+  @param  XenLeaf     CPUID index used to connect.
+
+  @return EFI_STATUS
+
+**/
+EFI_STATUS
+XenConnect (
+  UINT32 XenLeaf
+  )
+{
+  UINT32 Index;
+  UINT32 TransferReg;
+  UINT32 TransferPages;
+  UINT32 XenVersion;
+
+  AsmCpuid (XenLeaf + 2, &TransferPages, &TransferReg, NULL, NULL);
+  mXenInfo.HyperPages = AllocatePages (TransferPages);
+  if (!mXenInfo.HyperPages) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < TransferPages; Index++) {
+    AsmWriteMsr64 (TransferReg,
+                   (UINTN) mXenInfo.HyperPages +
+                   (Index << EFI_PAGE_SHIFT) + Index);
+  }
+
+  AsmCpuid (XenLeaf + 1, &XenVersion, NULL, NULL, NULL);
+  DEBUG ((EFI_D_ERROR, "Detected Xen version %d.%d\n",
+          XenVersion >> 16, XenVersion & 0xFFFF));
+  mXenInfo.VersionMajor = (UINT16)(XenVersion >> 16);
+  mXenInfo.VersionMinor = (UINT16)(XenVersion & 0xFFFF);
+
+  /* TBD: Locate hvm_info and reserve it away. */
+  mXenInfo.HvmInfo = NULL;
+
+  BuildGuidDataHob (
+    &gEfiXenInfoGuid,
+    &mXenInfo,
+    sizeof(mXenInfo)
+    );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Figures out if we are running inside Xen HVM.
+
+  @retval TRUE   Xen was detected
+  @retval FALSE  Xen was not detected
+
+**/
+BOOLEAN
+XenDetect (
+  VOID
+  )
+{
+  UINT8 Signature[13];
+
+  if (mXenLeaf != 0) {
+    return TRUE;
+  }
+
+  Signature[12] = '\0';
+  for (mXenLeaf = 0x40000000; mXenLeaf < 0x40010000; mXenLeaf += 0x100) {
+    AsmCpuid (mXenLeaf,
+              NULL,
+              (UINT32 *) &Signature[0],
+              (UINT32 *) &Signature[4],
+              (UINT32 *) &Signature[8]);
+
+    if (!AsciiStrCmp ((CHAR8 *) Signature, "XenVMMXenVMM")) {
+      mXen = TRUE;
+      return TRUE;
+    }
+  }
+
+  mXenLeaf = 0;
+  return FALSE;
+}
+
+
+VOID
+XenPublishRamRegions (
+  VOID
+  )
+{
+  EFI_E820_ENTRY64  *E820Map;
+  UINT32            E820EntriesCount;
+  EFI_STATUS        Status;
+
+  if (!mXen) {
+    return;
+  }
+
+  DEBUG ((EFI_D_INFO, "Using memory map provided by Xen\n"));
+
+  //
+  // Parse RAM in E820 map
+  //
+  E820EntriesCount = 0;
+  Status = XenGetE820Map (&E820Map, &E820EntriesCount);
+
+  ASSERT_EFI_ERROR (Status);
+
+  if (E820EntriesCount > 0) {
+    EFI_E820_ENTRY64 *Entry;
+    UINT32 Loop;
+
+    for (Loop = 0; Loop < E820EntriesCount; Loop++) {
+      Entry = E820Map + Loop;
+
+      //
+      // Only care about RAM
+      //
+      if (Entry->Type != EfiAcpiAddressRangeMemory) {
+        continue;
+      }
+
+      AddMemoryBaseSizeHob (Entry->BaseAddr, Entry->Length);
+
+      MtrrSetMemoryAttribute (Entry->BaseAddr, Entry->Length, CacheWriteBack);
+    }
+  }
+}
+
+
+/**
+  Perform Xen PEI initialization.
+
+  @return EFI_SUCCESS     Xen initialized successfully
+  @return EFI_NOT_FOUND   Not running under Xen
+
+**/
+EFI_STATUS
+InitializeXen (
+  VOID
+  )
+{
+  RETURN_STATUS PcdStatus;
+
+  if (mXenLeaf == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  XenConnect (mXenLeaf);
+
+  //
+  // Reserve away HVMLOADER reserved memory [0xFC000000,0xFD000000).
+  // This needs to match HVMLOADER RESERVED_MEMBASE/RESERVED_MEMSIZE.
+  //
+  AddReservedMemoryBaseSizeHob (0xFC000000, 0x1000000, FALSE);
+
+  PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, TRUE);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/XenPlatformPei/Xen.h b/OvmfPkg/XenPlatformPei/Xen.h
new file mode 100644
index 0000000..2a8a32b
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Xen.h
@@ -0,0 +1,45 @@ 
+/** @file
+  Ovmf info structure passed by Xen
+
+Copyright (c) 2013, Citrix Systems UK Ltd.<BR>
+
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __XEN_H__
+#define __XEN_H__
+
+#include <PiPei.h>
+
+// Physical address of OVMF info
+#define OVMF_INFO_PHYSICAL_ADDRESS 0x00001000
+
+// This structure must match the definition on Xen side
+#pragma pack(1)
+typedef struct {
+  CHAR8 Signature[14]; // XenHVMOVMF\0
+  UINT8 Length;        // Length of this structure
+  UINT8 Checksum;      // Set such that the sum over bytes 0..length == 0
+  //
+  // Physical address of an array of TablesCount elements.
+  //
+  // Each element contains the physical address of a BIOS table.
+  //
+  EFI_PHYSICAL_ADDRESS Tables;
+  UINT32 TablesCount;
+  //
+  // Physical address of the E820 table, contains E820EntriesCount entries.
+  //
+  EFI_PHYSICAL_ADDRESS E820;
+  UINT32 E820EntriesCount;
+} EFI_XEN_OVMF_INFO;
+#pragma pack()
+
+#endif /* __XEN_H__ */
diff --git a/OvmfPkg/XenPlatformPei/XenPlatformPei.inf b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf
new file mode 100644
index 0000000..dfa7d85
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf
@@ -0,0 +1,110 @@ 
+## @file
+#  Platform PEI driver
+#
+#  This module provides platform specific function to detect boot mode.
+#  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution. The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = XenPlatformPei
+  FILE_GUID                      = f112a6ee-993a-4f0b-8295-e52029d9b4ba
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeXenPlatform
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources]
+  Cmos.c
+  Fv.c
+  MemDetect.c
+  Platform.c
+  Xen.c
+
+[Packages]
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[Guids]
+  gEfiMemoryTypeInformationGuid
+  gEfiXenInfoGuid
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  HobLib
+  IoLib
+  PciLib
+  PeiResourcePublicationLib
+  PeiServicesLib
+  PeiServicesTablePointerLib
+  PeimEntryPoint
+  MtrrLib
+  PcdLib
+
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
+  gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes
+  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
+
+[FixedPcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+
+[FeaturePcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
+
+[Ppis]
+  gEfiPeiMasterBootModePpiGuid
+  gEfiPeiMpServicesPpiGuid
+
+[Depex]
+  TRUE
+