Files
system76-edk2/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c
Brijesh Singh 202fb22be6 OvmfPkg/SecMain: validate the memory used for decompressing Fv
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275

The VMM launch sequence should have pre-validated all the data pages used
in the Reset vector. The range does not cover the data pages used during
the SEC phase (mainly PEI and DXE firmware volume decompression memory).

When SEV-SNP is active, the memory must be pre-validated before the access.
Add support to pre-validate the memory range from SnpSecPreValidatedStart
to SnpSecPreValidatedEnd. This should be sufficent to enter into the PEI
phase.

Cc: Michael Roth <michael.roth@amd.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Jiewen Yao <Jiewen.yao@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
2021-12-09 06:28:10 +00:00

129 lines
3.5 KiB
C

/** @file
SEV-SNP Page Validation functions.
Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi/UefiBaseType.h>
#include <Library/BaseLib.h>
#include <Library/PcdLib.h>
#include <Library/DebugLib.h>
#include <Library/MemEncryptSevLib.h>
#include "SnpPageStateChange.h"
#include "VirtualMemory.h"
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);
}
BaseAddress = OverlapRange.EndAddress;
continue;
}
// Validate the remaining pages.
NumPages = EFI_SIZE_TO_PAGES (EndAddress - BaseAddress);
InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
BaseAddress = EndAddress;
}
}