[edk2-devel] [PATCH v3 04/35] OvmfPkg: Introduce XenPlatformPei

Anthony PERARD posted 35 patches 5 years, 4 months ago
There is a newer version of this series
[edk2-devel] [PATCH v3 04/35] OvmfPkg: Introduce XenPlatformPei
Posted by Anthony PERARD 5 years, 4 months ago
Introduce XenPlatformPei, a copy of OvmfPkg/PlatformPei without some
of QEMU specific initialization, Xen does not support QemuFwCfg.

This new module will be adjusted to accommodate Xen PVH.

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

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

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

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

Notes:
    v3:
      - fix coding style in new code
        (use DEBUG_xxx, add ASSERT before CpuDeadLoop)
      - rebased, SPDX

 OvmfPkg/OvmfXen.dsc                       |   2 +-
 OvmfPkg/OvmfXen.fdf                       |   2 +-
 OvmfPkg/XenPlatformPei/XenPlatformPei.inf |  96 +++++
 OvmfPkg/XenPlatformPei/Cmos.h             |  52 +++
 OvmfPkg/XenPlatformPei/Platform.h         | 108 ++++++
 OvmfPkg/XenPlatformPei/Xen.h              |  39 ++
 OvmfPkg/XenPlatformPei/AmdSev.c           |  64 ++++
 OvmfPkg/XenPlatformPei/ClearCache.c       | 112 ++++++
 OvmfPkg/XenPlatformPei/Cmos.c             |  60 +++
 OvmfPkg/XenPlatformPei/Fv.c               |  76 ++++
 OvmfPkg/XenPlatformPei/MemDetect.c        | 421 ++++++++++++++++++++
 OvmfPkg/XenPlatformPei/Platform.c         | 444 ++++++++++++++++++++++
 OvmfPkg/XenPlatformPei/Xen.c              | 219 +++++++++++
 13 files changed, 1693 insertions(+), 2 deletions(-)
 create mode 100644 OvmfPkg/XenPlatformPei/XenPlatformPei.inf
 create mode 100644 OvmfPkg/XenPlatformPei/Cmos.h
 create mode 100644 OvmfPkg/XenPlatformPei/Platform.h
 create mode 100644 OvmfPkg/XenPlatformPei/Xen.h
 create mode 100644 OvmfPkg/XenPlatformPei/AmdSev.c
 create mode 100644 OvmfPkg/XenPlatformPei/ClearCache.c
 create mode 100644 OvmfPkg/XenPlatformPei/Cmos.c
 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/Xen.c

diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index cab54da3e8..9f79d455fa 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -523,7 +523,7 @@ [Components]
   }

   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf

 

-  OvmfPkg/PlatformPei/PlatformPei.inf

+  OvmfPkg/XenPlatformPei/XenPlatformPei.inf

   UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf

   UefiCpuPkg/CpuMpPei/CpuMpPei.inf

 

diff --git a/OvmfPkg/OvmfXen.fdf b/OvmfPkg/OvmfXen.fdf
index 6fc8479aae..2ceff7baa2 100644
--- a/OvmfPkg/OvmfXen.fdf
+++ b/OvmfPkg/OvmfXen.fdf
@@ -152,7 +152,7 @@ [FV.PEIFV]
 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

 INF  UefiCpuPkg/CpuMpPei/CpuMpPei.inf

diff --git a/OvmfPkg/XenPlatformPei/XenPlatformPei.inf b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf
new file mode 100644
index 0000000000..d1265c365a
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf
@@ -0,0 +1,96 @@
+## @file

+#  Platform PEI driver

+#

+#  This module provides platform specific function to detect boot mode.

+#  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>

+#  Copyright (c) 2019, Citrix Systems, Inc.

+#

+#  SPDX-License-Identifier: BSD-2-Clause-Patent

+#

+##

+

+[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 EBC

+#

+

+[Sources]

+  AmdSev.c

+  ClearCache.c

+  Cmos.c

+  Cmos.h

+  Fv.c

+  MemDetect.c

+  Platform.c

+  Platform.h

+  Xen.c

+  Xen.h

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+  SecurityPkg/SecurityPkg.dec

+  UefiCpuPkg/UefiCpuPkg.dec

+  OvmfPkg/OvmfPkg.dec

+

+[Guids]

+  gEfiMemoryTypeInformationGuid

+  gEfiXenInfoGuid

+

+[LibraryClasses]

+  BaseLib

+  CacheMaintenanceLib

+  DebugLib

+  HobLib

+  IoLib

+  PciLib

+  ResourcePublicationLib

+  PeiServicesLib

+  PeimEntryPoint

+  MtrrLib

+  MemEncryptSevLib

+  PcdLib

+

+[Pcd]

+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase

+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize

+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase

+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize

+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase

+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize

+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId

+  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase

+  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize

+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base

+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size

+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base

+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size

+  gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes

+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize

+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved

+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration

+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode

+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable

+  gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask

+  gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy

+  gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress

+

+[FixedPcd]

+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress

+

+[Ppis]

+  gEfiPeiMasterBootModePpiGuid

+  gEfiPeiMpServicesPpiGuid

+

+[Depex]

+  TRUE

+

diff --git a/OvmfPkg/XenPlatformPei/Cmos.h b/OvmfPkg/XenPlatformPei/Cmos.h
new file mode 100644
index 0000000000..80ffcb002f
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Cmos.h
@@ -0,0 +1,52 @@
+/** @file

+  PC/AT CMOS access routines

+

+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#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/Platform.h b/OvmfPkg/XenPlatformPei/Platform.h
new file mode 100644
index 0000000000..77427496c0
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Platform.h
@@ -0,0 +1,108 @@
+/** @file

+  Platform PEI module include file.

+

+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#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

+  );

+

+VOID

+Q35TsegMbytesInitialization (

+  VOID

+  );

+

+EFI_STATUS

+PublishPeiMemory (

+  VOID

+  );

+

+UINT32

+GetSystemMemorySizeBelow4gb (

+  VOID

+  );

+

+VOID

+InitializeRamRegions (

+  VOID

+  );

+

+EFI_STATUS

+PeiFvInitialization (

+  VOID

+  );

+

+VOID

+InstallClearCacheCallback (

+  VOID

+  );

+

+EFI_STATUS

+InitializeXen (

+  VOID

+  );

+

+BOOLEAN

+XenDetect (

+  VOID

+  );

+

+VOID

+AmdSevInitialize (

+  VOID

+  );

+

+VOID

+XenPublishRamRegions (

+  VOID

+  );

+

+extern EFI_BOOT_MODE mBootMode;

+

+extern UINT8 mPhysMemAddressWidth;

+

+extern UINT16 mHostBridgeDevId;

+

+#endif // _PLATFORM_PEI_H_INCLUDED_

diff --git a/OvmfPkg/XenPlatformPei/Xen.h b/OvmfPkg/XenPlatformPei/Xen.h
new file mode 100644
index 0000000000..2605481280
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Xen.h
@@ -0,0 +1,39 @@
+/** @file

+  Ovmf info structure passed by Xen

+

+Copyright (c) 2013, Citrix Systems UK Ltd.<BR>

+

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#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/AmdSev.c b/OvmfPkg/XenPlatformPei/AmdSev.c
new file mode 100644
index 0000000000..7ebbb5cc1f
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/AmdSev.c
@@ -0,0 +1,64 @@
+/**@file

+  Initialize Secure Encrypted Virtualization (SEV) support

+

+  Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+//

+// The package level header files this module uses

+//

+#include <Library/DebugLib.h>

+#include <Library/MemEncryptSevLib.h>

+#include <Library/PcdLib.h>

+#include <PiPei.h>

+#include <Register/Amd/Cpuid.h>

+#include <Register/Cpuid.h>

+

+#include "Platform.h"

+

+/**

+

+  Function checks if SEV support is available, if present then it sets

+  the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.

+

+  **/

+VOID

+AmdSevInitialize (

+  VOID

+  )

+{

+  CPUID_MEMORY_ENCRYPTION_INFO_EBX  Ebx;

+  UINT64                            EncryptionMask;

+  RETURN_STATUS                     PcdStatus;

+

+  //

+  // Check if SEV is enabled

+  //

+  if (!MemEncryptSevIsEnabled ()) {

+    return;

+  }

+

+  //

+  // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position)

+  //

+  AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL);

+  EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits);

+

+  //

+  // Set Memory Encryption Mask PCD

+  //

+  PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);

+  ASSERT_RETURN_ERROR (PcdStatus);

+

+  DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));

+

+  //

+  // Set Pcd to Deny the execution of option ROM when security

+  // violation.

+  //

+  PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);

+  ASSERT_RETURN_ERROR (PcdStatus);

+}

