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