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