diff --git a/OvmfPkg/XenPlatformPei/ClearCache.c b/OvmfPkg/XenPlatformPei/ClearCache.c
new file mode 100644
index 0000000000..fab53633a9
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/ClearCache.c
@@ -0,0 +1,112 @@
+/**@file

+  Install a callback to clear cache on all processors.

+  This is for conformance with the TCG "Platform Reset Attack Mitigation

+  Specification". Because clearing the CPU caches at boot doesn't impact

+  performance significantly, do it unconditionally, for simplicity's

+  sake.

+

+  Copyright (C) 2018, Red Hat, Inc.

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+**/

+

+#include <Library/CacheMaintenanceLib.h>

+#include <Library/DebugLib.h>

+#include <Library/PeiServicesLib.h>

+#include <Ppi/MpServices.h>

+

+#include "Platform.h"

+

+/**

+  Invalidate data & instruction caches.

+  All APs execute this function in parallel. The BSP executes the function

+  separately.

+

+  @param[in,out] WorkSpace  Pointer to the input/output argument workspace

+                            shared by all processors.

+**/

+STATIC

+VOID

+EFIAPI

+ClearCache (

+  IN OUT VOID *WorkSpace

+  )

+{

+  WriteBackInvalidateDataCache ();

+  InvalidateInstructionCache ();

+}

+

+/**

+  Notification function called when EFI_PEI_MP_SERVICES_PPI becomes available.

+

+  @param[in] PeiServices      Indirect reference to the PEI Services Table.

+  @param[in] NotifyDescriptor Address of the notification descriptor data

+                              structure.

+  @param[in] Ppi              Address of the PPI that was installed.

+

+  @return  Status of the notification. The status code returned from this

+           function is ignored.

+**/

+STATIC

+EFI_STATUS

+EFIAPI

+ClearCacheOnMpServicesAvailable (

+  IN EFI_PEI_SERVICES           **PeiServices,

+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,

+  IN VOID                       *Ppi

+  )

+{

+  EFI_PEI_MP_SERVICES_PPI *MpServices;

+  EFI_STATUS              Status;

+

+  DEBUG ((DEBUG_INFO, "%a: %a\n", gEfiCallerBaseName, __FUNCTION__));

+

+  //

+  // Clear cache on all the APs in parallel.

+  //

+  MpServices = Ppi;

+  Status = MpServices->StartupAllAPs (

+                         (CONST EFI_PEI_SERVICES **)PeiServices,

+                         MpServices,

+                         ClearCache,          // Procedure

+                         FALSE,               // SingleThread

+                         0,                   // TimeoutInMicroSeconds: inf.

+                         NULL                 // ProcedureArgument

+                         );

+  if (EFI_ERROR (Status) && Status != EFI_NOT_STARTED) {

+    DEBUG ((DEBUG_ERROR, "%a: StartupAllAps(): %r\n", __FUNCTION__, Status));

+    return Status;

+  }

+

+  //

+  // Now clear cache on the BSP too.

+  //

+  ClearCache (NULL);

+  return EFI_SUCCESS;

+}

+

+//

+// Notification object for registering the callback, for when

+// EFI_PEI_MP_SERVICES_PPI becomes available.

+//

+STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mMpServicesNotify = {

+  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | // Flags

+  EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,

+  &gEfiPeiMpServicesPpiGuid,               // Guid

+  ClearCacheOnMpServicesAvailable          // Notify

+};

+

+VOID

+InstallClearCacheCallback (

+  VOID

+  )

+{

+  EFI_STATUS           Status;

+

+  Status = PeiServicesNotifyPpi (&mMpServicesNotify);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a: failed to set up MP Services callback: %r\n",

+      __FUNCTION__, Status));

+  }

+}

diff --git a/OvmfPkg/XenPlatformPei/Cmos.c b/OvmfPkg/XenPlatformPei/Cmos.c
new file mode 100644
index 0000000000..5d9ee67cd8
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Cmos.c
@@ -0,0 +1,60 @@
+/** @file

+  PC/AT CMOS access routines

+

+  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+

+#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/Fv.c b/OvmfPkg/XenPlatformPei/Fv.c
new file mode 100644
index 0000000000..fac1ffc9fd
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Fv.c
@@ -0,0 +1,76 @@
+/** @file

+  Build FV related hobs for platform.

+

+  Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#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

+  )

+{

+  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),

+    EfiBootServicesData

+    );

+

+  //

+  // Let DXE know about the DXE FV

+  //

+  BuildFvHob (PcdGet32 (PcdOvmfDxeMemFvBase), PcdGet32 (PcdOvmfDxeMemFvSize));

+

+  //

+  // 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),

+    EfiBootServicesData

+    );

+

+  //

+  // 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 0000000000..cb7dd93ad6
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/MemDetect.c
@@ -0,0 +1,421 @@
+/**@file

+  Memory Detection for Virtual Machines.

+

+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+

+Module Name:

+

+  MemDetect.c

+

+**/

