/** @file
SEV-SNP Page Validation functions.
Copyright (c) 2021 - 2024, AMD Incorporated. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include "SnpPageStateChange.h"
#include "VirtualMemory.h"
STATIC UINT8 mPscBufferPage[EFI_PAGE_SIZE];
typedef struct {
UINT64 StartAddress;
UINT64 EndAddress;
} SNP_PRE_VALIDATED_RANGE;
STATIC SNP_PRE_VALIDATED_RANGE mPreValidatedRange[] = {
// The below address range was part of the SEV OVMF metadata, and range
// should be pre-validated by the Hypervisor.
{
FixedPcdGet32 (PcdOvmfSecPageTablesBase),
FixedPcdGet32 (PcdOvmfPeiMemFvBase),
},
// The below range is pre-validated by the Sec/SecMain.c
{
FixedPcdGet32 (PcdOvmfSecValidatedStart),
FixedPcdGet32 (PcdOvmfSecValidatedEnd)
},
};
STATIC
BOOLEAN
DetectPreValidatedOverLap (
IN PHYSICAL_ADDRESS StartAddress,
IN PHYSICAL_ADDRESS EndAddress,
OUT SNP_PRE_VALIDATED_RANGE *OverlapRange
)
{
UINTN i;
//
// Check if the specified address range exist in pre-validated array.
//
for (i = 0; i < ARRAY_SIZE (mPreValidatedRange); i++) {
if ((mPreValidatedRange[i].StartAddress < EndAddress) &&
(StartAddress < mPreValidatedRange[i].EndAddress))
{
OverlapRange->StartAddress = mPreValidatedRange[i].StartAddress;
OverlapRange->EndAddress = mPreValidatedRange[i].EndAddress;
return TRUE;
}
}
return FALSE;
}
/**
Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
@param[in] BaseAddress Base address
@param[in] NumPages Number of pages starting from the base address
**/
VOID
EFIAPI
MemEncryptSevSnpPreValidateSystemRam (
IN PHYSICAL_ADDRESS BaseAddress,
IN UINTN NumPages
)
{
PHYSICAL_ADDRESS EndAddress;
SNP_PRE_VALIDATED_RANGE OverlapRange;
EFI_STATUS Status;
if (!MemEncryptSevSnpIsEnabled ()) {
return;
}
EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
//
// The page table used in PEI can address up to 4GB memory. If we are asked to
// validate a range above the 4GB, then create an identity mapping so that the
// PVALIDATE instruction can execute correctly. If the page table entry is not
// present then PVALIDATE will #GP.
//
if (BaseAddress >= SIZE_4GB) {
Status = InternalMemEncryptSevCreateIdentityMap1G (
0,
BaseAddress,
EFI_PAGES_TO_SIZE (NumPages)
);
if (EFI_ERROR (Status)) {
ASSERT (FALSE);
CpuDeadLoop ();
}
}
while (BaseAddress < EndAddress) {
//
// Check if the range overlaps with the pre-validated ranges.
//
if (DetectPreValidatedOverLap (BaseAddress, EndAddress, &OverlapRange)) {
// Validate the non-overlap regions.
if (BaseAddress < OverlapRange.StartAddress) {
NumPages = EFI_SIZE_TO_PAGES (OverlapRange.StartAddress - BaseAddress);
InternalSetPageState (
BaseAddress,
NumPages,
SevSnpPagePrivate,
TRUE,
mPscBufferPage,
sizeof (mPscBufferPage)
);
}
BaseAddress = OverlapRange.EndAddress;
continue;
}
// Validate the remaining pages.
NumPages = EFI_SIZE_TO_PAGES (EndAddress - BaseAddress);
InternalSetPageState (
BaseAddress,
NumPages,
SevSnpPagePrivate,
TRUE,
mPscBufferPage,
sizeof (mPscBufferPage)
);
BaseAddress = EndAddress;
}
}