--- /dev/null
+/** @file\r
+ VMGEXIT Support Library.\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/VmgExitLib.h>\r
+#include <Register/Amd/Msr.h>\r
+\r
+/**\r
+ Check for VMGEXIT error\r
+\r
+ Check if the hypervisor has returned an error after completion of the VMGEXIT\r
+ by examining the SwExitInfo1 field of the GHCB.\r
+\r
+ @param[in] Ghcb A pointer to the GHCB\r
+\r
+ @retval 0 VMGEXIT succeeded.\r
+ @return Exception number to be propagated, VMGEXIT processing\r
+ did not succeed.\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+VmgExitErrorCheck (\r
+ IN GHCB *Ghcb\r
+ )\r
+{\r
+ GHCB_EVENT_INJECTION Event;\r
+ GHCB_EXIT_INFO ExitInfo;\r
+ UINT64 Status;\r
+\r
+ ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;\r
+ ASSERT ((ExitInfo.Elements.Lower32Bits == 0) ||\r
+ (ExitInfo.Elements.Lower32Bits == 1));\r
+\r
+ Status = 0;\r
+ if (ExitInfo.Elements.Lower32Bits == 0) {\r
+ return Status;\r
+ }\r
+\r
+ if (ExitInfo.Elements.Lower32Bits == 1) {\r
+ ASSERT (Ghcb->SaveArea.SwExitInfo2 != 0);\r
+\r
+ //\r
+ // Check that the return event is valid\r
+ //\r
+ Event.Uint64 = Ghcb->SaveArea.SwExitInfo2;\r
+ if (Event.Elements.Valid &&\r
+ Event.Elements.Type == GHCB_EVENT_INJECTION_TYPE_EXCEPTION) {\r
+ switch (Event.Elements.Vector) {\r
+ case GP_EXCEPTION:\r
+ case UD_EXCEPTION:\r
+ //\r
+ // Use returned event as return code\r
+ //\r
+ Status = Event.Uint64;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Status == 0) {\r
+ GHCB_EVENT_INJECTION GpEvent;\r
+\r
+ GpEvent.Uint64 = 0;\r
+ GpEvent.Elements.Vector = GP_EXCEPTION;\r
+ GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
+ GpEvent.Elements.Valid = 1;\r
+\r
+ Status = GpEvent.Uint64;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Perform VMGEXIT.\r
+\r
+ Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and\r
+ then handles the return actions.\r
+\r
+ @param[in, out] Ghcb A pointer to the GHCB\r
+ @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode\r
+ field of the GHCB.\r
+ @param[in] ExitInfo1 VMGEXIT information to be assigned to the\r
+ SwExitInfo1 field of the GHCB.\r
+ @param[in] ExitInfo2 VMGEXIT information to be assigned to the\r
+ SwExitInfo2 field of the GHCB.\r
+\r
+ @retval 0 VMGEXIT succeeded.\r
+ @return Exception number to be propagated, VMGEXIT\r
+ processing did not succeed.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+VmgExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN UINT64 ExitCode,\r
+ IN UINT64 ExitInfo1,\r
+ IN UINT64 ExitInfo2\r
+ )\r
+{\r
+ Ghcb->SaveArea.SwExitCode = ExitCode;\r
+ Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;\r
+ Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;\r
+\r
+ //\r
+ // Guest memory is used for the guest-hypervisor communication, so fence\r
+ // the invocation of the VMGEXIT instruction to ensure GHCB accesses are\r
+ // synchronized properly.\r
+ //\r
+ MemoryFence ();\r
+ AsmVmgExit ();\r
+ MemoryFence ();\r
+\r
+ return VmgExitErrorCheck (Ghcb);\r
+}\r
+\r
+/**\r
+ Perform pre-VMGEXIT initialization/preparation.\r
+\r
+ Performs the necessary steps in preparation for invoking VMGEXIT. Must be\r
+ called before setting any fields within the GHCB.\r
+\r
+ @param[in, out] Ghcb A pointer to the GHCB\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgInit (\r
+ IN OUT GHCB *Ghcb\r
+ )\r
+{\r
+ SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);\r
+}\r
+\r
+/**\r
+ Perform post-VMGEXIT cleanup.\r
+\r
+ Performs the necessary steps to cleanup after invoking VMGEXIT. Must be\r
+ called after obtaining needed fields within the GHCB.\r
+\r
+ @param[in, out] Ghcb A pointer to the GHCB\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgDone (\r
+ IN OUT GHCB *Ghcb\r
+ )\r
+{\r
+}\r
+\r
--- /dev/null
+/** @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/VmgExitLib.h>\r
+#include <Register/Amd/Msr.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
+ EFI_SYSTEM_CONTEXT_X64 *Regs;\r
+ GHCB *Ghcb;\r
+ UINT64 ExitCode, Status;\r
+ EFI_STATUS VcRet;\r
+\r
+ VcRet = EFI_SUCCESS;\r
+\r
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+ ASSERT (Msr.GhcbInfo.Function == 0);\r
+ ASSERT (Msr.Ghcb != 0);\r
+\r
+ Regs = SystemContext.SystemContextX64;\r
+ Ghcb = Msr.Ghcb;\r
+\r
+ VmgInit (Ghcb);\r
+\r
+ ExitCode = Regs->ExceptionData;\r
+ switch (ExitCode) {\r
+ default:\r
+ Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, ExitCode, 0);\r
+ if (Status == 0) {\r
+ Regs->ExceptionData = 0;\r
+ *ExceptionType = GP_EXCEPTION;\r
+ } else {\r
+ GHCB_EVENT_INJECTION Event;\r
+\r
+ Event.Uint64 = Status;\r
+ if (Event.Elements.ErrorCodeValid != 0) {\r
+ Regs->ExceptionData = Event.Elements.ErrorCode;\r
+ } else {\r
+ Regs->ExceptionData = 0;\r
+ }\r
+\r
+ *ExceptionType = Event.Elements.Vector;\r
+ }\r
+\r
+ VcRet = EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ VmgDone (Ghcb);\r
+\r
+ return VcRet;\r
+}\r