CloverBootloader/OvmfPkg/Library/CcExitLib/SecCcExitVcHandler.c

110 lines
2.9 KiB
C

/** @file
X64 #VC Exception Handler functon.
Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Base.h>
#include <Uefi.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemEncryptSevLib.h>
#include <Library/CcExitLib.h>
#include <Register/Amd/Msr.h>
#include "CcExitVcHandler.h"
/**
Handle a #VC exception.
Performs the necessary processing to handle a #VC exception.
@param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
as value to use on error.
@param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
@retval EFI_SUCCESS Exception handled
@retval EFI_UNSUPPORTED #VC not supported, (new) exception value to
propagate provided
@retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to
propagate provided
**/
EFI_STATUS
EFIAPI
CcExitHandleVc (
IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
{
MSR_SEV_ES_GHCB_REGISTER Msr;
GHCB *Ghcb;
GHCB *GhcbBackup;
EFI_STATUS VcRet;
BOOLEAN InterruptState;
SEV_ES_PER_CPU_DATA *SevEsData;
InterruptState = GetInterruptState ();
if (InterruptState) {
DisableInterrupts ();
}
Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
ASSERT (Msr.GhcbInfo.Function == 0);
ASSERT (Msr.Ghcb != 0);
Ghcb = Msr.Ghcb;
GhcbBackup = NULL;
SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
SevEsData->VcCount++;
//
// Check for maximum SEC #VC nesting.
//
if (SevEsData->VcCount > VMGEXIT_MAXIMUM_VC_COUNT) {
VmgExitIssueAssert (SevEsData);
} else if (SevEsData->VcCount > 1) {
UINTN GhcbBackupSize;
//
// Be sure that the proper amount of pages are allocated
//
GhcbBackupSize = (VMGEXIT_MAXIMUM_VC_COUNT - 1) * sizeof (*Ghcb);
if (GhcbBackupSize > FixedPcdGet32 (PcdOvmfSecGhcbBackupSize)) {
//
// Not enough SEC backup pages allocated.
//
VmgExitIssueAssert (SevEsData);
}
//
// Save the active GHCB to a backup page.
// To access the correct backup page, increment the backup page pointer
// based on the current VcCount.
//
GhcbBackup = (GHCB *)FixedPcdGet32 (PcdOvmfSecGhcbBackupBase);
GhcbBackup += (SevEsData->VcCount - 2);
CopyMem (GhcbBackup, Ghcb, sizeof (*Ghcb));
}
VcRet = InternalVmgExitHandleVc (Ghcb, ExceptionType, SystemContext);
if (GhcbBackup != NULL) {
//
// Restore the active GHCB from the backup page.
//
CopyMem (Ghcb, GhcbBackup, sizeof (*Ghcb));
}
SevEsData->VcCount--;
if (InterruptState) {
EnableInterrupts ();
}
return VcRet;
}