+

+//

+// The package level header files this module uses

+//

+#include <IndustryStandard/Q35MchIch9.h>

+#include <PiPei.h>

+

+//

+// The Library classes this module consumes

+//

+#include <Library/BaseLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/HobLib.h>

+#include <Library/IoLib.h>

+#include <Library/PcdLib.h>

+#include <Library/PciLib.h>

+#include <Library/PeimEntryPoint.h>

+#include <Library/ResourcePublicationLib.h>

+

+#include "Platform.h"

+#include "Cmos.h"

+

+UINT8 mPhysMemAddressWidth;

+

+STATIC UINT32 mS3AcpiReservedMemoryBase;

+STATIC UINT32 mS3AcpiReservedMemorySize;

+

+STATIC UINT16 mQ35TsegMbytes;

+

+VOID

+Q35TsegMbytesInitialization (

+  VOID

+  )

+{

+  UINT16        ExtendedTsegMbytes;

+  RETURN_STATUS PcdStatus;

+

+  if (mHostBridgeDevId != INTEL_Q35_MCH_DEVICE_ID) {

+    DEBUG ((

+      DEBUG_ERROR,

+      "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "

+      "only DID=0x%04x (Q35) is supported\n",

+      __FUNCTION__,

+      mHostBridgeDevId,

+      INTEL_Q35_MCH_DEVICE_ID

+      ));

+    ASSERT (FALSE);

+    CpuDeadLoop ();

+  }

+

+  //

+  // Check if QEMU offers an extended TSEG.

+  //

+  // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB

+  // register, and reading back the register.

+  //

+  // On a QEMU machine type that does not offer an extended TSEG, the initial

+  // write overwrites whatever value a malicious guest OS may have placed in

+  // the (unimplemented) register, before entering S3 or rebooting.

+  // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.

+  //

+  // On a QEMU machine type that offers an extended TSEG, the initial write

+  // triggers an update to the register. Subsequently, the value read back

+  // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the

+  // number of megabytes.

+  //

+  PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY);

+  ExtendedTsegMbytes = PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB));

+  if (ExtendedTsegMbytes == MCH_EXT_TSEG_MB_QUERY) {

+    mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);

+    return;

+  }

+

+  DEBUG ((

+    DEBUG_INFO,

+    "%a: QEMU offers an extended TSEG (%d MB)\n",

+    __FUNCTION__,

+    ExtendedTsegMbytes

+    ));

+  PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes);

+  ASSERT_RETURN_ERROR (PcdStatus);

+  mQ35TsegMbytes = ExtendedTsegMbytes;

+}

+

+

+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 (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

+    //

+    MemoryBase =

+      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 (mBootMode != BOOT_ON_S3_RESUME) {

+    //

+    // 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),

+      EfiBootServicesData

+      );

+  }

+}

