From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from SMTP02.CITRIX.COM (smtp02.citrix.com [66.165.176.63]) (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 801EF81F8F for ; Thu, 8 Dec 2016 07:35:53 -0800 (PST) X-IronPort-AV: E=Sophos;i="5.33,320,1477958400"; d="scan'208";a="402564145" From: Anthony PERARD To: , CC: Anthony PERARD Date: Thu, 8 Dec 2016 15:33:30 +0000 Message-ID: <20161208153340.2285-5-anthony.perard@citrix.com> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20161208153340.2285-1-anthony.perard@citrix.com> References: <20161208153340.2285-1-anthony.perard@citrix.com> MIME-Version: 1.0 Subject: [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, 08 Dec 2016 15:35:55 -0000 Content-Type: text/plain 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 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 + -- Anthony PERARD