From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232]) by mx.groups.io with SMTP id smtpd.web10.2770.1587752976476779841 for ; Fri, 24 Apr 2020 11:29:36 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: bsdio.com, ip: 166.70.13.232, mailfrom: rebecca@bsdio.com) Received: from in01.mta.xmission.com ([166.70.13.51]) by out02.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jS34x-00037t-DI; Fri, 24 Apr 2020 12:29:35 -0600 Received: from mta5.zcs.xmission.com ([166.70.13.69]) by in01.mta.xmission.com with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.87) (envelope-from ) id 1jS34t-0002lS-Q8; Fri, 24 Apr 2020 12:29:34 -0600 Received: from localhost (localhost [127.0.0.1]) by mta5.zcs.xmission.com (Postfix) with ESMTP id 9A4541280687; Fri, 24 Apr 2020 12:29:31 -0600 (MDT) X-Amavis-Modified: Mail body modified (using disclaimer) - mta5.zcs.xmission.com Received: from mta5.zcs.xmission.com ([127.0.0.1]) by localhost (mta5.zcs.xmission.com [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id Qsqj6L2LyJPr; Fri, 24 Apr 2020 12:29:31 -0600 (MDT) Received: from photon.int.bluestop.org (c-174-52-16-57.hsd1.ut.comcast.net [174.52.16.57]) by mta5.zcs.xmission.com (Postfix) with ESMTPSA id 4415B1280681; Fri, 24 Apr 2020 12:29:31 -0600 (MDT) From: "Rebecca Cran" To: devel@edk2.groups.io, Jordan Justen , Laszlo Ersek , Ard Biesheuvel , Andrew Fish , Leif Lindholm , Michael D Kinney Cc: Rebecca Cran Date: Fri, 24 Apr 2020 12:29:13 -0600 Message-Id: <20200424182914.138915-6-rebecca@bsdio.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200424182914.138915-1-rebecca@bsdio.com> References: <20200424182914.138915-1-rebecca@bsdio.com> MIME-Version: 1.0 X-XM-SPF: eid=1jS34t-0002lS-Q8;;;mid=<20200424182914.138915-6-rebecca@bsdio.com>;;;hst=in01.mta.xmission.com;;;ip=166.70.13.69;;;frm=rebecca@bsdio.com;;;spf=pass X-SA-Exim-Connect-IP: 166.70.13.69 X-SA-Exim-Mail-From: rebecca@bsdio.com X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on sa07.xmission.com X-Spam-Level: **** X-Spam-Status: No, score=4.8 required=8.0 tests=ALL_TRUSTED,BAYES_50, DCC_CHECK_NEGATIVE,TM2_M_VERY_LONG_WORD,TooManyTo_001,TooManyTo_002, TooManyTo_003,TooManyTo_004,TooManyTo_005,XMBrknScrpt_02,XMLngstWrd_00, XM_Doc_Oz_Body autolearn=disabled version=3.4.2 X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.8 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.5000] * 0.5 TooManyTo_002 Multiple "To" Header Recipients 3x (uncommon) * 0.4 TooManyTo_005 Multiple "To" Header Recipients 6x (uncommon) * 0.3 TooManyTo_001 Multiple "To" Header Recipients 2x (uncommon) * 0.6 TooManyTo_003 Multiple "To" Header Recipients 4x (uncommon) * 0.5 TooManyTo_004 Multiple "To" Header Recipients 5x (uncommon) * 1.0 TM2_M_VERY_LONG_WORD BODY: Very long word (longer than 40 * chars) * 1.0 XM_Doc_Oz_Body BODY: Dr. Oz body dropper * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa07 1397; IP=ok Body=1 Fuz1=1] [Fuz2=1] * 0.4 XMBrknScrpt_02 Possible Broken Spam Script * 0.2 XMLngstWrd_00 words over 45 charachters don't exist X-Spam-DCC: XMission; sa07 1397; IP=ok Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: ****;devel@edk2.groups.io, Jordan Justen , Laszlo Ersek , Ard Biesheuvel , Andrew Fish , Leif Lindholm , Michael D Kinney X-Spam-Relay-Country: X-Spam-Timing: total 2924 ms - load_scoreonly_sql: 0.03 (0.0%), signal_user_changed: 11 (0.4%), b_tie_ro: 9 (0.3%), parse: 4.4 (0.2%), extract_message_metadata: 43 (1.5%), get_uri_detail_list: 23 (0.8%), tests_pri_-1000: 17 (0.6%), tests_pri_-950: 1.35 (0.0%), tests_pri_-900: 1.08 (0.0%), tests_pri_-90: 376 (12.9%), check_bayes: 359 (12.3%), b_tokenize: 87 (3.0%), b_tok_get_all: 63 (2.2%), b_comp_prob: 10 (0.3%), b_tok_touch_all: 192 (6.6%), b_finish: 0.88 (0.0%), tests_pri_0: 2448 (83.7%), check_dkim_signature: 2.1 (0.1%), check_dkim_adsp: 2.5 (0.1%), poll_dns_idle: 0.54 (0.0%), tests_pri_10: 2.4 (0.1%), tests_pri_500: 12 (0.4%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH v4 5/6] BhyvePkg: Add PlatformPei X-Spam-Flag: No X-SA-Exim-Version: 4.2.1 (built Thu, 05 May 2016 13:38:54 -0600) X-SA-Exim-Scanned: Yes (on in01.mta.xmission.com) Content-Transfer-Encoding: quoted-printable 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/License.txt | 4 + BhyvePkg/PlatformPei/AmdSev.c | 106 +++++ BhyvePkg/PlatformPei/ClearCache.c | 111 +++++ BhyvePkg/PlatformPei/Cmos.c | 58 +++ BhyvePkg/PlatformPei/Cmos.h | 50 ++ BhyvePkg/PlatformPei/FeatureControl.c | 21 + BhyvePkg/PlatformPei/Fv.c | 94 ++++ BhyvePkg/PlatformPei/MemDetect.c | 627 ++++++++++++++++++++++++++ BhyvePkg/PlatformPei/Platform.c | 607 +++++++++++++++++++++++++ BhyvePkg/PlatformPei/Platform.h | 137 ++++++ BhyvePkg/PlatformPei/PlatformPei.inf | 113 +++++ 11 files changed, 1928 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 diff --git a/BhyvePkg/License.txt b/BhyvePkg/License.txt index cf41faacbf..2930e5372a 100644 --- a/BhyvePkg/License.txt +++ b/BhyvePkg/License.txt @@ -1,5 +1,8 @@ Copyright (c) 2020, Rebecca Cran =0D Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
=0D +Copyright (C) 2018, Red Hat, Inc.=0D +Copyright (c) 2017, Advanced Micro Devices. All rights reserved.
=0D +Copyright (C) 2016, Red Hat, Inc.=0D (C) Copyright 2016 Hewlett Packard Enterprise Development LP
=0D Copyright (c) 2015 Nahanni Systems=0D Copyright (C) 2015, Red Hat, Inc.=0D @@ -8,6 +11,7 @@ Copyright (c) 2014, Pluribus Networks, Inc. Copyright (C) 2013, Red Hat, Inc.=0D Copyright (c) 2012, 2013, Red Hat, Inc.=0D Copyright (c) 2011, Bei Guan =0D +Copyright (c) 2011, Andrei Warkentin =0D Portions copyright (c) 2011, Apple Inc. All rights reserved.=0D Portions copyright (c) 2010,Apple Inc. All rights reserved.
=0D =0D 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=0D + Initialize Secure Encrypted Virtualization (SEV) support=0D +=0D + Copyright (c) 2017, Advanced Micro Devices. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +//=0D +// The package level header files this module uses=0D +//=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "Platform.h"=0D +=0D +/**=0D +=0D + Function checks if SEV support is available, if present then it sets=0D + the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption m= ask.=0D +=0D + **/=0D +VOID=0D +AmdSevInitialize (=0D + VOID=0D + )=0D +{=0D + CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx;=0D + UINT64 EncryptionMask;=0D + RETURN_STATUS PcdStatus;=0D +=0D + //=0D + // Check if SEV is enabled=0D + //=0D + if (!MemEncryptSevIsEnabled ()) {=0D + return;=0D + }=0D +=0D + //=0D + // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position)=0D + //=0D + AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL);= =0D + EncryptionMask =3D LShiftU64 (1, Ebx.Bits.PtePosBits);=0D +=0D + //=0D + // Set Memory Encryption Mask PCD=0D + //=0D + PcdStatus =3D PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, Encryption= Mask);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +=0D + DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));=0D +=0D + //=0D + // Set Pcd to Deny the execution of option ROM when security=0D + // violation.=0D + //=0D + PcdStatus =3D PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +=0D + //=0D + // When SMM is required, cover the pages containing the initial SMRAM Sa= ve=0D + // State Map with a memory allocation HOB:=0D + //=0D + // There's going to be a time interval between our decrypting those page= s for=0D + // SMBASE relocation and re-encrypting the same pages after SMBASE=0D + // relocation. We shall ensure that the DXE phase stay away from those p= ages=0D + // until after re-encryption, in order to prevent an information leak to= the=0D + // hypervisor.=0D + //=0D + if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode !=3D BOOT_ON_S3_RES= UME)) {=0D + RETURN_STATUS LocateMapStatus;=0D + UINTN MapPagesBase;=0D + UINTN MapPagesCount;=0D +=0D + LocateMapStatus =3D MemEncryptSevLocateInitialSmramSaveStateMapPages (= =0D + &MapPagesBase,=0D + &MapPagesCount=0D + );=0D + ASSERT_RETURN_ERROR (LocateMapStatus);=0D +=0D + if (mQ35SmramAtDefaultSmbase) {=0D + //=0D + // The initial SMRAM Save State Map has been covered as part of a la= rger=0D + // reserved memory allocation in InitializeRamRegions().=0D + //=0D + ASSERT (SMM_DEFAULT_SMBASE <=3D MapPagesBase);=0D + ASSERT (=0D + (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=3D=0D + SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)=0D + );=0D + } else {=0D + BuildMemoryAllocationHob (=0D + MapPagesBase, // BaseAddress=0D + EFI_PAGES_TO_SIZE (MapPagesCount), // Length=0D + EfiBootServicesData // MemoryType=0D + );=0D + }=0D + }=0D +}=0D diff --git a/BhyvePkg/PlatformPei/ClearCache.c b/BhyvePkg/PlatformPei/Clear= Cache.c new file mode 100644 index 0000000000..5c538c59e0 --- /dev/null +++ b/BhyvePkg/PlatformPei/ClearCache.c @@ -0,0 +1,111 @@ +/**@file=0D + Install a callback to clear cache on all processors.=0D + This is for conformance with the TCG "Platform Reset Attack Mitigation=0D + Specification". Because clearing the CPU caches at boot doesn't impact=0D + performance significantly, do it unconditionally, for simplicity's=0D + sake.=0D +=0D + Copyright (C) 2018, Red Hat, Inc.=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "Platform.h"=0D +=0D +/**=0D + Invalidate data & instruction caches.=0D + All APs execute this function in parallel. The BSP executes the function= =0D + separately.=0D +=0D + @param[in,out] WorkSpace Pointer to the input/output argument workspace= =0D + shared by all processors.=0D +**/=0D +STATIC=0D +VOID=0D +EFIAPI=0D +ClearCache (=0D + IN OUT VOID *WorkSpace=0D + )=0D +{=0D + WriteBackInvalidateDataCache ();=0D + InvalidateInstructionCache ();=0D +}=0D +=0D +/**=0D + Notification function called when EFI_PEI_MP_SERVICES_PPI becomes availa= ble.=0D +=0D + @param[in] PeiServices Indirect reference to the PEI Services Table= .=0D + @param[in] NotifyDescriptor Address of the notification descriptor data= =0D + structure.=0D + @param[in] Ppi Address of the PPI that was installed.=0D +=0D + @return Status of the notification. The status code returned from this= =0D + function is ignored.=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +EFIAPI=0D +ClearCacheOnMpServicesAvailable (=0D + IN EFI_PEI_SERVICES **PeiServices,=0D + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,=0D + IN VOID *Ppi=0D + )=0D +{=0D + EFI_PEI_MP_SERVICES_PPI *MpServices;=0D + EFI_STATUS Status;=0D +=0D + DEBUG ((DEBUG_INFO, "%a: %a\n", gEfiCallerBaseName, __FUNCTION__));=0D +=0D + //=0D + // Clear cache on all the APs in parallel.=0D + //=0D + MpServices =3D Ppi;=0D + Status =3D MpServices->StartupAllAPs (=0D + (CONST EFI_PEI_SERVICES **)PeiServices,=0D + MpServices,=0D + ClearCache, // Procedure=0D + FALSE, // SingleThread=0D + 0, // TimeoutInMicroSeconds: in= f.=0D + NULL // ProcedureArgument=0D + );=0D + if (EFI_ERROR (Status) && Status !=3D EFI_NOT_STARTED) {=0D + DEBUG ((DEBUG_ERROR, "%a: StartupAllAps(): %r\n", __FUNCTION__, Status= ));=0D + return Status;=0D + }=0D +=0D + //=0D + // Now clear cache on the BSP too.=0D + //=0D + ClearCache (NULL);=0D + return EFI_SUCCESS;=0D +}=0D +=0D +//=0D +// Notification object for registering the callback, for when=0D +// EFI_PEI_MP_SERVICES_PPI becomes available.=0D +//=0D +STATIC CONST EFI_PEI_NOTIFY_DESCRIPTOR mMpServicesNotify =3D {=0D + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | // Flags=0D + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,=0D + &gEfiPeiMpServicesPpiGuid, // Guid=0D + ClearCacheOnMpServicesAvailable // Notify=0D +};=0D +=0D +VOID=0D +InstallClearCacheCallback (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D PeiServicesNotifyPpi (&mMpServicesNotify);=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "%a: failed to set up MP Services callback: %r\n"= ,=0D + __FUNCTION__, Status));=0D + }=0D +}=0D 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=0D + PC/AT CMOS access routines=0D +=0D + Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +=0D +#include "Cmos.h"=0D +#include "Library/IoLib.h"=0D +=0D +/**=0D + Reads 8-bits of CMOS data.=0D +=0D + Reads the 8-bits of CMOS data at the location specified by Index.=0D + The 8-bit read value is returned.=0D +=0D + @param Index The CMOS location to read.=0D +=0D + @return The value read.=0D +=0D +**/=0D +UINT8=0D +EFIAPI=0D +CmosRead8 (=0D + IN UINTN Index=0D + )=0D +{=0D + IoWrite8 (0x70, (UINT8) Index);=0D + return IoRead8 (0x71);=0D +}=0D +=0D +=0D +/**=0D + Writes 8-bits of CMOS data.=0D +=0D + Writes 8-bits of CMOS data to the location specified by Index=0D + with the value specified by Value and returns Value.=0D +=0D + @param Index The CMOS location to write.=0D + @param Value The value to write to CMOS.=0D +=0D + @return The value written to CMOS.=0D +=0D +**/=0D +UINT8=0D +EFIAPI=0D +CmosWrite8 (=0D + IN UINTN Index,=0D + IN UINT8 Value=0D + )=0D +{=0D + IoWrite8 (0x70, (UINT8) Index);=0D + IoWrite8 (0x71, Value);=0D + return Value;=0D +}=0D +=0D 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=0D + PC/AT CMOS access routines=0D +=0D + Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef __CMOS_H__=0D +#define __CMOS_H__=0D +=0D +/**=0D + Reads 8-bits of CMOS data.=0D +=0D + Reads the 8-bits of CMOS data at the location specified by Index.=0D + The 8-bit read value is returned.=0D +=0D + @param Index The CMOS location to read.=0D +=0D + @return The value read.=0D +=0D +**/=0D +UINT8=0D +EFIAPI=0D +CmosRead8 (=0D + IN UINTN Index=0D + );=0D +=0D +/**=0D + Writes 8-bits of CMOS data.=0D +=0D + Writes 8-bits of CMOS data to the location specified by Index=0D + with the value specified by Value and returns Value.=0D +=0D + @param Index The CMOS location to write.=0D + @param Value The value to write to CMOS.=0D +=0D + @return The value written to CMOS.=0D +=0D +**/=0D +UINT8=0D +EFIAPI=0D +CmosWrite8 (=0D + IN UINTN Index,=0D + IN UINT8 Value=0D + );=0D +=0D +=0D +#endif=0D +=0D diff --git a/BhyvePkg/PlatformPei/FeatureControl.c b/BhyvePkg/PlatformPei/F= eatureControl.c new file mode 100644 index 0000000000..40d9ebdbe6 --- /dev/null +++ b/BhyvePkg/PlatformPei/FeatureControl.c @@ -0,0 +1,21 @@ +/**@file=0D + Install a callback when necessary for setting the Feature Control MSR on= all=0D + processors.=0D +=0D + Copyright (C) 2020, Rebecca Cran =0D + Copyright (C) 2016, Red Hat, Inc.=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include "Platform.h"=0D +=0D +VOID=0D +InstallFeatureControlCallback (=0D + VOID=0D + )=0D +{=0D + //=0D + // Nothing to do.=0D + //=0D +}=0D 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=0D + Build FV related hobs for platform.=0D +=0D + Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include "PiPei.h"=0D +#include "Platform.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +=0D +/**=0D + Publish PEI & DXE (Decompressed) Memory based FVs to let PEI=0D + and DXE know about them.=0D +=0D + @retval EFI_SUCCESS Platform PEI FVs were initialized successfully.=0D +=0D +**/=0D +EFI_STATUS=0D +PeiFvInitialization (=0D + VOID=0D + )=0D +{=0D + BOOLEAN SecureS3Needed;=0D +=0D + DEBUG ((DEBUG_INFO, "Platform PEI Firmware Volume Initialization\n"));=0D +=0D + //=0D + // Create a memory allocation HOB for the PEI FV.=0D + //=0D + // Allocate as ACPI NVS is S3 is supported=0D + //=0D + BuildMemoryAllocationHob (=0D + PcdGet32 (PcdOvmfPeiMemFvBase),=0D + PcdGet32 (PcdOvmfPeiMemFvSize),=0D + mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData=0D + );=0D +=0D + //=0D + // Let DXE know about the DXE FV=0D + //=0D + BuildFvHob (PcdGet32 (PcdOvmfDxeMemFvBase), PcdGet32 (PcdOvmfDxeMemFvSiz= e));=0D +=0D + SecureS3Needed =3D mS3Supported && FeaturePcdGet (PcdSmmSmramRequire);=0D +=0D + //=0D + // Create a memory allocation HOB for the DXE FV.=0D + //=0D + // If "secure" S3 is needed, then SEC will decompress both PEI and DXE=0D + // firmware volumes at S3 resume too, hence we need to keep away the OS = from=0D + // DXEFV as well. Otherwise we only need to keep away DXE itself from th= e=0D + // DXEFV area.=0D + //=0D + BuildMemoryAllocationHob (=0D + PcdGet32 (PcdOvmfDxeMemFvBase),=0D + PcdGet32 (PcdOvmfDxeMemFvSize),=0D + SecureS3Needed ? EfiACPIMemoryNVS : EfiBootServicesData=0D + );=0D +=0D + //=0D + // Additionally, said decompression will use temporary memory above the = end=0D + // of DXEFV, so let's keep away the OS from there too.=0D + //=0D + if (SecureS3Needed) {=0D + UINT32 DxeMemFvEnd;=0D +=0D + DxeMemFvEnd =3D PcdGet32 (PcdOvmfDxeMemFvBase) +=0D + PcdGet32 (PcdOvmfDxeMemFvSize);=0D + BuildMemoryAllocationHob (=0D + DxeMemFvEnd,=0D + PcdGet32 (PcdOvmfDecompressionScratchEnd) - DxeMemFvEnd,=0D + EfiACPIMemoryNVS=0D + );=0D + }=0D +=0D + //=0D + // Let PEI know about the DXE FV so it can find the DXE Core=0D + //=0D + PeiServicesInstallFvInfoPpi (=0D + NULL,=0D + (VOID *)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase),=0D + PcdGet32 (PcdOvmfDxeMemFvSize),=0D + NULL,=0D + NULL=0D + );=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D diff --git a/BhyvePkg/PlatformPei/MemDetect.c b/BhyvePkg/PlatformPei/MemDet= ect.c new file mode 100644 index 0000000000..1b556be69c --- /dev/null +++ b/BhyvePkg/PlatformPei/MemDetect.c @@ -0,0 +1,627 @@ +/**@file=0D + Memory Detection for Virtual Machines.=0D +=0D + Copyright (c) 2020, Rebecca Cran =0D + Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +Module Name:=0D +=0D + MemDetect.c=0D +=0D +**/=0D +=0D +//=0D +// The package level header files this module uses=0D +//=0D +#include =0D +#include =0D +#include =0D +=0D +//=0D +// The Library classes this module consumes=0D +//=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "Platform.h"=0D +#include "Cmos.h"=0D +=0D +UINT8 mPhysMemAddressWidth;=0D +=0D +STATIC UINT32 mS3AcpiReservedMemoryBase;=0D +STATIC UINT32 mS3AcpiReservedMemorySize;=0D +=0D +STATIC UINT16 mQ35TsegMbytes;=0D +=0D +BOOLEAN mQ35SmramAtDefaultSmbase =3D FALSE;=0D +=0D +VOID=0D +Q35TsegMbytesInitialization (=0D + VOID=0D + )=0D +{=0D + UINT16 ExtendedTsegMbytes;=0D + RETURN_STATUS PcdStatus;=0D +=0D + if (mHostBridgeDevId !=3D INTEL_Q35_MCH_DEVICE_ID) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "%a: no TSEG (SMRAM) on host bridge DID=3D0x%04x; "=0D + "only DID=3D0x%04x (Q35) is supported\n",=0D + __FUNCTION__,=0D + mHostBridgeDevId,=0D + INTEL_Q35_MCH_DEVICE_ID=0D + ));=0D + ASSERT (FALSE);=0D + CpuDeadLoop ();=0D + }=0D +=0D + //=0D + // Check if QEMU offers an extended TSEG.=0D + //=0D + // This can be seen from writing MCH_EXT_TSEG_MB_QUERY to the MCH_EXT_TS= EG_MB=0D + // register, and reading back the register.=0D + //=0D + // On a QEMU machine type that does not offer an extended TSEG, the init= ial=0D + // write overwrites whatever value a malicious guest OS may have placed = in=0D + // the (unimplemented) register, before entering S3 or rebooting.=0D + // Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.=0D + //=0D + // On a QEMU machine type that offers an extended TSEG, the initial writ= e=0D + // triggers an update to the register. Subsequently, the value read back= =0D + // (which is guaranteed to differ from MCH_EXT_TSEG_MB_QUERY) tells us t= he=0D + // number of megabytes.=0D + //=0D + PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY)= ;=0D + ExtendedTsegMbytes =3D PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB));= =0D + if (ExtendedTsegMbytes =3D=3D MCH_EXT_TSEG_MB_QUERY) {=0D + mQ35TsegMbytes =3D PcdGet16 (PcdQ35TsegMbytes);=0D + return;=0D + }=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "%a: QEMU offers an extended TSEG (%d MB)\n",=0D + __FUNCTION__,=0D + ExtendedTsegMbytes=0D + ));=0D + PcdStatus =3D PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + mQ35TsegMbytes =3D ExtendedTsegMbytes;=0D +}=0D +=0D +=0D +UINT32=0D +GetSystemMemorySizeBelow4gb (=0D + VOID=0D + )=0D +{=0D + UINT8 Cmos0x34;=0D + UINT8 Cmos0x35;=0D +=0D + //=0D + // CMOS 0x34/0x35 specifies the system memory above 16 MB.=0D + // * CMOS(0x35) is the high byte=0D + // * CMOS(0x34) is the low byte=0D + // * The size is specified in 64kb chunks=0D + // * Since this is memory above 16MB, the 16MB must be added=0D + // into the calculation to get the total memory size.=0D + //=0D +=0D + Cmos0x34 =3D (UINT8) CmosRead8 (0x34);=0D + Cmos0x35 =3D (UINT8) CmosRead8 (0x35);=0D +=0D + return (UINT32) (((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB= );=0D +}=0D +=0D +=0D +STATIC=0D +UINT64=0D +GetSystemMemorySizeAbove4gb (=0D + )=0D +{=0D + UINT32 Size;=0D + UINTN CmosIndex;=0D +=0D + //=0D + // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.=0D + // * CMOS(0x5d) is the most significant size byte=0D + // * CMOS(0x5c) is the middle size byte=0D + // * CMOS(0x5b) is the least significant size byte=0D + // * The size is specified in 64kb chunks=0D + //=0D +=0D + Size =3D 0;=0D + for (CmosIndex =3D 0x5d; CmosIndex >=3D 0x5b; CmosIndex--) {=0D + Size =3D (UINT32) (Size << 8) + (UINT32) CmosRead8 (CmosIndex);=0D + }=0D +=0D + return LShiftU64 (Size, 16);=0D +}=0D +=0D +=0D +/**=0D + Return the highest address that DXE could possibly use, plus one.=0D +**/=0D +STATIC=0D +UINT64=0D +GetFirstNonAddress (=0D + VOID=0D + )=0D +{=0D + UINT64 FirstNonAddress;=0D + UINT64 Pci64Base, Pci64Size;=0D + RETURN_STATUS PcdStatus;=0D +=0D + FirstNonAddress =3D BASE_4GB + GetSystemMemorySizeAbove4gb ();=0D +=0D + //=0D + // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO= =0D + // resources to 32-bit anyway. See DegradeResource() in=0D + // "PciResourceSupport.c".=0D + //=0D +#ifdef MDE_CPU_IA32=0D + if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {=0D + return FirstNonAddress;=0D + }=0D +#endif=0D +=0D + //=0D + // Otherwise, in order to calculate the highest address plus one, we mus= t=0D + // consider the 64-bit PCI host aperture too. Fetch the default size.=0D + //=0D + Pci64Size =3D PcdGet64 (PcdPciMmio64Size);=0D +=0D + if (Pci64Size =3D=3D 0) {=0D + if (mBootMode !=3D BOOT_ON_S3_RESUME) {=0D + DEBUG ((DEBUG_INFO, "%a: disabling 64-bit PCI host aperture\n",=0D + __FUNCTION__));=0D + PcdStatus =3D PcdSet64S (PcdPciMmio64Size, 0);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + }=0D +=0D + //=0D + // There's nothing more to do; the amount of memory above 4GB fully=0D + // determines the highest address plus one. The memory hotplug area (s= ee=0D + // below) plays no role for the firmware in this case.=0D + //=0D + return FirstNonAddress;=0D + }=0D +=0D + //=0D + // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB= , so=0D + // that the host can map it with 1GB hugepages. Follow suit.=0D + //=0D + Pci64Base =3D ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);=0D + Pci64Size =3D ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);=0D +=0D + //=0D + // The 64-bit PCI host aperture should also be "naturally" aligned. The= =0D + // alignment is determined by rounding the size of the aperture down to = the=0D + // next smaller or equal power of two. That is, align the aperture by th= e=0D + // largest BAR size that can fit into it.=0D + //=0D + Pci64Base =3D ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));=0D +=0D + if (mBootMode !=3D BOOT_ON_S3_RESUME) {=0D + //=0D + // The core PciHostBridgeDxe driver will automatically add this range = to=0D + // the GCD memory space map through our PciHostBridgeLib instance; her= e we=0D + // only need to set the PCDs.=0D + //=0D + PcdStatus =3D PcdSet64S (PcdPciMmio64Base, Pci64Base);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + PcdStatus =3D PcdSet64S (PcdPciMmio64Size, Pci64Size);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +=0D + DEBUG ((DEBUG_INFO, "%a: Pci64Base=3D0x%Lx Pci64Size=3D0x%Lx\n",=0D + __FUNCTION__, Pci64Base, Pci64Size));=0D + }=0D +=0D + //=0D + // The useful address space ends with the 64-bit PCI host aperture.=0D + //=0D + FirstNonAddress =3D Pci64Base + Pci64Size;=0D + return FirstNonAddress;=0D +}=0D +=0D +=0D +/**=0D + Initialize the mPhysMemAddressWidth variable, based on guest RAM size.=0D +**/=0D +VOID=0D +AddressWidthInitialization (=0D + VOID=0D + )=0D +{=0D + UINT64 FirstNonAddress;=0D +=0D + //=0D + // As guest-physical memory size grows, the permanent PEI RAM requiremen= ts=0D + // are dominated by the identity-mapping page tables built by the DXE IP= L.=0D + // The DXL IPL keys off of the physical address bits advertized in the C= PU=0D + // HOB. To conserve memory, we calculate the minimum address width here.= =0D + //=0D + FirstNonAddress =3D GetFirstNonAddress ();=0D + mPhysMemAddressWidth =3D (UINT8)HighBitSet64 (FirstNonAddress);=0D +=0D + //=0D + // If FirstNonAddress is not an integral power of two, then we need an=0D + // additional bit.=0D + //=0D + if ((FirstNonAddress & (FirstNonAddress - 1)) !=3D 0) {=0D + ++mPhysMemAddressWidth;=0D + }=0D +=0D + //=0D + // The minimum address width is 36 (covers up to and excluding 64 GB, wh= ich=0D + // is the maximum for Ia32 + PAE). The theoretical architecture maximum = for=0D + // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits= . We=0D + // can simply assert that here, since 48 bits are good enough for 256 TB= .=0D + //=0D + if (mPhysMemAddressWidth <=3D 36) {=0D + mPhysMemAddressWidth =3D 36;=0D + }=0D + ASSERT (mPhysMemAddressWidth <=3D 48);=0D +}=0D +=0D +=0D +/**=0D + Calculate the cap for the permanent PEI memory.=0D +**/=0D +STATIC=0D +UINT32=0D +GetPeiMemoryCap (=0D + VOID=0D + )=0D +{=0D + BOOLEAN Page1GSupport;=0D + UINT32 RegEax;=0D + UINT32 RegEdx;=0D + UINT32 Pml4Entries;=0D + UINT32 PdpEntries;=0D + UINTN TotalPages;=0D +=0D + //=0D + // If DXE is 32-bit, then just return the traditional 64 MB cap.=0D + //=0D +#ifdef MDE_CPU_IA32=0D + if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {=0D + return SIZE_64MB;=0D + }=0D +#endif=0D +=0D + //=0D + // Dependent on physical address width, PEI memory allocations can be=0D + // dominated by the page tables built for 64-bit DXE. So we key the cap = off=0D + // of those. The code below is based on CreateIdentityMappingPageTables(= ) in=0D + // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".=0D + //=0D + Page1GSupport =3D FALSE;=0D + if (PcdGetBool (PcdUse1GPageTable)) {=0D + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);=0D + if (RegEax >=3D 0x80000001) {=0D + AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);=0D + if ((RegEdx & BIT26) !=3D 0) {=0D + Page1GSupport =3D TRUE;=0D + }=0D + }=0D + }=0D +=0D + if (mPhysMemAddressWidth <=3D 39) {=0D + Pml4Entries =3D 1;=0D + PdpEntries =3D 1 << (mPhysMemAddressWidth - 30);=0D + ASSERT (PdpEntries <=3D 0x200);=0D + } else {=0D + Pml4Entries =3D 1 << (mPhysMemAddressWidth - 39);=0D + ASSERT (Pml4Entries <=3D 0x200);=0D + PdpEntries =3D 512;=0D + }=0D +=0D + TotalPages =3D Page1GSupport ? Pml4Entries + 1 :=0D + (PdpEntries + 1) * Pml4Entries + 1;=0D + ASSERT (TotalPages <=3D 0x40201);=0D +=0D + //=0D + // Add 64 MB for miscellaneous allocations. Note that for=0D + // mPhysMemAddressWidth values close to 36, the cap will actually be=0D + // dominated by this increment.=0D + //=0D + return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);=0D +}=0D +=0D +=0D +/**=0D + Publish PEI core memory=0D +=0D + @return EFI_SUCCESS The PEIM initialized successfully.=0D +=0D +**/=0D +EFI_STATUS=0D +PublishPeiMemory (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_PHYSICAL_ADDRESS MemoryBase;=0D + UINT64 MemorySize;=0D + UINT32 LowerMemorySize;=0D + UINT32 PeiMemoryCap;=0D +=0D + LowerMemorySize =3D GetSystemMemorySizeBelow4gb ();=0D + if (FeaturePcdGet (PcdSmmSmramRequire)) {=0D + //=0D + // TSEG is chipped from the end of low RAM=0D + //=0D + LowerMemorySize -=3D mQ35TsegMbytes * SIZE_1MB;=0D + }=0D +=0D + //=0D + // If S3 is supported, then the S3 permanent PEI memory is placed next,= =0D + // downwards. Its size is primarily dictated by CpuMpPei. The formula be= low=0D + // is an approximation.=0D + //=0D + if (mS3Supported) {=0D + mS3AcpiReservedMemorySize =3D SIZE_512KB +=0D + mMaxCpuCount *=0D + PcdGet32 (PcdCpuApStackSize);=0D + mS3AcpiReservedMemoryBase =3D LowerMemorySize - mS3AcpiReservedMemoryS= ize;=0D + LowerMemorySize =3D mS3AcpiReservedMemoryBase;=0D + }=0D +=0D + if (mBootMode =3D=3D BOOT_ON_S3_RESUME) {=0D + MemoryBase =3D mS3AcpiReservedMemoryBase;=0D + MemorySize =3D mS3AcpiReservedMemorySize;=0D + } else {=0D + PeiMemoryCap =3D GetPeiMemoryCap ();=0D + DEBUG ((DEBUG_INFO, "%a: mPhysMemAddressWidth=3D%d PeiMemoryCap=3D%u K= B\n",=0D + __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));=0D +=0D + //=0D + // Determine the range of memory to use during PEI=0D + //=0D + // Technically we could lay the permanent PEI RAM over SEC's temporary= =0D + // decompression and scratch buffer even if "secure S3" is needed, sin= ce=0D + // their lifetimes don't overlap. However, PeiFvInitialization() will = cover=0D + // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS m= emory=0D + // allocation HOB, and other allocations served from the permanent PEI= RAM=0D + // shouldn't overlap with that HOB.=0D + //=0D + MemoryBase =3D mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ?=0D + PcdGet32 (PcdOvmfDecompressionScratchEnd) :=0D + PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);=0D + MemorySize =3D LowerMemorySize - MemoryBase;=0D + if (MemorySize > PeiMemoryCap) {=0D + MemoryBase =3D LowerMemorySize - PeiMemoryCap;=0D + MemorySize =3D PeiMemoryCap;=0D + }=0D + }=0D +=0D + //=0D + // Publish this memory to the PEI Core=0D + //=0D + Status =3D PublishSystemMemory(MemoryBase, MemorySize);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return Status;=0D +}=0D +=0D +=0D +/**=0D + Peform Memory Detection for QEMU / KVM=0D +=0D +**/=0D +STATIC=0D +VOID=0D +QemuInitializeRam (=0D + VOID=0D + )=0D +{=0D + UINT64 LowerMemorySize;=0D + UINT64 UpperMemorySize;=0D + MTRR_SETTINGS MtrrSettings;=0D + EFI_STATUS Status;=0D +=0D + DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));=0D +=0D + //=0D + // Determine total memory size available=0D + //=0D + LowerMemorySize =3D GetSystemMemorySizeBelow4gb ();=0D + UpperMemorySize =3D GetSystemMemorySizeAbove4gb ();=0D +=0D + if (mBootMode =3D=3D BOOT_ON_S3_RESUME) {=0D + //=0D + // Create the following memory HOB as an exception on the S3 boot path= .=0D + //=0D + // Normally we'd create memory HOBs only on the normal boot path. Howe= ver,=0D + // CpuMpPei specifically needs such a low-memory HOB on the S3 path as= =0D + // well, for "borrowing" a subset of it temporarily, for the AP startu= p=0D + // vector.=0D + //=0D + // CpuMpPei saves the original contents of the borrowed area in perman= ent=0D + // PEI RAM, in a backup buffer allocated with the normal PEI services.= =0D + // CpuMpPei restores the original contents ("returns" the borrowed are= a) at=0D + // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before=0D + // transferring control to the OS's wakeup vector in the FACS.=0D + //=0D + // We expect any other PEIMs that "borrow" memory similarly to CpuMpPe= i to=0D + // restore the original contents. Furthermore, we expect all such PEIM= s=0D + // (CpuMpPei included) to claim the borrowed areas by producing memory= =0D + // allocation HOBs, and to honor preexistent memory allocation HOBs wh= en=0D + // looking for an area to borrow.=0D + //=0D + AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);=0D + } else {=0D + //=0D + // Create memory HOBs=0D + //=0D + AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);=0D +=0D + if (FeaturePcdGet (PcdSmmSmramRequire)) {=0D + UINT32 TsegSize;=0D +=0D + TsegSize =3D mQ35TsegMbytes * SIZE_1MB;=0D + AddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);=0D + AddReservedMemoryBaseSizeHob (LowerMemorySize - TsegSize, TsegSize,= =0D + TRUE);=0D + } else {=0D + AddMemoryRangeHob (BASE_1MB, LowerMemorySize);=0D + }=0D +=0D + if (UpperMemorySize !=3D 0) {=0D + AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);=0D + }=0D + }=0D +=0D + //=0D + // We'd like to keep the following ranges uncached:=0D + // - [640 KB, 1 MB)=0D + // - [LowerMemorySize, 4 GB)=0D + //=0D + // Everything else should be WB. Unfortunately, programming the inverse = (ie.=0D + // keeping the default UC, and configuring the complement set of the abo= ve as=0D + // WB) is not reliable in general, because the end of the upper RAM can = have=0D + // practically any alignment, and we may not have enough variable MTRRs = to=0D + // cover it exactly.=0D + //=0D + if (IsMtrrSupported ()) {=0D + MtrrGetAllMtrrs (&MtrrSettings);=0D +=0D + //=0D + // MTRRs disabled, fixed MTRRs disabled, default type is uncached=0D + //=0D + ASSERT ((MtrrSettings.MtrrDefType & BIT11) =3D=3D 0);=0D + ASSERT ((MtrrSettings.MtrrDefType & BIT10) =3D=3D 0);=0D + ASSERT ((MtrrSettings.MtrrDefType & 0xFF) =3D=3D 0);=0D +=0D + //=0D + // flip default type to writeback=0D + //=0D + SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);=0D + ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);=0D + MtrrSettings.MtrrDefType |=3D BIT11 | BIT10 | 6;=0D + MtrrSetAllMtrrs (&MtrrSettings);=0D +=0D + //=0D + // Set memory range from 640KB to 1MB to uncacheable=0D + //=0D + Status =3D MtrrSetMemoryAttribute (BASE_512KB + BASE_128KB,=0D + BASE_1MB - (BASE_512KB + BASE_128KB), CacheUncacheable);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Set memory range from the "top of lower RAM" (RAM below 4GB) to 4GB= as=0D + // uncacheable=0D + //=0D + Status =3D MtrrSetMemoryAttribute (LowerMemorySize,=0D + SIZE_4GB - LowerMemorySize, CacheUncacheable);=0D + ASSERT_EFI_ERROR (Status);=0D + }=0D +}=0D +=0D +/**=0D + Publish system RAM and reserve memory regions=0D +=0D +**/=0D +VOID=0D +InitializeRamRegions (=0D + VOID=0D + )=0D +{=0D + QemuInitializeRam ();=0D +=0D + if (mS3Supported && mBootMode !=3D BOOT_ON_S3_RESUME) {=0D + //=0D + // This is the memory range that will be used for PEI on S3 resume=0D + //=0D + BuildMemoryAllocationHob (=0D + mS3AcpiReservedMemoryBase,=0D + mS3AcpiReservedMemorySize,=0D + EfiACPIMemoryNVS=0D + );=0D +=0D + //=0D + // Cover the initial RAM area used as stack and temporary PEI heap.=0D + //=0D + // This is reserved as ACPI NVS so it can be used on S3 resume.=0D + //=0D + BuildMemoryAllocationHob (=0D + PcdGet32 (PcdOvmfSecPeiTempRamBase),=0D + PcdGet32 (PcdOvmfSecPeiTempRamSize),=0D + EfiACPIMemoryNVS=0D + );=0D +=0D + //=0D + // SEC stores its table of GUIDed section handlers here.=0D + //=0D + BuildMemoryAllocationHob (=0D + PcdGet64 (PcdGuidedExtractHandlerTableAddress),=0D + PcdGet32 (PcdGuidedExtractHandlerTableSize),=0D + EfiACPIMemoryNVS=0D + );=0D +=0D +#ifdef MDE_CPU_X64=0D + //=0D + // Reserve the initial page tables built by the reset vector code.=0D + //=0D + // Since this memory range will be used by the Reset Vector on S3=0D + // resume, it must be reserved as ACPI NVS.=0D + //=0D + BuildMemoryAllocationHob (=0D + (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfSecPageTablesBase),=0D + (UINT64)(UINTN) PcdGet32 (PcdOvmfSecPageTablesSize),=0D + EfiACPIMemoryNVS=0D + );=0D +#endif=0D + }=0D +=0D + if (mBootMode !=3D BOOT_ON_S3_RESUME) {=0D + if (!FeaturePcdGet (PcdSmmSmramRequire)) {=0D + //=0D + // Reserve the lock box storage area=0D + //=0D + // Since this memory range will be used on S3 resume, it must be=0D + // reserved as ACPI NVS.=0D + //=0D + // If S3 is unsupported, then various drivers might still write to t= he=0D + // LockBox area. We ought to prevent DXE from serving allocation req= uests=0D + // such that they would overlap the LockBox storage.=0D + //=0D + ZeroMem (=0D + (VOID*)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase),=0D + (UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize)=0D + );=0D + BuildMemoryAllocationHob (=0D + (EFI_PHYSICAL_ADDRESS)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase)= ,=0D + (UINT64)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageSize),=0D + mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData=0D + );=0D + }=0D +=0D + if (FeaturePcdGet (PcdSmmSmramRequire)) {=0D + UINT32 TsegSize;=0D +=0D + //=0D + // Make sure the TSEG area that we reported as a reserved memory res= ource=0D + // cannot be used for reserved memory allocations.=0D + //=0D + TsegSize =3D mQ35TsegMbytes * SIZE_1MB;=0D + BuildMemoryAllocationHob (=0D + GetSystemMemorySizeBelow4gb() - TsegSize,=0D + TsegSize,=0D + EfiReservedMemoryType=0D + );=0D + }=0D + }=0D +}=0D diff --git a/BhyvePkg/PlatformPei/Platform.c b/BhyvePkg/PlatformPei/Platfor= m.c new file mode 100644 index 0000000000..11658d478c --- /dev/null +++ b/BhyvePkg/PlatformPei/Platform.c @@ -0,0 +1,607 @@ +/**@file=0D + Platform PEI driver=0D +=0D + Copyright (c) 2020, Rebecca Cran =0D + Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
=0D + Copyright (c) 2011, Andrei Warkentin =0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +//=0D +// The package level header files this module uses=0D +//=0D +#include =0D +=0D +//=0D +// The Library classes this module consumes=0D +//=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "Platform.h"=0D +#include "Cmos.h"=0D +=0D +EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] =3D {=0D + { EfiACPIMemoryNVS, 0x004 },=0D + { EfiACPIReclaimMemory, 0x008 },=0D + { EfiReservedMemoryType, 0x004 },=0D + { EfiRuntimeServicesData, 0x024 },=0D + { EfiRuntimeServicesCode, 0x030 },=0D + { EfiBootServicesCode, 0x180 },=0D + { EfiBootServicesData, 0xF00 },=0D + { EfiMaxMemoryType, 0x000 }=0D +};=0D +=0D +=0D +EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] =3D {=0D + {=0D + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,=0D + &gEfiPeiMasterBootModePpiGuid,=0D + NULL=0D + }=0D +};=0D +=0D +=0D +UINT16 mHostBridgeDevId;=0D +=0D +EFI_BOOT_MODE mBootMode =3D BOOT_WITH_FULL_CONFIGURATION;=0D +=0D +BOOLEAN mS3Supported =3D FALSE;=0D +=0D +UINT32 mMaxCpuCount;=0D +=0D +VOID=0D +AddIoMemoryBaseSizeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + UINT64 MemorySize=0D + )=0D +{=0D + BuildResourceDescriptorHob (=0D + EFI_RESOURCE_MEMORY_MAPPED_IO,=0D + EFI_RESOURCE_ATTRIBUTE_PRESENT |=0D + EFI_RESOURCE_ATTRIBUTE_INITIALIZED |=0D + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |=0D + EFI_RESOURCE_ATTRIBUTE_TESTED,=0D + MemoryBase,=0D + MemorySize=0D + );=0D +}=0D +=0D +VOID=0D +AddReservedMemoryBaseSizeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + UINT64 MemorySize,=0D + BOOLEAN Cacheable=0D + )=0D +{=0D + BuildResourceDescriptorHob (=0D + EFI_RESOURCE_MEMORY_RESERVED,=0D + EFI_RESOURCE_ATTRIBUTE_PRESENT |=0D + EFI_RESOURCE_ATTRIBUTE_INITIALIZED |=0D + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |=0D + (Cacheable ?=0D + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |=0D + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |=0D + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :=0D + 0=0D + ) |=0D + EFI_RESOURCE_ATTRIBUTE_TESTED,=0D + MemoryBase,=0D + MemorySize=0D + );=0D +}=0D +=0D +VOID=0D +AddIoMemoryRangeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + EFI_PHYSICAL_ADDRESS MemoryLimit=0D + )=0D +{=0D + AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));= =0D +}=0D +=0D +=0D +VOID=0D +AddMemoryBaseSizeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + UINT64 MemorySize=0D + )=0D +{=0D + BuildResourceDescriptorHob (=0D + EFI_RESOURCE_SYSTEM_MEMORY,=0D + EFI_RESOURCE_ATTRIBUTE_PRESENT |=0D + EFI_RESOURCE_ATTRIBUTE_INITIALIZED |=0D + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |=0D + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |=0D + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |=0D + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |=0D + EFI_RESOURCE_ATTRIBUTE_TESTED,=0D + MemoryBase,=0D + MemorySize=0D + );=0D +}=0D +=0D +=0D +VOID=0D +AddMemoryRangeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + EFI_PHYSICAL_ADDRESS MemoryLimit=0D + )=0D +{=0D + AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));=0D +}=0D +=0D +=0D +VOID=0D +MemMapInitialization (=0D + VOID=0D + )=0D +{=0D + UINT64 PciIoBase;=0D + UINT64 PciIoSize;=0D + RETURN_STATUS PcdStatus;=0D +=0D + PciIoBase =3D 0xC000;=0D + PciIoSize =3D 0x4000;=0D +=0D + //=0D + // Create Memory Type Information HOB=0D + //=0D + BuildGuidDataHob (=0D + &gEfiMemoryTypeInformationGuid,=0D + mDefaultMemoryTypeInformation,=0D + sizeof(mDefaultMemoryTypeInformation)=0D + );=0D +=0D + //=0D + // Video memory + Legacy BIOS region=0D + //=0D + AddIoMemoryRangeHob (0x0A0000, BASE_1MB);=0D +=0D + if (TRUE) {=0D + UINT32 TopOfLowRam;=0D + UINT64 PciExBarBase;=0D + UINT32 PciBase;=0D + UINT32 PciSize;=0D +=0D + TopOfLowRam =3D GetSystemMemorySizeBelow4gb ();=0D + PciExBarBase =3D 0;=0D + if (mHostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) {=0D + //=0D + // The MMCONFIG area is expected to fall between the top of low RAM = and=0D + // the base of the 32-bit PCI host aperture.=0D + //=0D + PciExBarBase =3D FixedPcdGet64 (PcdPciExpressBaseAddress);=0D + ASSERT (TopOfLowRam <=3D PciExBarBase);=0D + ASSERT (PciExBarBase <=3D MAX_UINT32 - SIZE_256MB);=0D + PciBase =3D (UINT32)(PciExBarBase + SIZE_256MB);=0D + } else {=0D + PciBase =3D (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;=0D + }=0D +=0D + //=0D + // address purpose size=0D + // ------------ -------- -------------------------=0D + // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g)=0D + // 0xFC000000 gap 44 MB=0D + // 0xFEC00000 IO-APIC 4 KB=0D + // 0xFEC01000 gap 1020 KB=0D + // 0xFED00000 HPET 1 KB=0D + // 0xFED00400 gap 111 KB=0D + // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB=0D + // 0xFED20000 gap 896 KB=0D + // 0xFEE00000 LAPIC 1 MB=0D + //=0D + PciSize =3D 0xFC000000 - PciBase;=0D + AddIoMemoryBaseSizeHob (PciBase, PciSize);=0D + PcdStatus =3D PcdSet64S (PcdPciMmio32Base, PciBase);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + PcdStatus =3D PcdSet64S (PcdPciMmio32Size, PciSize);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +=0D + AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);=0D + AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);=0D + if (mHostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) {=0D + AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);=0D + //=0D + // Note: there should be an=0D + //=0D + // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);=0D + //=0D + // call below, just like the one above for RCBA. However, Linux insi= sts=0D + // that the MMCONFIG area be marked in the E820 or UEFI memory map a= s=0D + // "reserved memory" -- Linux does not content itself with a simple = gap=0D + // in the memory map wherever the MCFG ACPI table points to.=0D + //=0D + // This appears to be a safety measure. The PCI Firmware Specificati= on=0D + // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources= can=0D + // *optionally* be returned in [...] EFIGetMemoryMap as reserved mem= ory=0D + // [...]". (Emphasis added here.)=0D + //=0D + // Normally we add memory resource descriptor HOBs in=0D + // QemuInitializeRam(), and pre-allocate from those with memory=0D + // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG = area=0D + // is most definitely not RAM; so, as an exception, cover it with=0D + // uncacheable reserved memory right here.=0D + //=0D + AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);=0D + BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB,=0D + EfiReservedMemoryType);=0D + }=0D + AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB= );=0D +=0D + //=0D + // On Q35, the IO Port space is available for PCI resource allocations= from=0D + // 0x6000 up.=0D + //=0D + if (mHostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) {=0D + PciIoBase =3D 0x6000;=0D + PciIoSize =3D 0xA000;=0D + ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);=0D + }=0D + }=0D +=0D + //=0D + // Add PCI IO Port space available for PCI resource allocations.=0D + //=0D + BuildResourceDescriptorHob (=0D + EFI_RESOURCE_IO,=0D + EFI_RESOURCE_ATTRIBUTE_PRESENT |=0D + EFI_RESOURCE_ATTRIBUTE_INITIALIZED,=0D + PciIoBase,=0D + PciIoSize=0D + );=0D + PcdStatus =3D PcdSet64S (PcdPciIoBase, PciIoBase);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + PcdStatus =3D PcdSet64S (PcdPciIoSize, PciIoSize);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +}=0D +=0D +VOID=0D +NoexecDxeInitialization (=0D + VOID=0D + )=0D +{=0D +}=0D +=0D +VOID=0D +PciExBarInitialization (=0D + VOID=0D + )=0D +{=0D + union {=0D + UINT64 Uint64;=0D + UINT32 Uint32[2];=0D + } PciExBarBase;=0D +=0D + //=0D + // We only support the 256MB size for the MMCONFIG area:=0D + // 256 buses * 32 devices * 8 functions * 4096 bytes config space.=0D + //=0D + // The masks used below enforce the Q35 requirements that the MMCONFIG a= rea=0D + // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 G= B.=0D + //=0D + // Note that (b) also ensures that the minimum address width we have=0D + // determined in AddressWidthInitialization(), i.e., 36 bits, will suffi= ce=0D + // for DXE's page tables to cover the MMCONFIG area.=0D + //=0D + PciExBarBase.Uint64 =3D FixedPcdGet64 (PcdPciExpressBaseAddress);=0D + ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) =3D=3D 0);=0D + ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) =3D=3D 0);=0D +=0D + //=0D + // Clear the PCIEXBAREN bit first, before programming the high register.= =0D + //=0D + PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);=0D +=0D + //=0D + // Program the high register. Then program the low register, setting the= =0D + // MMCONFIG area size and enabling decoding at once.=0D + //=0D + PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[= 1]);=0D + PciWrite32 (=0D + DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),=0D + PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN=0D + );=0D +}=0D +=0D +VOID=0D +MiscInitialization (=0D + VOID=0D + )=0D +{=0D + UINTN PmCmd;=0D + UINTN Pmba;=0D + UINT32 PmbaAndVal;=0D + UINT32 PmbaOrVal;=0D + UINTN AcpiCtlReg;=0D + UINT8 AcpiEnBit;=0D + RETURN_STATUS PcdStatus;=0D +=0D + //=0D + // Disable A20 Mask=0D + //=0D + IoOr8 (0x92, BIT1);=0D +=0D + //=0D + // Build the CPU HOB with guest RAM size dependent address width and 16-= bits=0D + // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed dur= ing=0D + // S3 resume as well, so we build it unconditionally.)=0D + //=0D + BuildCpuHob (mPhysMemAddressWidth, 16);=0D +=0D + //=0D + // Determine platform type and save Host Bridge DID to PCD=0D + //=0D + switch (mHostBridgeDevId) {=0D + case 0x1275: // BHYVE=0D + case INTEL_82441_DEVICE_ID:=0D + PmCmd =3D POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);=0D + Pmba =3D POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);=0D + PmbaAndVal =3D ~(UINT32)PIIX4_PMBA_MASK;=0D + PmbaOrVal =3D PIIX4_PMBA_VALUE;=0D + AcpiCtlReg =3D POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);=0D + AcpiEnBit =3D PIIX4_PMREGMISC_PMIOSE;=0D + break;=0D + case INTEL_Q35_MCH_DEVICE_ID:=0D + PmCmd =3D POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);=0D + Pmba =3D POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);=0D + PmbaAndVal =3D ~(UINT32)ICH9_PMBASE_MASK;=0D + PmbaOrVal =3D ICH9_PMBASE_VALUE;=0D + AcpiCtlReg =3D POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);=0D + AcpiEnBit =3D ICH9_ACPI_CNTL_ACPI_EN;=0D + break;=0D + default:=0D + DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",= =0D + __FUNCTION__, mHostBridgeDevId));=0D + ASSERT (FALSE);=0D + return;=0D + }=0D + PcdStatus =3D PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +=0D + //=0D + // If the appropriate IOspace enable bit is set, assume the ACPI PMBA=0D + // has been configured (e.g., by Xen) and skip the setup here.=0D + // This matches the logic in AcpiTimerLibConstructor ().=0D + //=0D + if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) =3D=3D 0) {=0D + //=0D + // The PEI phase should be exited with fully accessibe ACPI PM IO spac= e:=0D + // 1. set PMBA=0D + //=0D + PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);=0D +=0D + //=0D + // 2. set PCICMD/IOSE=0D + //=0D + PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);=0D +=0D + //=0D + // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN= )=0D + //=0D + PciOr8 (AcpiCtlReg, AcpiEnBit);=0D + }=0D +=0D + if (mHostBridgeDevId =3D=3D INTEL_Q35_MCH_DEVICE_ID) {=0D + //=0D + // Set Root Complex Register Block BAR=0D + //=0D + PciWrite32 (=0D + POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),=0D + ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN=0D + );=0D +=0D + //=0D + // Set PCI Express Register Range Base Address=0D + //=0D + PciExBarInitialization ();=0D + }=0D +}=0D +=0D +=0D +VOID=0D +BootModeInitialization (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + if (CmosRead8 (0xF) =3D=3D 0xFE) {=0D + mBootMode =3D BOOT_ON_S3_RESUME;=0D + }=0D + CmosWrite8 (0xF, 0x00);=0D +=0D + Status =3D PeiServicesSetBootMode (mBootMode);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D PeiServicesInstallPpi (mPpiBootMode);=0D + ASSERT_EFI_ERROR (Status);=0D +}=0D +=0D +=0D +VOID=0D +ReserveEmuVariableNvStore (=0D + )=0D +{=0D + EFI_PHYSICAL_ADDRESS VariableStore;=0D + RETURN_STATUS PcdStatus;=0D +=0D + //=0D + // Allocate storage for NV variables early on so it will be=0D + // at a consistent address. Since VM memory is preserved=0D + // across reboots, this allows the NV variable storage to survive=0D + // a VM reboot.=0D + //=0D + VariableStore =3D=0D + (EFI_PHYSICAL_ADDRESS)(UINTN)=0D + AllocateRuntimePages (=0D + EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))=0D + );=0D + DEBUG ((DEBUG_INFO,=0D + "Reserved variable store memory: 0x%lX; size: %dkb\n",=0D + VariableStore,=0D + (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024=0D + ));=0D + PcdStatus =3D PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);= =0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +}=0D +=0D +=0D +VOID=0D +DebugDumpCmos (=0D + VOID=0D + )=0D +{=0D + UINT32 Loop;=0D +=0D + DEBUG ((DEBUG_INFO, "CMOS:\n"));=0D +=0D + for (Loop =3D 0; Loop < 0x80; Loop++) {=0D + if ((Loop % 0x10) =3D=3D 0) {=0D + DEBUG ((DEBUG_INFO, "%02x:", Loop));=0D + }=0D + DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));=0D + if ((Loop % 0x10) =3D=3D 0xf) {=0D + DEBUG ((DEBUG_INFO, "\n"));=0D + }=0D + }=0D +}=0D +=0D +=0D +VOID=0D +S3Verification (=0D + VOID=0D + )=0D +{=0D +#if defined (MDE_CPU_X64)=0D + if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {=0D + DEBUG ((DEBUG_ERROR,=0D + "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n", __FUNCTION_= _));=0D + DEBUG ((DEBUG_ERROR,=0D + "%a: Please disable S3 on the QEMU command line (see the README),\n"= ,=0D + __FUNCTION__));=0D + DEBUG ((DEBUG_ERROR,=0D + "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n", __FUNCTION__));= =0D + ASSERT (FALSE);=0D + CpuDeadLoop ();=0D + }=0D +#endif=0D +}=0D +=0D +=0D +/**=0D + Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modu= les.=0D + Set the mMaxCpuCount variable.=0D +**/=0D +VOID=0D +MaxCpuCountInitialization (=0D + VOID=0D + )=0D +{=0D + UINT16 ProcessorCount =3D 0;=0D + RETURN_STATUS PcdStatus;=0D +=0D + //=0D + // If the fw_cfg key or fw_cfg entirely is unavailable, load mMaxCpuCoun= t=0D + // from the PCD default. No change to PCDs.=0D + //=0D + if (ProcessorCount =3D=3D 0) {=0D + mMaxCpuCount =3D PcdGet32 (PcdCpuMaxLogicalProcessorNumber);=0D + return;=0D + }=0D + //=0D + // Otherwise, set mMaxCpuCount to the value reported by QEMU.=0D + //=0D + mMaxCpuCount =3D ProcessorCount;=0D + //=0D + // Additionally, tell UefiCpuPkg modules (a) the exact number of VCPUs, = (b)=0D + // to wait, in the initial AP bringup, exactly as long as it takes for a= ll of=0D + // the APs to report in. For this, we set the longest representable time= out=0D + // (approx. 71 minutes).=0D + //=0D + PcdStatus =3D PcdSet32S (PcdCpuMaxLogicalProcessorNumber, ProcessorCount= );=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + PcdStatus =3D PcdSet32S (PcdCpuApInitTimeOutInMicroSeconds, MAX_UINT32);= =0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + DEBUG ((DEBUG_INFO, "%a: QEMU reports %d processor(s)\n", __FUNCTION__,= =0D + ProcessorCount));=0D +}=0D +=0D +=0D +/**=0D + Perform Platform PEI initialization.=0D +=0D + @param FileHandle Handle of the file being invoked.=0D + @param PeiServices Describes the list of possible PEI Services.=0D +=0D + @return EFI_SUCCESS The PEIM initialized successfully.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InitializePlatform (=0D + IN EFI_PEI_FILE_HANDLE FileHandle,=0D + IN CONST EFI_PEI_SERVICES **PeiServices=0D + )=0D +{=0D + DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));=0D +=0D + //=0D + // Initialize Local APIC Timer hardware and disable Local APIC Timer=0D + // interrupts before initializing the Debug Agent and the debug timer is= =0D + // enabled.=0D + //=0D + InitializeApicTimer (0, MAX_UINT32, TRUE, 5);=0D + DisableApicTimerInterrupt ();=0D +=0D + DebugDumpCmos ();=0D +=0D + BootModeInitialization ();=0D + AddressWidthInitialization ();=0D + MaxCpuCountInitialization ();=0D +=0D + //=0D + // Query Host Bridge DID=0D + //=0D + mHostBridgeDevId =3D PciRead16 (OVMF_HOSTBRIDGE_DID);=0D +=0D + if (FeaturePcdGet (PcdSmmSmramRequire)) {=0D + Q35TsegMbytesInitialization ();=0D + }=0D +=0D + PublishPeiMemory ();=0D +=0D + InitializeRamRegions ();=0D +=0D + if (mBootMode !=3D BOOT_ON_S3_RESUME) {=0D + if (!FeaturePcdGet (PcdSmmSmramRequire)) {=0D + ReserveEmuVariableNvStore ();=0D + }=0D + PeiFvInitialization ();=0D + MemMapInitialization ();=0D + NoexecDxeInitialization ();=0D + }=0D +=0D + InstallClearCacheCallback ();=0D + AmdSevInitialize ();=0D + MiscInitialization ();=0D + InstallFeatureControlCallback ();=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/BhyvePkg/PlatformPei/Platform.h b/BhyvePkg/PlatformPei/Platfor= m.h new file mode 100644 index 0000000000..8239ca05ac --- /dev/null +++ b/BhyvePkg/PlatformPei/Platform.h @@ -0,0 +1,137 @@ +/** @file=0D + Platform PEI module include file.=0D +=0D + Copyright (c) 2020, Rebecca Cran =0D + Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef _PLATFORM_PEI_H_INCLUDED_=0D +#define _PLATFORM_PEI_H_INCLUDED_=0D +=0D +#include =0D +=0D +VOID=0D +AddIoMemoryBaseSizeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + UINT64 MemorySize=0D + );=0D +=0D +VOID=0D +AddIoMemoryRangeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + EFI_PHYSICAL_ADDRESS MemoryLimit=0D + );=0D +=0D +VOID=0D +AddMemoryBaseSizeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + UINT64 MemorySize=0D + );=0D +=0D +VOID=0D +AddMemoryRangeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + EFI_PHYSICAL_ADDRESS MemoryLimit=0D + );=0D +=0D +VOID=0D +AddReservedMemoryBaseSizeHob (=0D + EFI_PHYSICAL_ADDRESS MemoryBase,=0D + UINT64 MemorySize,=0D + BOOLEAN Cacheable=0D + );=0D +=0D +VOID=0D +AddressWidthInitialization (=0D + VOID=0D + );=0D +=0D +VOID=0D +Q35TsegMbytesInitialization (=0D + VOID=0D + );=0D +=0D +VOID=0D +Q35SmramAtDefaultSmbaseInitialization (=0D + VOID=0D + );=0D +=0D +EFI_STATUS=0D +PublishPeiMemory (=0D + VOID=0D + );=0D +=0D +UINT32=0D +GetSystemMemorySizeBelow4gb (=0D + VOID=0D + );=0D +=0D +VOID=0D +QemuUc32BaseInitialization (=0D + VOID=0D + );=0D +=0D +VOID=0D +InitializeRamRegions (=0D + VOID=0D + );=0D +=0D +EFI_STATUS=0D +PeiFvInitialization (=0D + VOID=0D + );=0D +=0D +VOID=0D +MemTypeInfoInitialization (=0D + VOID=0D + );=0D +=0D +VOID=0D +InstallFeatureControlCallback (=0D + VOID=0D + );=0D +=0D +VOID=0D +InstallClearCacheCallback (=0D + VOID=0D + );=0D +=0D +EFI_STATUS=0D +InitializeXen (=0D + VOID=0D + );=0D +=0D +BOOLEAN=0D +XenDetect (=0D + VOID=0D + );=0D +=0D +VOID=0D +AmdSevInitialize (=0D + VOID=0D + );=0D +=0D +extern BOOLEAN mXen;=0D +=0D +VOID=0D +XenPublishRamRegions (=0D + VOID=0D + );=0D +=0D +extern EFI_BOOT_MODE mBootMode;=0D +=0D +extern BOOLEAN mS3Supported;=0D +=0D +extern UINT8 mPhysMemAddressWidth;=0D +=0D +extern UINT32 mMaxCpuCount;=0D +=0D +extern UINT16 mHostBridgeDevId;=0D +=0D +extern BOOLEAN mQ35SmramAtDefaultSmbase;=0D +=0D +extern UINT32 mQemuUc32Base;=0D +=0D +#endif // _PLATFORM_PEI_H_INCLUDED_=0D diff --git a/BhyvePkg/PlatformPei/PlatformPei.inf b/BhyvePkg/PlatformPei/Pl= atformPei.inf new file mode 100644 index 0000000000..7288cff4c8 --- /dev/null +++ b/BhyvePkg/PlatformPei/PlatformPei.inf @@ -0,0 +1,113 @@ +## @file=0D +# Platform PEI driver=0D +#=0D +# This module provides platform specific function to detect boot mode.=0D +#=0D +# Copyright (c) 2020, Rebecca Cran =0D +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
= =0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D PlatformPei=0D + FILE_GUID =3D aa89d903-345b-4ab2-9abf-030b5efb5d50= =0D + MODULE_TYPE =3D PEIM=0D + VERSION_STRING =3D 1.0=0D + ENTRY_POINT =3D InitializePlatform=0D +=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64 EBC=0D +#=0D +=0D +[Sources]=0D + AmdSev.c=0D + ClearCache.c=0D + Cmos.c=0D + Cmos.h=0D + FeatureControl.c=0D + Fv.c=0D + MemDetect.c=0D + Platform.c=0D + Platform.h=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + SecurityPkg/SecurityPkg.dec=0D + UefiCpuPkg/UefiCpuPkg.dec=0D + OvmfPkg/OvmfPkg.dec=0D +=0D +[Guids]=0D + gEfiMemoryTypeInformationGuid=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + CacheMaintenanceLib=0D + DebugLib=0D + HobLib=0D + IoLib=0D + PciLib=0D + ResourcePublicationLib=0D + PeiServicesLib=0D + PeiServicesTablePointerLib=0D + PeimEntryPoint=0D + MtrrLib=0D + MemEncryptSevLib=0D + PcdLib=0D + LocalApicLib=0D +=0D +[Pcd]=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize=0D + gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId=0D + gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase=0D + gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize=0D + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base=0D + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size=0D + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base=0D + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd=0D + gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes=0D + gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask=0D + gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy=0D + gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress=0D + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber=0D + gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds=0D + gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize=0D +=0D +[FixedPcd]=0D + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress=0D +=0D +[FeaturePcd]=0D + gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire=0D +=0D +[Ppis]=0D + gEfiPeiMasterBootModePpiGuid=0D + gEfiPeiMpServicesPpiGuid=0D +=0D +[Depex]=0D + TRUE=0D +=0D --=20 2.25.1