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