From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-1.mimecast.com (us-smtp-delivery-1.mimecast.com [207.211.31.81]) by mx.groups.io with SMTP id smtpd.web10.3063.1587633884108426334 for ; Thu, 23 Apr 2020 02:24:44 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=UShNE00b; spf=pass (domain: redhat.com, ip: 207.211.31.81, mailfrom: lersek@redhat.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1587633883; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AwZmH5gaMYob1lCrhfOhmN0FiIdUPO93bi/jd0nH/CM=; b=UShNE00bc+5qd7jpcWxSP7qUhy0jyM53FNtKp6EMd11VoXUFER2yMaNc/u2bUO447kqHiZ W1T/C3N4vvXoNqOzi9SG4gwC7oHVORd+33RQLlTc9WWD+93tCwThVHPtS7OgjzL09MlZPz DZYHAq8/7EndpgAjDurRLPDGP3c46kw= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-261-JJYTIQleN2uf4dXqWPPB_g-1; Thu, 23 Apr 2020 05:24:37 -0400 X-MC-Unique: JJYTIQleN2uf4dXqWPPB_g-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4AD4318B9FC6; Thu, 23 Apr 2020 09:24:36 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-114-95.ams2.redhat.com [10.36.114.95]) by smtp.corp.redhat.com (Postfix) with ESMTP id A13EF5C1BD; Thu, 23 Apr 2020 09:24:33 +0000 (UTC) Subject: Re: [edk2-devel] [PATCH v3 5/6] BhyvePkg: Add PlatformPei To: devel@edk2.groups.io, rebecca@bsdio.com Cc: Jordan Justen , Ard Biesheuvel , Leif Lindholm , Michael Kinney , Andrew Fish , Peter Grehan References: <20200421030955.114850-1-rebecca@bsdio.com> <20200421030955.114850-6-rebecca@bsdio.com> From: "Laszlo Ersek" Message-ID: <54cbbf03-85bf-cf0c-a261-aa172f87e047@redhat.com> Date: Thu, 23 Apr 2020 11:24:32 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 In-Reply-To: <20200421030955.114850-6-rebecca@bsdio.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit On 04/21/20 05:09, Rebecca Cran wrote: > Make a copy of OvmfPkg/PlatformPei under BhyvePkg with the changes > that are needed to support the bhyve hypervisor. > > Signed-off-by: Rebecca Cran > --- > BhyvePkg/PlatformPei/AmdSev.c | 106 +++++ > BhyvePkg/PlatformPei/ClearCache.c | 111 +++++ > BhyvePkg/PlatformPei/Cmos.c | 58 +++ > BhyvePkg/PlatformPei/Cmos.h | 50 ++ > BhyvePkg/PlatformPei/FeatureControl.c | 20 + > BhyvePkg/PlatformPei/Fv.c | 94 ++++ > BhyvePkg/PlatformPei/MemDetect.c | 631 ++++++++++++++++++++++++++ > BhyvePkg/PlatformPei/Platform.c | 612 +++++++++++++++++++++++++ > BhyvePkg/PlatformPei/Platform.h | 136 ++++++ > BhyvePkg/PlatformPei/PlatformPei.inf | 117 +++++ > 10 files changed, 1935 insertions(+) > create mode 100644 BhyvePkg/PlatformPei/AmdSev.c > create mode 100644 BhyvePkg/PlatformPei/ClearCache.c > create mode 100644 BhyvePkg/PlatformPei/Cmos.c > create mode 100644 BhyvePkg/PlatformPei/Cmos.h > create mode 100644 BhyvePkg/PlatformPei/FeatureControl.c > create mode 100644 BhyvePkg/PlatformPei/Fv.c > create mode 100644 BhyvePkg/PlatformPei/MemDetect.c > create mode 100644 BhyvePkg/PlatformPei/Platform.c > create mode 100644 BhyvePkg/PlatformPei/Platform.h > create mode 100644 BhyvePkg/PlatformPei/PlatformPei.inf - There are multiple files added in this patch (MemDetect.c, Platform.c, PlatformPei.inf) that still don't use the SPDX-License-Identifier format, but spell out the license texts verbatim. Please fix up those. - Also, please refresh the copyright notices / years on these files, like I request under patch#4, in point (2). With those updates, I think I'll be ready to ACK this patch. Thanks, Laszlo > > diff --git a/BhyvePkg/PlatformPei/AmdSev.c b/BhyvePkg/PlatformPei/AmdSev.c > new file mode 100644 > index 0000000000..e484f4b311 > --- /dev/null > +++ b/BhyvePkg/PlatformPei/AmdSev.c > @@ -0,0 +1,106 @@ > +/**@file > + Initialize Secure Encrypted Virtualization (SEV) support > + > + Copyright (c) 2017, Advanced Micro Devices. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > +// > +// The package level header files this module uses > +// > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "Platform.h" > + > +/** > + > + Function checks if SEV support is available, if present then it sets > + the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask. > + > + **/ > +VOID > +AmdSevInitialize ( > + VOID > + ) > +{ > + CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx; > + UINT64 EncryptionMask; > + RETURN_STATUS PcdStatus; > + > + // > + // Check if SEV is enabled > + // > + if (!MemEncryptSevIsEnabled ()) { > + return; > + } > + > + // > + // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position) > + // > + AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL); > + EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits); > + > + // > + // Set Memory Encryption Mask PCD > + // > + PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask); > + ASSERT_RETURN_ERROR (PcdStatus); > + > + DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask)); > + > + // > + // Set Pcd to Deny the execution of option ROM when security > + // violation. > + // > + PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4); > + ASSERT_RETURN_ERROR (PcdStatus); > + > + // > + // When SMM is required, cover the pages containing the initial SMRAM Save > + // State Map with a memory allocation HOB: > + // > + // There's going to be a time interval between our decrypting those pages for > + // SMBASE relocation and re-encrypting the same pages after SMBASE > + // relocation. We shall ensure that the DXE phase stay away from those pages > + // until after re-encryption, in order to prevent an information leak to the > + // hypervisor. > + // > + if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) { > + RETURN_STATUS LocateMapStatus; > + UINTN MapPagesBase; > + UINTN MapPagesCount; > + > + LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages ( > + &MapPagesBase, > + &MapPagesCount > + ); > + ASSERT_RETURN_ERROR (LocateMapStatus); > + > + if (mQ35SmramAtDefaultSmbase) { > + // > + // The initial SMRAM Save State Map has been covered as part of a larger > + // reserved memory allocation in InitializeRamRegions(). > + // > + ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase); > + ASSERT ( > + (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <= > + SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE) > + ); > + } else { > + BuildMemoryAllocationHob ( > + MapPagesBase, // BaseAddress > + EFI_PAGES_TO_SIZE (MapPagesCount), // Length > + EfiBootServicesData // MemoryType > + ); > + } > + } > +} > diff --git a/BhyvePkg/PlatformPei/ClearCache.c b/BhyvePkg/PlatformPei/ClearCache.c > new file mode 100644 > index 0000000000..5c538c59e0 > --- /dev/null > +++ b/BhyvePkg/PlatformPei/ClearCache.c > @@ -0,0 +1,111 @@ > +/**@file > + Install a callback to clear cache on all processors. > + This is for conformance with the TCG "Platform Reset Attack Mitigation > + Specification". Because clearing the CPU caches at boot doesn't impact > + performance significantly, do it unconditionally, for simplicity's > + sake. > + > + Copyright (C) 2018, Red Hat, Inc. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include > +#include > +#include > +#include > + > +#include "Platform.h" > + > +/** > + Invalidate data & instruction caches. > + All APs execute this function in parallel. The BSP executes the function > + separately. > + > + @param[in,out] WorkSpace Pointer to the input/output argument workspace > + shared by all processors. > +**/ > +STATIC > +VOID > +EFIAPI > +ClearCache ( > + IN OUT VOID *WorkSpace > + ) > +{ > + WriteBackInvalidateDataCache (); > + InvalidateInstructionCache (); > +} > + > +/** > + Notification function called when EFI_PEI_MP_SERVICES_PPI becomes available. > + > + @param[in] PeiServices Indirect reference to the PEI Services Table. > + @param[in] NotifyDescriptor Address of the notification descriptor data > + structure. > + @param[in] Ppi Address of the PPI that was installed. > + > + @return Status of the notification. The status code returned from this > + function is ignored. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +ClearCacheOnMpServicesAvailable ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, > + IN VOID *Ppi > + ) > +{ > + EFI_PEI_MP_SERVICES_PPI *MpServices; > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_INFO, "%a: %a\n", gEfiCallerBaseName, __FUNCTION__)); > + > + // > + // Clear cache on all the APs in parallel. > + // > + MpServices = Ppi; > + Status = MpServices->StartupAllAPs ( > + (CONST EFI_PEI_SERVICES **)PeiServices, > + MpServices, > + ClearCache, // Procedure > + FALSE, // SingleThread > + 0, // TimeoutInMicroSeconds: inf. > + NULL // ProcedureArgument > + ); > + if (EFI_ERROR (Status) && Status != EFI_NOT_STARTED) { > + DEBUG ((DEBUG_ERROR, "%a: StartupAllAps(): %r\n", __FUNCTION__, Status)); > + return Status; > + } > + > + // > + // Now clear cache on the BSP too. > + // > + ClearCache (NULL); > + return EFI_SUCCESS; > +} > + > +// > +// Notification object for registering the callback, for when > +// EFI_PEI_MP_SERVICES_PPI becomes available. > +// > +STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mMpServicesNotify = { > + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | // Flags > + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, > + &gEfiPeiMpServicesPpiGuid, // Guid > + ClearCacheOnMpServicesAvailable // Notify > +}; > + > +VOID > +InstallClearCacheCallback ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + > + Status = PeiServicesNotifyPpi (&mMpServicesNotify); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a: failed to set up MP Services callback: %r\n", > + __FUNCTION__, Status)); > + } > +} > diff --git a/BhyvePkg/PlatformPei/Cmos.c b/BhyvePkg/PlatformPei/Cmos.c > new file mode 100644 > index 0000000000..9b34e10b17 > --- /dev/null > +++ b/BhyvePkg/PlatformPei/Cmos.c > @@ -0,0 +1,58 @@ > +/** @file > + PC/AT CMOS access routines > + > + Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > + > +#include "Cmos.h" > +#include "Library/IoLib.h" > + > +/** > + Reads 8-bits of CMOS data. > + > + Reads the 8-bits of CMOS data at the location specified by Index. > + The 8-bit read value is returned. > + > + @param Index The CMOS location to read. > + > + @return The value read. > + > +**/ > +UINT8 > +EFIAPI > +CmosRead8 ( > + IN UINTN Index > + ) > +{ > + IoWrite8 (0x70, (UINT8) Index); > + return IoRead8 (0x71); > +} > + > + > +/** > + Writes 8-bits of CMOS data. > + > + Writes 8-bits of CMOS data to the location specified by Index > + with the value specified by Value and returns Value. > + > + @param Index The CMOS location to write. > + @param Value The value to write to CMOS. > + > + @return The value written to CMOS. > + > +**/ > +UINT8 > +EFIAPI > +CmosWrite8 ( > + IN UINTN Index, > + IN UINT8 Value > + ) > +{ > + IoWrite8 (0x70, (UINT8) Index); > + IoWrite8 (0x71, Value); > + return Value; > +} > + > diff --git a/BhyvePkg/PlatformPei/Cmos.h b/BhyvePkg/PlatformPei/Cmos.h > new file mode 100644 > index 0000000000..3cd98799a3 > --- /dev/null > +++ b/BhyvePkg/PlatformPei/Cmos.h > @@ -0,0 +1,50 @@ > +/** @file > + PC/AT CMOS access routines > + > + Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef __CMOS_H__ > +#define __CMOS_H__ > + > +/** > + Reads 8-bits of CMOS data. > + > + Reads the 8-bits of CMOS data at the location specified by Index. > + The 8-bit read value is returned. > + > + @param Index The CMOS location to read. > + > + @return The value read. > + > +**/ > +UINT8 > +EFIAPI > +CmosRead8 ( > + IN UINTN Index > + ); > + > +/** > + Writes 8-bits of CMOS data. > + > + Writes 8-bits of CMOS data to the location specified by Index > + with the value specified by Value and returns Value. > + > + @param Index The CMOS location to write. > + @param Value The value to write to CMOS. > + > + @return The value written to CMOS. > + > +**/ > +UINT8 > +EFIAPI > +CmosWrite8 ( > + IN UINTN Index, > + IN UINT8 Value > + ); > + > + > +#endif > + > diff --git a/BhyvePkg/PlatformPei/FeatureControl.c b/BhyvePkg/PlatformPei/FeatureControl.c > new file mode 100644 > index 0000000000..418b11a370 > --- /dev/null > +++ b/BhyvePkg/PlatformPei/FeatureControl.c > @@ -0,0 +1,20 @@ > +/**@file > + Install a callback when necessary for setting the Feature Control MSR on all > + processors. > + > + Copyright (C) 2016, Red Hat, Inc. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "Platform.h" > + > +VOID > +InstallFeatureControlCallback ( > + VOID > + ) > +{ > + // > + // Nothing to do. > + // > +} > diff --git a/BhyvePkg/PlatformPei/Fv.c b/BhyvePkg/PlatformPei/Fv.c > new file mode 100644 > index 0000000000..ee4ecab615 > --- /dev/null > +++ b/BhyvePkg/PlatformPei/Fv.c > @@ -0,0 +1,94 @@ > +/** @file > + Build FV related hobs for platform. > + > + Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#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 ((DEBUG_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/BhyvePkg/PlatformPei/MemDetect.c b/BhyvePkg/PlatformPei/MemDetect.c > new file mode 100644 > index 0000000000..1e18886248 > --- /dev/null > +++ b/BhyvePkg/PlatformPei/MemDetect.c > @@ -0,0 +1,631 @@ > +/**@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 > +#include > +#include > + > +// > +// The Library classes this module consumes > +// > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "Platform.h" > +#include "Cmos.h" > + > +UINT8 mPhysMemAddressWidth; > + > +STATIC UINT32 mS3AcpiReservedMemoryBase; > +STATIC UINT32 mS3AcpiReservedMemorySize; > + > +STATIC UINT16 mQ35TsegMbytes; > + > +BOOLEAN mQ35SmramAtDefaultSmbase = FALSE; > + > +VOID > +Q35TsegMbytesInitialization ( > + VOID > + ) > +{ > + UINT16 ExtendedTsegMbytes; > + RETURN_STATUS PcdStatus; > + > + if (mHostBridgeDevId != INTEL_Q35_MCH_DEVICE_ID) { > + DEBUG (( > + DEBUG_ERROR, > + "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; " > + "only DID=0x%04x (Q35) is supported\n", > + __FUNCTION__, > + mHostBridgeDevId, > + INTEL_Q35_MCH_DEVICE_ID > + )); > + ASSERT (FALSE); > + CpuDeadLoop (); > + } > + > + // > + // Check if QEMU offers an extended TSEG. > + // > + // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TSEG_MB > + // register, and reading back the register. > + // > + // On a QEMU machine type that does not offer an extended TSEG, the initial > + // write overwrites whatever value a malicious guest OS may have placed in > + // the (unimplemented) register, before entering S3 or rebooting. > + // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged. > + // > + // On a QEMU machine type that offers an extended TSEG, the initial write > + // triggers an update to the register. Subsequently, the value read back > + // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us the > + // number of megabytes. > + // > + PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY); > + ExtendedTsegMbytes = PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB)); > + if (ExtendedTsegMbytes == MCH_EXT_TSEG_MB_QUERY) { > + mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes); > + return; > + } > + > + DEBUG (( > + DEBUG_INFO, > + "%a: QEMU offers an extended TSEG (%d MB)\n", > + __FUNCTION__, > + ExtendedTsegMbytes > + )); > + PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes); > + ASSERT_RETURN_ERROR (PcdStatus); > + mQ35TsegMbytes = ExtendedTsegMbytes; > +} > + > + > +UINT32 > +GetSystemMemorySizeBelow4gb ( > + VOID > + ) > +{ > + UINT8 Cmos0x34; > + UINT8 Cmos0x35; > + > + // > + // CMOS 0x34/0x35 specifies the system memory above 16 MB. > + // * CMOS(0x35) is the high byte > + // * CMOS(0x34) is the low byte > + // * The size is specified in 64kb chunks > + // * Since this is memory above 16MB, the 16MB must be added > + // into the calculation to get the total memory size. > + // > + > + Cmos0x34 = (UINT8) CmosRead8 (0x34); > + Cmos0x35 = (UINT8) CmosRead8 (0x35); > + > + return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB); > +} > + > + > +STATIC > +UINT64 > +GetSystemMemorySizeAbove4gb ( > + ) > +{ > + UINT32 Size; > + UINTN CmosIndex; > + > + // > + // CMOS 0x5b-0x5d specifies the system memory above 4GB MB. > + // * CMOS(0x5d) is the most significant size byte > + // * CMOS(0x5c) is the middle size byte > + // * CMOS(0x5b) is the least significant size byte > + // * The size is specified in 64kb chunks > + // > + > + Size = 0; > + for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) { > + Size = (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex); > + } > + > + return LShiftU64 (Size, 16); > +} > + > + > +/** > + Return the highest address that DXE could possibly use, plus one. > +**/ > +STATIC > +UINT64 > +GetFirstNonAddress ( > + VOID > + ) > +{ > + UINT64 FirstNonAddress; > + UINT64 Pci64Base, Pci64Size; > + RETURN_STATUS PcdStatus; > + > + FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb (); > + > + // > + // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO > + // resources to 32-bit anyway. See DegradeResource() in > + // "PciResourceSupport.c". > + // > +#ifdef MDE_CPU_IA32 > + if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { > + return FirstNonAddress; > + } > +#endif > + > + // > + // Otherwise, in order to calculate the highest address plus one, we must > + // consider the 64-bit PCI host aperture too. Fetch the default size. > + // > + Pci64Size = PcdGet64 (PcdPciMmio64Size); > + > + if (Pci64Size == 0) { > + if (mBootMode != BOOT_ON_S3_RESUME) { > + DEBUG ((DEBUG_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 ((DEBUG_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 (FeaturePcdGet (PcdSmmSmramRequire)) { > + // > + // TSEG is chipped from the end of low RAM > + // > + LowerMemorySize -= mQ35TsegMbytes * SIZE_1MB; > + } > + > + // > + // 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 + > + mMaxCpuCount * > + PcdGet32 (PcdCpuApStackSize); > + mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize; > + LowerMemorySize = mS3AcpiReservedMemoryBase; > + } > + > + if (mBootMode == BOOT_ON_S3_RESUME) { > + MemoryBase = mS3AcpiReservedMemoryBase; > + MemorySize = mS3AcpiReservedMemorySize; > + } else { > + PeiMemoryCap = GetPeiMemoryCap (); > + DEBUG ((DEBUG_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; > +} > + > + > +/** > + Peform Memory Detection for QEMU / KVM > + > +**/ > +STATIC > +VOID > +QemuInitializeRam ( > + VOID > + ) > +{ > + UINT64 LowerMemorySize; > + UINT64 UpperMemorySize; > + MTRR_SETTINGS MtrrSettings; > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__)); > + > + // > + // Determine total memory size available > + // > + LowerMemorySize = GetSystemMemorySizeBelow4gb (); > + UpperMemorySize = GetSystemMemorySizeAbove4gb (); > + > + if (mBootMode == BOOT_ON_S3_RESUME) { > + // > + // Create the following memory HOB as an exception on the S3 boot path. > + // > + // Normally we'd create memory HOBs only on the normal boot path. However, > + // CpuMpPei specifically needs such a low-memory HOB on the S3 path as > + // well, for "borrowing" a subset of it temporarily, for the AP startup > + // vector. > + // > + // CpuMpPei saves the original contents of the borrowed area in permanent > + // PEI RAM, in a backup buffer allocated with the normal PEI services. > + // CpuMpPei restores the original contents ("returns" the borrowed area) at > + // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before > + // transferring control to the OS's wakeup vector in the FACS. > + // > + // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to > + // restore the original contents. Furthermore, we expect all such PEIMs > + // (CpuMpPei included) to claim the borrowed areas by producing memory > + // allocation HOBs, and to honor preexistent memory allocation HOBs when > + // looking for an area to borrow. > + // > + AddMemoryRangeHob (0, BASE_512KB + BASE_128KB); > + } else { > + // > + // Create memory HOBs > + // > + AddMemoryRangeHob (0, BASE_512KB + BASE_128KB); > + > + if (FeaturePcdGet (PcdSmmSmramRequire)) { > + UINT32 TsegSize; > + > + TsegSize = mQ35TsegMbytes * SIZE_1MB; > + AddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize); > + AddReservedMemoryBaseSizeHob (LowerMemorySize - TsegSize, TsegSize, > + TRUE); > + } else { > + AddMemoryRangeHob (BASE_1MB, LowerMemorySize); > + } > + > + if (UpperMemorySize != 0) { > + AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize); > + } > + } > + > + // > + // We'd like to keep the following ranges uncached: > + // - [640 KB, 1 MB) > + // - [LowerMemorySize, 4 GB) > + // > + // Everything else should be WB. Unfortunately, programming the inverse (ie. > + // keeping the default UC, and configuring the complement set of the above as > + // WB) is not reliable in general, because the end of the upper RAM can have > + // practically any alignment, and we may not have enough variable MTRRs to > + // cover it exactly. > + // > + if (IsMtrrSupported ()) { > + MtrrGetAllMtrrs (&MtrrSettings); > + > + // > + // MTRRs disabled, fixed MTRRs disabled, default type is uncached > + // > + ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0); > + ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0); > + ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0); > + > + // > + // flip default type to writeback > + // > + SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06); > + ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables); > + MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6; > + MtrrSetAllMtrrs (&MtrrSettings); > + > + // > + // Set memory range from 640KB to 1MB to uncacheable > + // > + Status = MtrrSetMemoryAttribute (BASE_512KB + BASE_128KB, > + BASE_1MB - (BASE_512KB + BASE_128KB), CacheUncacheable); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Set memory range from the "top of lower RAM" (RAM below 4GB) to 4GB as > + // uncacheable > + // > + Status = MtrrSetMemoryAttribute (LowerMemorySize, > + SIZE_4GB - LowerMemorySize, CacheUncacheable); > + ASSERT_EFI_ERROR (Status); > + } > +} > + > +/** > + Publish system RAM and reserve memory regions > + > +**/ > +VOID > +InitializeRamRegions ( > + VOID > + ) > +{ > + QemuInitializeRam (); > + > + 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 = mQ35TsegMbytes * SIZE_1MB; > + BuildMemoryAllocationHob ( > + GetSystemMemorySizeBelow4gb() - TsegSize, > + TsegSize, > + EfiReservedMemoryType > + ); > + } > + } > +} > diff --git a/BhyvePkg/PlatformPei/Platform.c b/BhyvePkg/PlatformPei/Platform.c > new file mode 100644 > index 0000000000..10719d6f08 > --- /dev/null > +++ b/BhyvePkg/PlatformPei/Platform.c > @@ -0,0 +1,612 @@ > +/**@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; > + > +UINT32 mMaxCpuCount; > + > +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 (TRUE) { > + 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 > +NoexecDxeInitialization ( > + VOID > + ) > +{ > +} > + > +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 0x1275: // BHYVE > + 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 ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n", > + __FUNCTION__, mHostBridgeDevId)); > + ASSERT (FALSE); > + return; > + } > + PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId); > + ASSERT_RETURN_ERROR (PcdStatus); > + > + // > + // If the appropriate IOspace enable bit is set, assume the ACPI PMBA > + // has been configured (e.g., by Xen) and skip the setup here. > + // This matches the logic in AcpiTimerLibConstructor (). > + // > + if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) { > + // > + // The PEI phase should be exited with fully accessibe ACPI PM IO space: > + // 1. set PMBA > + // > + PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal); > + > + // > + // 2. set PCICMD/IOSE > + // > + PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE); > + > + // > + // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN) > + // > + PciOr8 (AcpiCtlReg, AcpiEnBit); > + } > + > + if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { > + // > + // Set Root Complex Register Block BAR > + // > + PciWrite32 ( > + POWER_MGMT_REGISTER_Q35 (ICH9_RCBA), > + ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN > + ); > + > + // > + // Set PCI Express Register Range Base Address > + // > + PciExBarInitialization (); > + } > +} > + > + > +VOID > +BootModeInitialization ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + > + if (CmosRead8 (0xF) == 0xFE) { > + mBootMode = BOOT_ON_S3_RESUME; > + } > + CmosWrite8 (0xF, 0x00); > + > + Status = PeiServicesSetBootMode (mBootMode); > + ASSERT_EFI_ERROR (Status); > + > + Status = PeiServicesInstallPpi (mPpiBootMode); > + ASSERT_EFI_ERROR (Status); > +} > + > + > +VOID > +ReserveEmuVariableNvStore ( > + ) > +{ > + EFI_PHYSICAL_ADDRESS VariableStore; > + RETURN_STATUS PcdStatus; > + > + // > + // Allocate storage for NV variables early on so it will be > + // at a consistent address. Since VM memory is preserved > + // across reboots, this allows the NV variable storage to survive > + // a VM reboot. > + // > + VariableStore = > + (EFI_PHYSICAL_ADDRESS)(UINTN) > + AllocateRuntimePages ( > + EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) > + ); > + DEBUG ((DEBUG_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 ((DEBUG_INFO, "CMOS:\n")); > + > + for (Loop = 0; Loop < 0x80; Loop++) { > + if ((Loop % 0x10) == 0) { > + DEBUG ((DEBUG_INFO, "%02x:", Loop)); > + } > + DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop))); > + if ((Loop % 0x10) == 0xf) { > + DEBUG ((DEBUG_INFO, "\n")); > + } > + } > +} > + > + > +VOID > +S3Verification ( > + VOID > + ) > +{ > +#if defined (MDE_CPU_X64) > + if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) { > + DEBUG ((DEBUG_ERROR, > + "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n", __FUNCTION__)); > + DEBUG ((DEBUG_ERROR, > + "%a: Please disable S3 on the QEMU command line (see the README),\n", > + __FUNCTION__)); > + DEBUG ((DEBUG_ERROR, > + "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n", __FUNCTION__)); > + ASSERT (FALSE); > + CpuDeadLoop (); > + } > +#endif > +} > + > + > +/** > + Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modules. > + Set the mMaxCpuCount variable. > +**/ > +VOID > +MaxCpuCountInitialization ( > + VOID > + ) > +{ > + UINT16 ProcessorCount = 0; > + RETURN_STATUS PcdStatus; > + > + // > + // If the fw_cfg key or fw_cfg entirely is unavailable, load mMaxCpuCount > + // from the PCD default. No change to PCDs. > + // > + if (ProcessorCount == 0) { > + mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber); > + return; > + } > + // > + // Otherwise, set mMaxCpuCount to the value reported by QEMU. > + // > + mMaxCpuCount = ProcessorCount; > + // > + // Additionally, tell UefiCpuPkg modules (a) the exact number of VCPUs, (b) > + // to wait, in the initial AP bringup, exactly as long as it takes for all of > + // the APs to report in. For this, we set the longest representable timeout > + // (approx. 71 minutes). > + // > + PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, ProcessorCount); > + ASSERT_RETURN_ERROR (PcdStatus); > + PcdStatus = PcdSet32S (PcdCpuApInitTimeOutInMicroSeconds, MAX_UINT32); > + ASSERT_RETURN_ERROR (PcdStatus); > + DEBUG ((DEBUG_INFO, "%a: QEMU reports %d processor(s)\n", __FUNCTION__, > + ProcessorCount)); > +} > + > + > +/** > + 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 > +InitializePlatform ( > + IN EFI_PEI_FILE_HANDLE FileHandle, > + IN CONST EFI_PEI_SERVICES **PeiServices > + ) > +{ > + DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n")); > + > + // > + // Initialize Local APIC Timer hardware and disable Local APIC Timer > + // interrupts before initializing the Debug Agent and the debug timer is > + // enabled. > + // > + InitializeApicTimer (0, MAX_UINT32, TRUE, 5); > + DisableApicTimerInterrupt (); > + > + DebugDumpCmos (); > + > + BootModeInitialization (); > + AddressWidthInitialization (); > + MaxCpuCountInitialization (); > + > + // > + // Query Host Bridge DID > + // > + mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); > + > + if (FeaturePcdGet (PcdSmmSmramRequire)) { > + Q35TsegMbytesInitialization (); > + } > + > + PublishPeiMemory (); > + > + InitializeRamRegions (); > + > + if (mBootMode != BOOT_ON_S3_RESUME) { > + if (!FeaturePcdGet (PcdSmmSmramRequire)) { > + ReserveEmuVariableNvStore (); > + } > + PeiFvInitialization (); > + MemMapInitialization (); > + NoexecDxeInitialization (); > + } > + > + InstallClearCacheCallback (); > + AmdSevInitialize (); > + MiscInitialization (); > + InstallFeatureControlCallback (); > + > + return EFI_SUCCESS; > +} > diff --git a/BhyvePkg/PlatformPei/Platform.h b/BhyvePkg/PlatformPei/Platform.h > new file mode 100644 > index 0000000000..0484ec9e6b > --- /dev/null > +++ b/BhyvePkg/PlatformPei/Platform.h > @@ -0,0 +1,136 @@ > +/** @file > + Platform PEI module include file. > + > + Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#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 > + ); > + > +VOID > +Q35TsegMbytesInitialization ( > + VOID > + ); > + > +VOID > +Q35SmramAtDefaultSmbaseInitialization ( > + VOID > + ); > + > +EFI_STATUS > +PublishPeiMemory ( > + VOID > + ); > + > +UINT32 > +GetSystemMemorySizeBelow4gb ( > + VOID > + ); > + > +VOID > +QemuUc32BaseInitialization ( > + VOID > + ); > + > +VOID > +InitializeRamRegions ( > + VOID > + ); > + > +EFI_STATUS > +PeiFvInitialization ( > + VOID > + ); > + > +VOID > +MemTypeInfoInitialization ( > + VOID > + ); > + > +VOID > +InstallFeatureControlCallback ( > + VOID > + ); > + > +VOID > +InstallClearCacheCallback ( > + VOID > + ); > + > +EFI_STATUS > +InitializeXen ( > + VOID > + ); > + > +BOOLEAN > +XenDetect ( > + VOID > + ); > + > +VOID > +AmdSevInitialize ( > + VOID > + ); > + > +extern BOOLEAN mXen; > + > +VOID > +XenPublishRamRegions ( > + VOID > + ); > + > +extern EFI_BOOT_MODE mBootMode; > + > +extern BOOLEAN mS3Supported; > + > +extern UINT8 mPhysMemAddressWidth; > + > +extern UINT32 mMaxCpuCount; > + > +extern UINT16 mHostBridgeDevId; > + > +extern BOOLEAN mQ35SmramAtDefaultSmbase; > + > +extern UINT32 mQemuUc32Base; > + > +#endif // _PLATFORM_PEI_H_INCLUDED_ > diff --git a/BhyvePkg/PlatformPei/PlatformPei.inf b/BhyvePkg/PlatformPei/PlatformPei.inf > new file mode 100644 > index 0000000000..137c69a97d > --- /dev/null > +++ b/BhyvePkg/PlatformPei/PlatformPei.inf > @@ -0,0 +1,117 @@ > +## @file > +# Platform PEI driver > +# > +# This module provides platform specific function to detect boot mode. > +# Copyright (c) 2006 - 2018, 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 = PlatformPei > + FILE_GUID = aa89d903-345b-4ab2-9abf-030b5efb5d50 > + MODULE_TYPE = PEIM > + VERSION_STRING = 1.0 > + ENTRY_POINT = InitializePlatform > + > +# > +# The following information is for reference only and not required by the build tools. > +# > +# VALID_ARCHITECTURES = IA32 X64 EBC > +# > + > +[Sources] > + AmdSev.c > + ClearCache.c > + Cmos.c > + Cmos.h > + FeatureControl.c > + Fv.c > + MemDetect.c > + Platform.c > + Platform.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + SecurityPkg/SecurityPkg.dec > + UefiCpuPkg/UefiCpuPkg.dec > + OvmfPkg/OvmfPkg.dec > + > +[Guids] > + gEfiMemoryTypeInformationGuid > + > +[LibraryClasses] > + BaseLib > + CacheMaintenanceLib > + DebugLib > + HobLib > + IoLib > + PciLib > + ResourcePublicationLib > + PeiServicesLib > + PeiServicesTablePointerLib > + PeimEntryPoint > + MtrrLib > + MemEncryptSevLib > + PcdLib > + LocalApicLib > + > +[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.PcdFlashNvStorageFtwSpareSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved > + gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration > + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode > + gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable > + gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack > + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable > + gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask > + gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy > + gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress > + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber > + gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds > + gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize > + > +[FixedPcd] > + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress > + > +[FeaturePcd] > + gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire > + > +[Ppis] > + gEfiPeiMasterBootModePpiGuid > + gEfiPeiMpServicesPpiGuid > + > +[Depex] > + TRUE > + >