BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4654 In preparation for running under an SVSM at VMPL1 or higher (higher numerically, lower privilege), re-organize the way a page state change is performed in order to free up the GHCB for use by the SVSM support. Currently, the page state change logic directly uses the GHCB shared buffer to build the page state change structures. However, this will be in conflict with the use of the GHCB should an SVSM call be required. Instead, use a separate buffer (an area in the workarea during SEC and an allocated page during PEI/DXE) to hold the page state change request and only update the GHCB shared buffer as needed. Since the information is copied to, and operated on, in the GHCB shared buffer this has the added benefit of not requiring to save the start and end entries for use when validating the memory during the page state change sequence. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Michael Roth <michael.roth@amd.com> Cc: Min Xu <min.m.xu@intel.com> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
95 lines
2.1 KiB
C
95 lines
2.1 KiB
C
/** @file
|
|
|
|
SEV-SNP Page Validation functions.
|
|
|
|
Copyright (c) 2021 - 2024, AMD Incorporated. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <Uefi/UefiBaseType.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemEncryptSevLib.h>
|
|
|
|
#include "SnpPageStateChange.h"
|
|
|
|
//
|
|
// The variable used for the VMPL check.
|
|
//
|
|
STATIC UINT8 gVmpl0Data[4096];
|
|
|
|
/**
|
|
The function checks whether SEV-SNP guest is booted under VMPL0.
|
|
|
|
@retval TRUE The guest is booted under VMPL0
|
|
@retval FALSE The guest is not booted under VMPL0
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
SevSnpIsVmpl0 (
|
|
VOID
|
|
)
|
|
{
|
|
UINT64 Rdx;
|
|
UINT32 Status;
|
|
|
|
//
|
|
// There is no straightforward way to query the current VMPL level.
|
|
// The simplest method is to use the RMPADJUST instruction to change
|
|
// a page permission to a VMPL level-1, and if the guest kernel is
|
|
// launched at a level <= 1, then RMPADJUST instruction will return
|
|
// an error.
|
|
//
|
|
Rdx = 1;
|
|
|
|
Status = AsmRmpAdjust ((UINT64)gVmpl0Data, 0, Rdx);
|
|
if (Status != 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
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
|
|
)
|
|
{
|
|
SEC_SEV_ES_WORK_AREA *SevEsWorkArea;
|
|
|
|
if (!MemEncryptSevSnpIsEnabled ()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The page state change uses the PVALIDATE instruction. The instruction
|
|
// can be run on VMPL-0 only. If its not VMPL-0 guest then terminate
|
|
// the boot.
|
|
//
|
|
if (!SevSnpIsVmpl0 ()) {
|
|
SnpPageStateFailureTerminate ();
|
|
}
|
|
|
|
SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *)FixedPcdGet32 (PcdSevEsWorkAreaBase);
|
|
|
|
InternalSetPageState (
|
|
BaseAddress,
|
|
NumPages,
|
|
SevSnpPagePrivate,
|
|
TRUE,
|
|
SevEsWorkArea->WorkBuffer,
|
|
sizeof (SevEsWorkArea->WorkBuffer)
|
|
);
|
|
}
|