From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id C706181993 for ; Thu, 5 Jan 2017 01:59:27 -0800 (PST) Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 44CFBC04B950; Thu, 5 Jan 2017 09:59:28 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-100.phx2.redhat.com [10.3.116.100]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v059xPnp026484; Thu, 5 Jan 2017 04:59:26 -0500 To: Anthony PERARD , edk2-devel@ml01.01.org, xen-devel@lists.xenproject.org References: <20161208153340.2285-1-anthony.perard@citrix.com> <20161208153340.2285-5-anthony.perard@citrix.com> From: Laszlo Ersek Message-ID: <18f5f2d0-7b42-8fdf-3342-f98b186337d8@redhat.com> Date: Thu, 5 Jan 2017 10:59:24 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.6.0 MIME-Version: 1.0 In-Reply-To: <20161208153340.2285-5-anthony.perard@citrix.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Thu, 05 Jan 2017 09:59:28 +0000 (UTC) Subject: Re: [PATCH RFC 04/14] OvmfPkg: Introduce XenPlatformPei X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 05 Jan 2017 09:59:28 -0000 Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit 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 > --- > 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 { > > 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.
> + 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.
> + 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.
> + 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 > +#include > +#include > +#include > + > + > +/** > + 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.
> + 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 > + > +// > +// The Library classes this module consumes > +// > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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.
> + Copyright (c) 2011, Andrei Warkentin > + > + 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 > + > +// > +// The Library classes this module consumes > +// > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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.
> + 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 > + > +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.
> + Copyright (c) 2011, Andrei Warkentin > + > + 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 > + > +// > +// The Library classes this module consumes > +// > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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.
> + > +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 > + > +// 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.
> +# > +# 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 > + >