diff --git a/OvmfPkg/XenPlatformPei/Platform.c b/OvmfPkg/XenPlatformPei/Platform.c
new file mode 100644
index 0000000000..c97a2fb6c1
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Platform.c
@@ -0,0 +1,444 @@
+/**@file

+  Platform PEI driver

+

+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>

+  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+//

+// 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/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;

+

+

+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);

+

+  //

+  // 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)

+      AllocateRuntimePages (

+        EFI_SIZE_TO_PAGES (2 * 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 ((DEBUG_INFO, "Platform PEIM Loaded\n"));

+

+  DebugDumpCmos ();

+

+  if (!XenDetect ()) {

+    DEBUG ((DEBUG_ERROR, "ERROR: Xen isn't detected\n"));

+    ASSERT (FALSE);

+    CpuDeadLoop ();

+  }

+

+  BootModeInitialization ();

+  AddressWidthInitialization ();

+

+  //

+  // Query Host Bridge DID

+  //

+  mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);

+

+  PublishPeiMemory ();

+

+  InitializeRamRegions ();

+

+  InitializeXen ();

+

+  if (mBootMode != BOOT_ON_S3_RESUME) {

+    ReserveEmuVariableNvStore ();

+    PeiFvInitialization ();

+    MemMapInitialization ();

+  }

+

+  InstallClearCacheCallback ();

+  AmdSevInitialize ();

+  MiscInitialization ();

+

+  return EFI_SUCCESS;

+}

diff --git a/OvmfPkg/XenPlatformPei/Xen.c b/OvmfPkg/XenPlatformPei/Xen.c
new file mode 100644
index 0000000000..81042ab94f
--- /dev/null
+++ b/OvmfPkg/XenPlatformPei/Xen.c
@@ -0,0 +1,219 @@
+/**@file

+  Xen Platform PEI support

+

+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>

+  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>

+  Copyright (c) 2019, Citrix Systems, Inc.

+

+  SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+//

+// 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"

+

+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")) {

+      return TRUE;

+    }

+  }

+

+  mXenLeaf = 0;

+  return FALSE;

+}

+

+

+VOID

+XenPublishRamRegions (

+  VOID

+  )

+{

+  EFI_E820_ENTRY64  *E820Map;

+  UINT32            E820EntriesCount;

+  EFI_STATUS        Status;

+

+  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;

+}

-- 
Anthony PERARD


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#43285): https://edk2.groups.io/g/devel/message/43285
Mute This Topic: https://groups.io/mt/32308571/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [PATCH v3 04/35] OvmfPkg: Introduce XenPlatformPei
Posted by Laszlo Ersek 5 years, 4 months ago
Hi Anthony,

On 07/04/19 16:42, Anthony PERARD wrote:
> Introduce XenPlatformPei, a copy of OvmfPkg/PlatformPei without some
> of QEMU specific initialization, Xen does not support QemuFwCfg.
> 
> This new module will be adjusted to accommodate Xen PVH.
> 
> fw_cfg dependents that have been removed, which are dynamically skipped
> when running PlatformPei on Xen:
> - GetFirstNonAddress(): controlling the 64-bit PCI MMIO aperture via the
> (experimental) "opt/ovmf/X-PciMmio64Mb" file
> - GetFirstNonAddress(): honoring the hotplug DIMM area
> ("etc/reserved-memory-end") in the placement of the 64-bit PCI MMIO
> aperture
> - NoexecDxeInitialization() is removed, so PcdPropertiesTableEnable and
> PcdSetNxForStack are left constant FALSE (not set dynamically from
> fw_cfg "opt/ovmf/PcdXxxx")
> - MaxCpuCountInitialization(), PublishPeiMemory(): the max CPU count is
> not taken from the QemuFwCfgItemSmpCpuCount fw_cfg key;
> PcdCpuMaxLogicalProcessorNumber is used intact and
> PcdCpuApInitTimeOutInMicroSeconds is never changed or used.
> - InitializeXenPlatform(), S3Verification(): S3 is assumed disabled (not
> consulting "etc/system-states" via QemuFwCfgS3Enabled()).
> - InstallFeatureControlCallback(): the feature control MSR is not set
> from "etc/msr_feature_control"
> (also removed FeatureControl.c as there is nothing been executed)
> 
> Also removed:
> - SMRAM/TSEG-related low mem size adjusting (PcdSmmSmramRequire is
> assumed FALSE) in PublishPeiMemory(),
> - QemuInitializeRam() entirely,
> 
> Xen related changes:
> - Have removed the module variable mXen, as it should be always true.
> - Have the platform PEI initialization fails if Xen has not been
>   detected.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1689
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> ---
> 
> Notes:
>     v3:
>       - fix coding style in new code
>         (use DEBUG_xxx, add ASSERT before CpuDeadLoop)
>       - rebased, SPDX

In my v2 review at
<http://mid.mail-archive.com/994d01f3-bae7-c447-6e28-5a61a84464ac@redhat.com>,
point (2), I meant that you should please replace *all* EFI_D_xxx macros
with DEBUG_xxx macros, in new code.

By "new code" I didn't mean code that you wrote afresh, but simply
source code that appeared as new -- i.e., as an addition -- in the
patch. That is, all the EFI_D_xxx macros that you inherit from
PlatformPei by virtue of copying should be replaced as well.

This v3 patch continues to add 12 instances of EFI_D_xxx, by my count.
Please replace all of those, with DEBUG_xxx.

The rest of the updates in v3 are good, and sufficient.

Thanks
Laszlo

-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#43357): https://edk2.groups.io/g/devel/message/43357
Mute This Topic: https://groups.io/mt/32308571/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-