| /** @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 PEI/DXE #VC nesting. | |
| // | |
| if (SevEsData->VcCount > VMGEXIT_MAXIMUM_VC_COUNT) { | |
| VmgExitIssueAssert (SevEsData); | |
| } else if (SevEsData->VcCount > 1) { | |
| // | |
| // Nested #VC | |
| // | |
| if (SevEsData->GhcbBackupPages == NULL) { | |
| 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 *)SevEsData->GhcbBackupPages; | |
| 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; | |
| } |