QemuQ35Pkg/PlatformPei: Drop S3 and Lock Box support

Removes platform initialization logic for S3 and the lock box.

Notably, the number of MMRAM regions is reduced from two to one since
the first MMRAM range was previously a 4KB page used to hold S3
resume structures.

The amount of ACPI NVS reservation is reduced substantially since
areas like the following do not need to be preserved for S3 resume:

- CPU AP stack buffers
- Temp RAM stack and heap
- GUIDed section extraction handlers
- Reset vector initial page tables

The lock box storage buffer is also not allocated at all. Previously,
it was allocated as boot services data (not ACPI NVS) since S3 was
never enabled. In any case, that space is no longer allocated.

Asserts are added in places through key control flow to alert a
developer if S3 is detected as enabled when it should not be.

Signed-off-by: Michael Kubacki <Michael.kubacki@microsoft.com>
This commit is contained in:
Michael Kubacki 2024-09-20 09:03:57 -04:00
Родитель 4044593f31
Коммит d21b07fa30
5 изменённых файлов: 110 добавлений и 342 удалений

Просмотреть файл

@ -25,19 +25,15 @@ 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
EfiBootServicesData
);
//
@ -45,38 +41,15 @@ PeiFvInitialization (
//
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
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
//

Просмотреть файл

@ -2,12 +2,10 @@
Memory Detection for Virtual Machines.
Copyright (c) 2006 - 2024, Intel Corporation. All rights reserved.<BR>
Copyright (c) Microsoft Corporation
SPDX-License-Identifier: BSD-2-Clause-Patent
Module Name:
MemDetect.c
**/
//
@ -43,9 +41,6 @@ Module Name:
UINT8 mPhysMemAddressWidth;
STATIC UINT32 mS3AcpiReservedMemoryBase;
STATIC UINT32 mS3AcpiReservedMemorySize;
STATIC UINT16 mQ35TsegMbytes;
BOOLEAN mQ35SmramAtDefaultSmbase;
@ -70,7 +65,7 @@ Q35TsegMbytesInitialization (
//
// 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.
// the (unimplemented) register before rebooting.
// Subsequently, the read returns MCH_EXT_TSEG_MB_QUERY unchanged.
//
// On a QEMU machine type that offers an extended TSEG, the initial write
@ -673,28 +668,14 @@ PublishPeiMemory (
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;
}
// S3 is not supported
ASSERT (mBootMode != BOOT_ON_S3_RESUME);
if (mBootMode == BOOT_ON_S3_RESUME) {
MemoryBase = mS3AcpiReservedMemoryBase;
MemorySize = mS3AcpiReservedMemorySize;
} else {
PeiMemoryCap = GetPeiMemoryCap ();
DEBUG ((
DEBUG_INFO,
"%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
__FUNCTION__,
__func__,
mPhysMemAddressWidth,
PeiMemoryCap >> 10
));
@ -702,27 +683,16 @@ PublishPeiMemory (
//
// 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);
MemoryBase = PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);
MemorySize = LowerMemorySize - MemoryBase;
if (MemorySize > PeiMemoryCap) {
MemoryBase = LowerMemorySize - PeiMemoryCap;
MemorySize = PeiMemoryCap;
}
}
//
// MEMFD_BASE_ADDRESS separates the SMRAM at the default SMBASE from the
// normal boot permanent PEI RAM. Regarding the S3 boot path, the S3
// permanent PEI RAM is located even higher.
// normal boot permanent PEI RAM.
//
if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
ASSERT (SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE <= MemoryBase);
@ -758,7 +728,7 @@ CreateSmmSmramMemoryHob (
EFI_PEI_HOB_POINTERS Hob;
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock;
SmramRanges = 2;
SmramRanges = 1;
BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK) + (SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR);
Hob.Raw = BuildGuidHob (
@ -771,21 +741,12 @@ CreateSmmSmramMemoryHob (
SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;
//
// 1. Create first SMRAM descriptor, which contains data structures used in S3 resume.
// One page is enough for the data structure
// Create SMRAM descriptor, which is free and will be used by the SMM foundation.
//
SmramHobDescriptorBlock->Descriptor[0].PhysicalStart = StartAddress;
SmramHobDescriptorBlock->Descriptor[0].CpuStart = StartAddress;
SmramHobDescriptorBlock->Descriptor[0].PhysicalSize = EFI_PAGE_SIZE;
SmramHobDescriptorBlock->Descriptor[0].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE | EFI_ALLOCATED;
//
// 2. Create second SMRAM descriptor, which is free and will be used by SMM foundation.
//
SmramHobDescriptorBlock->Descriptor[1].PhysicalStart = SmramHobDescriptorBlock->Descriptor[0].PhysicalStart + EFI_PAGE_SIZE;
SmramHobDescriptorBlock->Descriptor[1].CpuStart = SmramHobDescriptorBlock->Descriptor[0].CpuStart + EFI_PAGE_SIZE;
SmramHobDescriptorBlock->Descriptor[1].PhysicalSize = Size - EFI_PAGE_SIZE;
SmramHobDescriptorBlock->Descriptor[1].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;
SmramHobDescriptorBlock->Descriptor[0].PhysicalSize = Size;
SmramHobDescriptorBlock->Descriptor[0].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;
}
STATIC
@ -824,8 +785,10 @@ QemuInitializeRam (
VOID
)
{
UINT32 TsegSize;
UINT64 LowerMemorySize;
UINT64 UpperMemorySize;
EFI_PHYSICAL_ADDRESS TsegBase;
MTRR_SETTINGS MtrrSettings;
EFI_STATUS Status;
@ -836,38 +799,12 @@ QemuInitializeRam (
//
LowerMemorySize = GetSystemMemorySizeBelow4gb ();
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.
//
QemuInitializeRamBelow1gb ();
} else {
//
// Create memory HOBs
//
QemuInitializeRamBelow1gb ();
if (FeaturePcdGet (PcdSmmSmramRequire)) {
UINT32 TsegSize;
EFI_PHYSICAL_ADDRESS TsegBase;
TsegSize = mQ35TsegMbytes * SIZE_1MB;
TsegBase = LowerMemorySize - TsegSize;
AddMemoryRangeHob (BASE_1MB, TsegBase);
@ -896,7 +833,6 @@ QemuInitializeRam (
AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
}
}
}
//
// We'd like to keep the following ranges uncached:
@ -959,109 +895,15 @@ InitializeRamRegions (
VOID
)
{
QemuInitializeRam ();
SevInitializeRam ();
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 (PcdSecPeiTemporaryRamBase),
PcdGet32 (PcdSecPeiTemporaryRamSize),
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
);
if (MemEncryptSevEsIsEnabled ()) {
//
// If SEV-ES is enabled, reserve the GHCB-related memory area. This
// includes the extra page table used to break down the 2MB page
// mapping into 4KB page entries where the GHCB resides and the
// GHCB area itself.
//
// 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 (PcdOvmfSecGhcbPageTableBase),
(UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableSize),
EfiACPIMemoryNVS
);
BuildMemoryAllocationHob (
(EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBase),
(UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbSize),
EfiACPIMemoryNVS
);
BuildMemoryAllocationHob (
(EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupBase),
(UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupSize),
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;
QemuInitializeRam ();
SevInitializeRam ();
// S3 is not supported.
ASSERT (mBootMode != BOOT_ON_S3_RESUME);
if (FeaturePcdGet (PcdSmmSmramRequire)) {
//
// Make sure the TSEG area that we reported as a reserved memory resource
// cannot be used for reserved memory allocations.
@ -1090,20 +932,20 @@ InitializeRamRegions (
//
// Reserve the work area.
//
// Since this memory range will be used by the Reset Vector on S3
// resume, it must be reserved as ACPI NVS.
// This range was originally used by the Reset Vector on S3
// resume and in that case, it would be allocated as ACPI NVS.
//
// If S3 is unsupported, then various drivers might still write to the
// S3 is no longer supported. However, drivers might still write to the
// work area. We ought to prevent DXE from serving allocation requests
// such that they would overlap the work area.
// such that they would overlap the work area. The area is also allocated
// as boot services data to prevent impact on OS mapped memory.
//
BuildMemoryAllocationHob (
(EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),
(UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),
mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
EfiBootServicesData
);
}
#endif
}
}

Просмотреть файл

@ -3,6 +3,7 @@
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
Copyright (c) Microsoft Corporation
SPDX-License-Identifier: BSD-2-Clause-Patent
@ -27,7 +28,6 @@
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/QemuFwCfgS3Lib.h>
#include <Library/QemuFwCfgSimpleParserLib.h>
#include <Library/ResourcePublicationLib.h>
#include <Ppi/MasterBootMode.h>
@ -55,8 +55,6 @@ UINT16 mHostBridgeDevId;
EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
BOOLEAN mS3Supported = FALSE;
UINT32 mMaxCpuCount;
VOID
@ -416,8 +414,7 @@ MiscInitialization (
//
// 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.)
// of IO space.
//
BuildCpuHob (mPhysMemAddressWidth, 16);
@ -516,7 +513,9 @@ BootModeInitialization (
EFI_STATUS Status;
if (CmosRead8 (0xF) == 0xFE) {
mBootMode = BOOT_ON_S3_RESUME;
// S3 is not supported. Do not modify the boot mode.
DEBUG ((DEBUG_ERROR, "[%a] S3 is enabled in CMOS, but not supported!\n", __func__));
ASSERT (FALSE);
}
CmosWrite8 (0xF, 0x00);
@ -578,35 +577,6 @@ DebugDumpCmos (
}
}
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 \"QemuQ35PkgIa32X64.dsc\".\n",
__FUNCTION__
));
ASSERT (FALSE);
CpuDeadLoop ();
}
#endif
}
VOID
Q35BoardVerification (
VOID
@ -818,7 +788,6 @@ InitializePlatform (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
// MU_CHANGE START
DXE_MEMORY_PROTECTION_SETTINGS DxeSettings;
MM_MEMORY_PROTECTION_SETTINGS MmSettings;
@ -852,14 +821,6 @@ InitializePlatform (
DebugDumpCmos ();
if (QemuFwCfgS3Enabled ()) {
DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
mS3Supported = TRUE;
Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
ASSERT_EFI_ERROR (Status);
}
S3Verification ();
BootModeInitialization ();
AddressWidthInitialization ();
@ -882,7 +843,6 @@ InitializePlatform (
InitializeRamRegions ();
if (mBootMode != BOOT_ON_S3_RESUME) {
if (!FeaturePcdGet (PcdSmmSmramRequire)) {
ReserveEmuVariableNvStore ();
}
@ -891,7 +851,6 @@ InitializePlatform (
MemTypeInfoInitialization ();
MemMapInitialization ();
NoexecDxeInitialization ();
}
InstallClearCacheCallback ();
AmdSevInitialize ();

Просмотреть файл

@ -114,8 +114,6 @@ SevInitializeRam (
VOID
);
extern BOOLEAN mS3Supported;
extern UINT8 mPhysMemAddressWidth;
extern UINT32 mMaxCpuCount;

Просмотреть файл

@ -63,7 +63,6 @@
PeiServicesTablePointerLib
PeimEntryPoint
QemuFwCfgLib
QemuFwCfgS3Lib
QemuFwCfgSimpleParserLib
MtrrLib
MemEncryptSevLib
@ -83,8 +82,6 @@
gUefiQemuQ35PkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
gUefiQemuQ35PkgTokenSpaceGuid.PcdOvmfSecGhcbBase
gUefiQemuQ35PkgTokenSpaceGuid.PcdOvmfSecGhcbSize
gQemuPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
gQemuPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
gUefiQemuQ35PkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
gQemuPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
gUefiQemuQ35PkgTokenSpaceGuid.PcdPciIoBase
@ -104,7 +101,6 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable
# gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack MU_CHANGE
gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable
gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize