\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf\r
TdxLib|MdePkg/Library/TdxLib/TdxLib.inf\r
\r
[LibraryClasses.common.SEC]\r
!else\r
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
!endif\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf\r
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf\r
\r
[LibraryClasses.common.PEI_CORE]\r
\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
TdxLib|MdePkg/Library/TdxLib/TdxLib.inf\r
\r
[LibraryClasses.common.SEC]\r
\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf\r
TdxLib|MdePkg/Library/TdxLib/TdxLib.inf\r
\r
[LibraryClasses.common.SEC]\r
!else\r
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
!endif\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf\r
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf\r
\r
[LibraryClasses.common.PEI_CORE]\r
#\r
OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf {\r
<LibraryClasses>\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
}\r
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf\r
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {\r
\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf\r
TdxLib|MdePkg/Library/TdxLib/TdxLib.inf\r
TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf\r
PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf\r
!else\r
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
!endif\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf\r
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf\r
PrePiHobListPointerLib|OvmfPkg/IntelTdx/PrePiHobListPointerLibTdx/PrePiHobListPointerLibTdx.inf\r
HobLib|EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf\r
DebugLib\r
MemoryAllocationLib\r
PcdLib\r
- VmgExitLib\r
+ CcExitLib\r
\r
[FeaturePcd]\r
gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire\r
DebugLib\r
MemoryAllocationLib\r
PcdLib\r
- VmgExitLib\r
+ CcExitLib\r
\r
[FeaturePcd]\r
gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire\r
CpuLib\r
DebugLib\r
PcdLib\r
- VmgExitLib\r
+ CcExitLib\r
\r
[FixedPcd]\r
gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/MemEncryptSevLib.h>\r
#include <Library/DebugLib.h>\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
\r
#include <Register/Amd/Ghcb.h>\r
#include <Register/Amd/Msr.h>\r
--- /dev/null
+/** @file\r
+ CcExitLib Support Library.\r
+\r
+ Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+ Copyright (C) 2020 - 2022, Intel Corporation. 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/CcExitLib.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 (\r
+ (ExitInfo.Elements.Lower32Bits == 0) ||\r
+ (ExitInfo.Elements.Lower32Bits == 1)\r
+ );\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
+ {\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
+ VmgSetOffsetValid (Ghcb, GhcbSwExitCode);\r
+ VmgSetOffsetValid (Ghcb, GhcbSwExitInfo1);\r
+ VmgSetOffsetValid (Ghcb, GhcbSwExitInfo2);\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
+ @param[in, out] InterruptState A pointer to hold the current interrupt\r
+ state, used for restoring in VmgDone ()\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgInit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT BOOLEAN *InterruptState\r
+ )\r
+{\r
+ //\r
+ // Be sure that an interrupt can't cause a #VC while the GHCB is\r
+ // being used.\r
+ //\r
+ *InterruptState = GetInterruptState ();\r
+ if (*InterruptState) {\r
+ DisableInterrupts ();\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
+ @param[in] InterruptState An indicator to conditionally (re)enable\r
+ interrupts\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgDone (\r
+ IN OUT GHCB *Ghcb,\r
+ IN BOOLEAN InterruptState\r
+ )\r
+{\r
+ if (InterruptState) {\r
+ EnableInterrupts ();\r
+ }\r
+}\r
+\r
+/**\r
+ Marks a field at the specified offset as valid in the GHCB.\r
+\r
+ The ValidBitmap area represents the areas of the GHCB that have been marked\r
+ valid. Set the bit in ValidBitmap for the input offset.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
+ @param[in] Offset Qword offset in the GHCB to mark valid\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgSetOffsetValid (\r
+ IN OUT GHCB *Ghcb,\r
+ IN GHCB_REGISTER Offset\r
+ )\r
+{\r
+ UINT32 OffsetIndex;\r
+ UINT32 OffsetBit;\r
+\r
+ OffsetIndex = Offset / 8;\r
+ OffsetBit = Offset % 8;\r
+\r
+ Ghcb->SaveArea.ValidBitmap[OffsetIndex] |= (1 << OffsetBit);\r
+}\r
+\r
+/**\r
+ Checks if a specified offset is valid in the GHCB.\r
+\r
+ The ValidBitmap area represents the areas of the GHCB that have been marked\r
+ valid. Return whether the bit in the ValidBitmap is set for the input offset.\r
+\r
+ @param[in] Ghcb A pointer to the GHCB\r
+ @param[in] Offset Qword offset in the GHCB to mark valid\r
+\r
+ @retval TRUE Offset is marked valid in the GHCB\r
+ @retval FALSE Offset is not marked valid in the GHCB\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+VmgIsOffsetValid (\r
+ IN GHCB *Ghcb,\r
+ IN GHCB_REGISTER Offset\r
+ )\r
+{\r
+ UINT32 OffsetIndex;\r
+ UINT32 OffsetBit;\r
+\r
+ OffsetIndex = Offset / 8;\r
+ OffsetBit = Offset % 8;\r
+\r
+ return ((Ghcb->SaveArea.ValidBitmap[OffsetIndex] & (1 << OffsetBit)) != 0);\r
+}\r
--- /dev/null
+## @file\r
+# CcExitLib Library.\r
+#\r
+# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+# Copyright (C) 2020 - 2022, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = CcExitLib\r
+ FILE_GUID = 0e923c25-13cd-430b-8714-ffe85652a97b\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = CcExitLib|PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = X64\r
+#\r
+\r
+[Sources.common]\r
+ CcExitLib.c\r
+ CcExitVcHandler.c\r
+ CcExitVcHandler.h\r
+ PeiDxeCcExitVcHandler.c\r
+ CcExitVeHandler.c\r
+ X64/TdVmcallCpuid.nasm\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ OvmfPkg/OvmfPkg.dec\r
+ UefiCpuPkg/UefiCpuPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ LocalApicLib\r
+ MemEncryptSevLib\r
+\r
+[Pcd]\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef CC_EXIT_TD_H_\r
+#define CC_EXIT_TD_H_\r
+\r
+#include <Base.h>\r
+#include <Uefi.h>\r
+\r
+/**\r
+ This function enable the TD guest to request the VMM to emulate CPUID\r
+ operation, especially for non-architectural, CPUID leaves.\r
+\r
+ @param[in] Eax Main leaf of the CPUID\r
+ @param[in] Ecx Sub-leaf of the CPUID\r
+ @param[out] Results Returned result of CPUID operation\r
+\r
+ @return EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TdVmCallCpuid (\r
+ IN UINT64 Eax,\r
+ IN UINT64 Ecx,\r
+ OUT VOID *Results\r
+ );\r
+\r
+#endif\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/LocalApicLib.h>\r
+#include <Library/MemEncryptSevLib.h>\r
+#include <Library/CcExitLib.h>\r
+#include <Register/Amd/Msr.h>\r
+#include <Register/Intel/Cpuid.h>\r
+#include <IndustryStandard/InstructionParsing.h>\r
+\r
+#include "CcExitVcHandler.h"\r
+\r
+//\r
+// Instruction execution mode definition\r
+//\r
+typedef enum {\r
+ LongMode64Bit = 0,\r
+ LongModeCompat32Bit,\r
+ LongModeCompat16Bit,\r
+} SEV_ES_INSTRUCTION_MODE;\r
+\r
+//\r
+// Instruction size definition (for operand and address)\r
+//\r
+typedef enum {\r
+ Size8Bits = 0,\r
+ Size16Bits,\r
+ Size32Bits,\r
+ Size64Bits,\r
+} SEV_ES_INSTRUCTION_SIZE;\r
+\r
+//\r
+// Intruction segment definition\r
+//\r
+typedef enum {\r
+ SegmentEs = 0,\r
+ SegmentCs,\r
+ SegmentSs,\r
+ SegmentDs,\r
+ SegmentFs,\r
+ SegmentGs,\r
+} SEV_ES_INSTRUCTION_SEGMENT;\r
+\r
+//\r
+// Instruction rep function definition\r
+//\r
+typedef enum {\r
+ RepNone = 0,\r
+ RepZ,\r
+ RepNZ,\r
+} SEV_ES_INSTRUCTION_REP;\r
+\r
+typedef struct {\r
+ UINT8 Rm;\r
+ UINT8 Reg;\r
+ UINT8 Mod;\r
+} SEV_ES_INSTRUCTION_MODRM_EXT;\r
+\r
+typedef struct {\r
+ UINT8 Base;\r
+ UINT8 Index;\r
+ UINT8 Scale;\r
+} SEV_ES_INSTRUCTION_SIB_EXT;\r
+\r
+//\r
+// Instruction opcode definition\r
+//\r
+typedef struct {\r
+ SEV_ES_INSTRUCTION_MODRM_EXT ModRm;\r
+\r
+ SEV_ES_INSTRUCTION_SIB_EXT Sib;\r
+\r
+ UINTN RegData;\r
+ UINTN RmData;\r
+} SEV_ES_INSTRUCTION_OPCODE_EXT;\r
+\r
+//\r
+// Instruction parsing context definition\r
+//\r
+typedef struct {\r
+ GHCB *Ghcb;\r
+\r
+ SEV_ES_INSTRUCTION_MODE Mode;\r
+ SEV_ES_INSTRUCTION_SIZE DataSize;\r
+ SEV_ES_INSTRUCTION_SIZE AddrSize;\r
+ BOOLEAN SegmentSpecified;\r
+ SEV_ES_INSTRUCTION_SEGMENT Segment;\r
+ SEV_ES_INSTRUCTION_REP RepMode;\r
+\r
+ UINT8 *Begin;\r
+ UINT8 *End;\r
+\r
+ UINT8 *Prefixes;\r
+ UINT8 *OpCodes;\r
+ UINT8 *Displacement;\r
+ UINT8 *Immediate;\r
+\r
+ INSTRUCTION_REX_PREFIX RexPrefix;\r
+\r
+ BOOLEAN ModRmPresent;\r
+ INSTRUCTION_MODRM ModRm;\r
+\r
+ BOOLEAN SibPresent;\r
+ INSTRUCTION_SIB Sib;\r
+\r
+ UINTN PrefixSize;\r
+ UINTN OpCodeSize;\r
+ UINTN DisplacementSize;\r
+ UINTN ImmediateSize;\r
+\r
+ SEV_ES_INSTRUCTION_OPCODE_EXT Ext;\r
+} SEV_ES_INSTRUCTION_DATA;\r
+\r
+//\r
+// Non-automatic Exit function prototype\r
+//\r
+typedef\r
+UINT64\r
+(*NAE_EXIT) (\r
+ GHCB *Ghcb,\r
+ EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ );\r
+\r
+//\r
+// SEV-SNP Cpuid table entry/function\r
+//\r
+typedef PACKED struct {\r
+ UINT32 EaxIn;\r
+ UINT32 EcxIn;\r
+ UINT64 Unused;\r
+ UINT64 Unused2;\r
+ UINT32 Eax;\r
+ UINT32 Ebx;\r
+ UINT32 Ecx;\r
+ UINT32 Edx;\r
+ UINT64 Reserved;\r
+} SEV_SNP_CPUID_FUNCTION;\r
+\r
+//\r
+// SEV-SNP Cpuid page format\r
+//\r
+typedef PACKED struct {\r
+ UINT32 Count;\r
+ UINT32 Reserved1;\r
+ UINT64 Reserved2;\r
+ SEV_SNP_CPUID_FUNCTION function[0];\r
+} SEV_SNP_CPUID_INFO;\r
+\r
+/**\r
+ Return a pointer to the contents of the specified register.\r
+\r
+ Based upon the input register, return a pointer to the registers contents\r
+ in the x86 processor context.\r
+\r
+ @param[in] Regs x64 processor context\r
+ @param[in] Register Register to obtain pointer for\r
+\r
+ @return Pointer to the contents of the requested register\r
+\r
+**/\r
+STATIC\r
+UINT64 *\r
+GetRegisterPointer (\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN UINT8 Register\r
+ )\r
+{\r
+ UINT64 *Reg;\r
+\r
+ switch (Register) {\r
+ case 0:\r
+ Reg = &Regs->Rax;\r
+ break;\r
+ case 1:\r
+ Reg = &Regs->Rcx;\r
+ break;\r
+ case 2:\r
+ Reg = &Regs->Rdx;\r
+ break;\r
+ case 3:\r
+ Reg = &Regs->Rbx;\r
+ break;\r
+ case 4:\r
+ Reg = &Regs->Rsp;\r
+ break;\r
+ case 5:\r
+ Reg = &Regs->Rbp;\r
+ break;\r
+ case 6:\r
+ Reg = &Regs->Rsi;\r
+ break;\r
+ case 7:\r
+ Reg = &Regs->Rdi;\r
+ break;\r
+ case 8:\r
+ Reg = &Regs->R8;\r
+ break;\r
+ case 9:\r
+ Reg = &Regs->R9;\r
+ break;\r
+ case 10:\r
+ Reg = &Regs->R10;\r
+ break;\r
+ case 11:\r
+ Reg = &Regs->R11;\r
+ break;\r
+ case 12:\r
+ Reg = &Regs->R12;\r
+ break;\r
+ case 13:\r
+ Reg = &Regs->R13;\r
+ break;\r
+ case 14:\r
+ Reg = &Regs->R14;\r
+ break;\r
+ case 15:\r
+ Reg = &Regs->R15;\r
+ break;\r
+ default:\r
+ Reg = NULL;\r
+ }\r
+\r
+ ASSERT (Reg != NULL);\r
+\r
+ return Reg;\r
+}\r
+\r
+/**\r
+ Update the instruction parsing context for displacement bytes.\r
+\r
+ @param[in, out] InstructionData Instruction parsing context\r
+ @param[in] Size The instruction displacement size\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UpdateForDisplacement (\r
+ IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ InstructionData->DisplacementSize = Size;\r
+ InstructionData->Immediate += Size;\r
+ InstructionData->End += Size;\r
+}\r
+\r
+/**\r
+ Determine if an instruction address if RIP relative.\r
+\r
+ Examine the instruction parsing context to determine if the address offset\r
+ is relative to the instruction pointer.\r
+\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval TRUE Instruction addressing is RIP relative\r
+ @retval FALSE Instruction addressing is not RIP relative\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsRipRelative (\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
+\r
+ Ext = &InstructionData->Ext;\r
+\r
+ return ((InstructionData->Mode == LongMode64Bit) &&\r
+ (Ext->ModRm.Mod == 0) &&\r
+ (Ext->ModRm.Rm == 5) &&\r
+ (InstructionData->SibPresent == FALSE));\r
+}\r
+\r
+/**\r
+ Return the effective address of a memory operand.\r
+\r
+ Examine the instruction parsing context to obtain the effective memory\r
+ address of a memory operand.\r
+\r
+ @param[in] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @return The memory operand effective address\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+GetEffectiveMemoryAddress (\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
+ UINT64 EffectiveAddress;\r
+\r
+ Ext = &InstructionData->Ext;\r
+ EffectiveAddress = 0;\r
+\r
+ if (IsRipRelative (InstructionData)) {\r
+ //\r
+ // RIP-relative displacement is a 32-bit signed value\r
+ //\r
+ INT32 RipRelative;\r
+\r
+ RipRelative = *(INT32 *)InstructionData->Displacement;\r
+\r
+ UpdateForDisplacement (InstructionData, 4);\r
+\r
+ //\r
+ // Negative displacement is handled by standard UINT64 wrap-around.\r
+ //\r
+ return Regs->Rip + (UINT64)RipRelative;\r
+ }\r
+\r
+ switch (Ext->ModRm.Mod) {\r
+ case 1:\r
+ UpdateForDisplacement (InstructionData, 1);\r
+ EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement));\r
+ break;\r
+ case 2:\r
+ switch (InstructionData->AddrSize) {\r
+ case Size16Bits:\r
+ UpdateForDisplacement (InstructionData, 2);\r
+ EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement));\r
+ break;\r
+ default:\r
+ UpdateForDisplacement (InstructionData, 4);\r
+ EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
+ break;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ if (InstructionData->SibPresent) {\r
+ INT64 Displacement;\r
+\r
+ if (Ext->Sib.Index != 4) {\r
+ CopyMem (\r
+ &Displacement,\r
+ GetRegisterPointer (Regs, Ext->Sib.Index),\r
+ sizeof (Displacement)\r
+ );\r
+ Displacement *= (INT64)(1 << Ext->Sib.Scale);\r
+\r
+ //\r
+ // Negative displacement is handled by standard UINT64 wrap-around.\r
+ //\r
+ EffectiveAddress += (UINT64)Displacement;\r
+ }\r
+\r
+ if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {\r
+ EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);\r
+ } else {\r
+ UpdateForDisplacement (InstructionData, 4);\r
+ EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
+ }\r
+ } else {\r
+ EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+ }\r
+\r
+ return EffectiveAddress;\r
+}\r
+\r
+/**\r
+ Decode a ModRM byte.\r
+\r
+ Examine the instruction parsing context to decode a ModRM byte and the SIB\r
+ byte, if present.\r
+\r
+ @param[in] Regs x64 processor context\r
+ @param[in, out] InstructionData Instruction parsing context\r
+\r
+**/\r
+STATIC\r
+VOID\r
+DecodeModRm (\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
+ INSTRUCTION_REX_PREFIX *RexPrefix;\r
+ INSTRUCTION_MODRM *ModRm;\r
+ INSTRUCTION_SIB *Sib;\r
+\r
+ RexPrefix = &InstructionData->RexPrefix;\r
+ Ext = &InstructionData->Ext;\r
+ ModRm = &InstructionData->ModRm;\r
+ Sib = &InstructionData->Sib;\r
+\r
+ InstructionData->ModRmPresent = TRUE;\r
+ ModRm->Uint8 = *(InstructionData->End);\r
+\r
+ InstructionData->Displacement++;\r
+ InstructionData->Immediate++;\r
+ InstructionData->End++;\r
+\r
+ Ext->ModRm.Mod = ModRm->Bits.Mod;\r
+ Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg;\r
+ Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm;\r
+\r
+ Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);\r
+\r
+ if (Ext->ModRm.Mod == 3) {\r
+ Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+ } else {\r
+ if (ModRm->Bits.Rm == 4) {\r
+ InstructionData->SibPresent = TRUE;\r
+ Sib->Uint8 = *(InstructionData->End);\r
+\r
+ InstructionData->Displacement++;\r
+ InstructionData->Immediate++;\r
+ InstructionData->End++;\r
+\r
+ Ext->Sib.Scale = Sib->Bits.Scale;\r
+ Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index;\r
+ Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base;\r
+ }\r
+\r
+ Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);\r
+ }\r
+}\r
+\r
+/**\r
+ Decode instruction prefixes.\r
+\r
+ Parse the instruction data to track the instruction prefixes that have\r
+ been used.\r
+\r
+ @param[in] Regs x64 processor context\r
+ @param[in, out] InstructionData Instruction parsing context\r
+\r
+**/\r
+STATIC\r
+VOID\r
+DecodePrefixes (\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ SEV_ES_INSTRUCTION_MODE Mode;\r
+ SEV_ES_INSTRUCTION_SIZE ModeDataSize;\r
+ SEV_ES_INSTRUCTION_SIZE ModeAddrSize;\r
+ UINT8 *Byte;\r
+\r
+ //\r
+ // Always in 64-bit mode\r
+ //\r
+ Mode = LongMode64Bit;\r
+ ModeDataSize = Size32Bits;\r
+ ModeAddrSize = Size64Bits;\r
+\r
+ InstructionData->Mode = Mode;\r
+ InstructionData->DataSize = ModeDataSize;\r
+ InstructionData->AddrSize = ModeAddrSize;\r
+\r
+ InstructionData->Prefixes = InstructionData->Begin;\r
+\r
+ Byte = InstructionData->Prefixes;\r
+ for ( ; ; Byte++, InstructionData->PrefixSize++) {\r
+ //\r
+ // Check the 0x40 to 0x4F range using an if statement here since some\r
+ // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids\r
+ // 16 case statements below.\r
+ //\r
+ if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {\r
+ InstructionData->RexPrefix.Uint8 = *Byte;\r
+ if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {\r
+ InstructionData->DataSize = Size64Bits;\r
+ }\r
+\r
+ continue;\r
+ }\r
+\r
+ switch (*Byte) {\r
+ case OVERRIDE_SEGMENT_CS:\r
+ case OVERRIDE_SEGMENT_DS:\r
+ case OVERRIDE_SEGMENT_ES:\r
+ case OVERRIDE_SEGMENT_SS:\r
+ if (Mode != LongMode64Bit) {\r
+ InstructionData->SegmentSpecified = TRUE;\r
+ InstructionData->Segment = (*Byte >> 3) & 3;\r
+ }\r
+\r
+ break;\r
+\r
+ case OVERRIDE_SEGMENT_FS:\r
+ case OVERRIDE_SEGMENT_GS:\r
+ InstructionData->SegmentSpecified = TRUE;\r
+ InstructionData->Segment = *Byte & 7;\r
+ break;\r
+\r
+ case OVERRIDE_OPERAND_SIZE:\r
+ if (InstructionData->RexPrefix.Uint8 == 0) {\r
+ InstructionData->DataSize =\r
+ (Mode == LongMode64Bit) ? Size16Bits :\r
+ (Mode == LongModeCompat32Bit) ? Size16Bits :\r
+ (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
+ }\r
+\r
+ break;\r
+\r
+ case OVERRIDE_ADDRESS_SIZE:\r
+ InstructionData->AddrSize =\r
+ (Mode == LongMode64Bit) ? Size32Bits :\r
+ (Mode == LongModeCompat32Bit) ? Size16Bits :\r
+ (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
+ break;\r
+\r
+ case LOCK_PREFIX:\r
+ break;\r
+\r
+ case REPZ_PREFIX:\r
+ InstructionData->RepMode = RepZ;\r
+ break;\r
+\r
+ case REPNZ_PREFIX:\r
+ InstructionData->RepMode = RepNZ;\r
+ break;\r
+\r
+ default:\r
+ InstructionData->OpCodes = Byte;\r
+ InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;\r
+\r
+ InstructionData->End = Byte + InstructionData->OpCodeSize;\r
+ InstructionData->Displacement = InstructionData->End;\r
+ InstructionData->Immediate = InstructionData->End;\r
+ return;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Determine instruction length\r
+\r
+ Return the total length of the parsed instruction.\r
+\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @return Length of parsed instruction\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+InstructionLength (\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ return (UINT64)(InstructionData->End - InstructionData->Begin);\r
+}\r
+\r
+/**\r
+ Initialize the instruction parsing context.\r
+\r
+ Initialize the instruction parsing context, which includes decoding the\r
+ instruction prefixes.\r
+\r
+ @param[in, out] InstructionData Instruction parsing context\r
+ @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in] Regs x64 processor context\r
+\r
+**/\r
+STATIC\r
+VOID\r
+InitInstructionData (\r
+ IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
+ IN GHCB *Ghcb,\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs\r
+ )\r
+{\r
+ SetMem (InstructionData, sizeof (*InstructionData), 0);\r
+ InstructionData->Ghcb = Ghcb;\r
+ InstructionData->Begin = (UINT8 *)Regs->Rip;\r
+ InstructionData->End = (UINT8 *)Regs->Rip;\r
+\r
+ DecodePrefixes (Regs, InstructionData);\r
+}\r
+\r
+/**\r
+ Report an unsupported event to the hypervisor\r
+\r
+ Use the VMGEXIT support to report an unsupported event to the hypervisor.\r
+\r
+ @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+UnsupportedExit (\r
+ IN GHCB *Ghcb,\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 Status;\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);\r
+ if (Status == 0) {\r
+ GHCB_EVENT_INJECTION Event;\r
+\r
+ Event.Uint64 = 0;\r
+ Event.Elements.Vector = GP_EXCEPTION;\r
+ Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
+ Event.Elements.Valid = 1;\r
+\r
+ Status = Event.Uint64;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Validate that the MMIO memory access is not to encrypted memory.\r
+\r
+ Examine the pagetable entry for the memory specified. MMIO should not be\r
+ performed against encrypted memory. MMIO to the APIC page is always allowed.\r
+\r
+ @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
+ @param[in] MemoryAddress Memory address to validate\r
+ @param[in] MemoryLength Memory length to validate\r
+\r
+ @retval 0 Memory is not encrypted\r
+ @return New exception value to propogate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+ValidateMmioMemory (\r
+ IN GHCB *Ghcb,\r
+ IN UINTN MemoryAddress,\r
+ IN UINTN MemoryLength\r
+ )\r
+{\r
+ MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;\r
+ GHCB_EVENT_INJECTION GpEvent;\r
+ UINTN Address;\r
+\r
+ //\r
+ // Allow APIC accesses (which will have the encryption bit set during\r
+ // SEC and PEI phases).\r
+ //\r
+ Address = MemoryAddress & ~(SIZE_4KB - 1);\r
+ if (Address == GetLocalApicBaseAddress ()) {\r
+ return 0;\r
+ }\r
+\r
+ State = MemEncryptSevGetAddressRangeState (\r
+ 0,\r
+ MemoryAddress,\r
+ MemoryLength\r
+ );\r
+ if (State == MemEncryptSevAddressRangeUnencrypted) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Any state other than unencrypted is an error, issue a #GP.\r
+ //\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "MMIO using encrypted memory: %lx\n",\r
+ (UINT64)MemoryAddress\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
+ return GpEvent.Uint64;\r
+}\r
+\r
+/**\r
+ Handle an MMIO event.\r
+\r
+ Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in, out] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+MmioExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 ExitInfo1, ExitInfo2, Status;\r
+ UINTN Bytes;\r
+ UINT64 *Register;\r
+ UINT8 OpCode, SignByte;\r
+ UINTN Address;\r
+\r
+ Bytes = 0;\r
+\r
+ OpCode = *(InstructionData->OpCodes);\r
+ if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {\r
+ OpCode = *(InstructionData->OpCodes + 1);\r
+ }\r
+\r
+ switch (OpCode) {\r
+ //\r
+ // MMIO write (MOV reg/memX, regX)\r
+ //\r
+ case 0x88:\r
+ Bytes = 1;\r
+ //\r
+ // fall through\r
+ //\r
+ case 0x89:\r
+ DecodeModRm (Regs, InstructionData);\r
+ Bytes = ((Bytes != 0) ? Bytes :\r
+ (InstructionData->DataSize == Size16Bits) ? 2 :\r
+ (InstructionData->DataSize == Size32Bits) ? 4 :\r
+ (InstructionData->DataSize == Size64Bits) ? 8 :\r
+ 0);\r
+\r
+ if (InstructionData->Ext.ModRm.Mod == 3) {\r
+ //\r
+ // NPF on two register operands???\r
+ //\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ ExitInfo1 = InstructionData->Ext.RmData;\r
+ ExitInfo2 = Bytes;\r
+ CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);\r
+\r
+ Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+ Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // MMIO write (MOV moffsetX, aX)\r
+ //\r
+ case 0xA2:\r
+ Bytes = 1;\r
+ //\r
+ // fall through\r
+ //\r
+ case 0xA3:\r
+ Bytes = ((Bytes != 0) ? Bytes :\r
+ (InstructionData->DataSize == Size16Bits) ? 2 :\r
+ (InstructionData->DataSize == Size32Bits) ? 4 :\r
+ (InstructionData->DataSize == Size64Bits) ? 8 :\r
+ 0);\r
+\r
+ InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
+ InstructionData->End += InstructionData->ImmediateSize;\r
+\r
+ //\r
+ // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
+ // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
+ //\r
+ STATIC_ASSERT (\r
+ sizeof (UINTN) == sizeof (UINT64),\r
+ "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
+ );\r
+\r
+ Address = 0;\r
+ CopyMem (\r
+ &Address,\r
+ InstructionData->Immediate,\r
+ InstructionData->ImmediateSize\r
+ );\r
+\r
+ Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ ExitInfo1 = Address;\r
+ ExitInfo2 = Bytes;\r
+ CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);\r
+\r
+ Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+ Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // MMIO write (MOV reg/memX, immX)\r
+ //\r
+ case 0xC6:\r
+ Bytes = 1;\r
+ //\r
+ // fall through\r
+ //\r
+ case 0xC7:\r
+ DecodeModRm (Regs, InstructionData);\r
+ Bytes = ((Bytes != 0) ? Bytes :\r
+ (InstructionData->DataSize == Size16Bits) ? 2 :\r
+ (InstructionData->DataSize == Size32Bits) ? 4 :\r
+ 0);\r
+\r
+ InstructionData->ImmediateSize = Bytes;\r
+ InstructionData->End += Bytes;\r
+\r
+ Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ ExitInfo1 = InstructionData->Ext.RmData;\r
+ ExitInfo2 = Bytes;\r
+ CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);\r
+\r
+ Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+ Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // MMIO read (MOV regX, reg/memX)\r
+ //\r
+ case 0x8A:\r
+ Bytes = 1;\r
+ //\r
+ // fall through\r
+ //\r
+ case 0x8B:\r
+ DecodeModRm (Regs, InstructionData);\r
+ Bytes = ((Bytes != 0) ? Bytes :\r
+ (InstructionData->DataSize == Size16Bits) ? 2 :\r
+ (InstructionData->DataSize == Size32Bits) ? 4 :\r
+ (InstructionData->DataSize == Size64Bits) ? 8 :\r
+ 0);\r
+ if (InstructionData->Ext.ModRm.Mod == 3) {\r
+ //\r
+ // NPF on two register operands???\r
+ //\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ ExitInfo1 = InstructionData->Ext.RmData;\r
+ ExitInfo2 = Bytes;\r
+\r
+ Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+ Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+ if (Bytes == 4) {\r
+ //\r
+ // Zero-extend for 32-bit operation\r
+ //\r
+ *Register = 0;\r
+ }\r
+\r
+ CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
+ break;\r
+\r
+ //\r
+ // MMIO read (MOV aX, moffsetX)\r
+ //\r
+ case 0xA0:\r
+ Bytes = 1;\r
+ //\r
+ // fall through\r
+ //\r
+ case 0xA1:\r
+ Bytes = ((Bytes != 0) ? Bytes :\r
+ (InstructionData->DataSize == Size16Bits) ? 2 :\r
+ (InstructionData->DataSize == Size32Bits) ? 4 :\r
+ (InstructionData->DataSize == Size64Bits) ? 8 :\r
+ 0);\r
+\r
+ InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
+ InstructionData->End += InstructionData->ImmediateSize;\r
+\r
+ //\r
+ // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
+ // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
+ //\r
+ STATIC_ASSERT (\r
+ sizeof (UINTN) == sizeof (UINT64),\r
+ "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
+ );\r
+\r
+ Address = 0;\r
+ CopyMem (\r
+ &Address,\r
+ InstructionData->Immediate,\r
+ InstructionData->ImmediateSize\r
+ );\r
+\r
+ Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ ExitInfo1 = Address;\r
+ ExitInfo2 = Bytes;\r
+\r
+ Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+ Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if (Bytes == 4) {\r
+ //\r
+ // Zero-extend for 32-bit operation\r
+ //\r
+ Regs->Rax = 0;\r
+ }\r
+\r
+ CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);\r
+ break;\r
+\r
+ //\r
+ // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)\r
+ //\r
+ case 0xB6:\r
+ Bytes = 1;\r
+ //\r
+ // fall through\r
+ //\r
+ case 0xB7:\r
+ DecodeModRm (Regs, InstructionData);\r
+ Bytes = (Bytes != 0) ? Bytes : 2;\r
+\r
+ Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ ExitInfo1 = InstructionData->Ext.RmData;\r
+ ExitInfo2 = Bytes;\r
+\r
+ Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+ Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+ SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);\r
+ CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
+ break;\r
+\r
+ //\r
+ // MMIO read w/ sign-extension (MOVSX regX, reg/memX)\r
+ //\r
+ case 0xBE:\r
+ Bytes = 1;\r
+ //\r
+ // fall through\r
+ //\r
+ case 0xBF:\r
+ DecodeModRm (Regs, InstructionData);\r
+ Bytes = (Bytes != 0) ? Bytes : 2;\r
+\r
+ Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ ExitInfo1 = InstructionData->Ext.RmData;\r
+ ExitInfo2 = Bytes;\r
+\r
+ Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+ Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if (Bytes == 1) {\r
+ UINT8 *Data;\r
+\r
+ Data = (UINT8 *)Ghcb->SharedBuffer;\r
+ SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;\r
+ } else {\r
+ UINT16 *Data;\r
+\r
+ Data = (UINT16 *)Ghcb->SharedBuffer;\r
+ SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;\r
+ }\r
+\r
+ Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+ SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);\r
+ CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
+ break;\r
+\r
+ default:\r
+ DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));\r
+ Status = GP_EXCEPTION;\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Handle a MWAIT event.\r
+\r
+ Use the VMGEXIT instruction to handle a MWAIT event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+MwaitExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ Ghcb->SaveArea.Rax = Regs->Rax;\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+ Ghcb->SaveArea.Rcx = Regs->Rcx;\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
+\r
+ return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);\r
+}\r
+\r
+/**\r
+ Handle a MONITOR event.\r
+\r
+ Use the VMGEXIT instruction to handle a MONITOR event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+MonitorExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+ Ghcb->SaveArea.Rcx = Regs->Rcx;\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
+ Ghcb->SaveArea.Rdx = Regs->Rdx;\r
+ VmgSetOffsetValid (Ghcb, GhcbRdx);\r
+\r
+ return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);\r
+}\r
+\r
+/**\r
+ Handle a WBINVD event.\r
+\r
+ Use the VMGEXIT instruction to handle a WBINVD event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+WbinvdExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);\r
+}\r
+\r
+/**\r
+ Handle a RDTSCP event.\r
+\r
+ Use the VMGEXIT instruction to handle a RDTSCP event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+RdtscpExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 Status;\r
+\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
+ {\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ Regs->Rax = Ghcb->SaveArea.Rax;\r
+ Regs->Rcx = Ghcb->SaveArea.Rcx;\r
+ Regs->Rdx = Ghcb->SaveArea.Rdx;\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Handle a VMMCALL event.\r
+\r
+ Use the VMGEXIT instruction to handle a VMMCALL event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+VmmCallExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 Status;\r
+\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ Ghcb->SaveArea.Rax = Regs->Rax;\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+ Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);\r
+ VmgSetOffsetValid (Ghcb, GhcbCpl);\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ Regs->Rax = Ghcb->SaveArea.Rax;\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Handle an MSR event.\r
+\r
+ Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+MsrExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 ExitInfo1, Status;\r
+\r
+ ExitInfo1 = 0;\r
+\r
+ switch (*(InstructionData->OpCodes + 1)) {\r
+ case 0x30: // WRMSR\r
+ ExitInfo1 = 1;\r
+ Ghcb->SaveArea.Rax = Regs->Rax;\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+ Ghcb->SaveArea.Rdx = Regs->Rdx;\r
+ VmgSetOffsetValid (Ghcb, GhcbRdx);\r
+ //\r
+ // fall through\r
+ //\r
+ case 0x32: // RDMSR\r
+ Ghcb->SaveArea.Rcx = Regs->Rcx;\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
+ break;\r
+ default:\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if (ExitInfo1 == 0) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
+ {\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ Regs->Rax = Ghcb->SaveArea.Rax;\r
+ Regs->Rdx = Ghcb->SaveArea.Rdx;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Build the IOIO event information.\r
+\r
+ The IOIO event information identifies the type of IO operation to be performed\r
+ by the hypervisor. Build this information based on the instruction data.\r
+\r
+ @param[in] Regs x64 processor context\r
+ @param[in, out] InstructionData Instruction parsing context\r
+\r
+ @return IOIO event information value\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+IoioExitInfo (\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 ExitInfo;\r
+\r
+ ExitInfo = 0;\r
+\r
+ switch (*(InstructionData->OpCodes)) {\r
+ //\r
+ // INS opcodes\r
+ //\r
+ case 0x6C:\r
+ case 0x6D:\r
+ ExitInfo |= IOIO_TYPE_INS;\r
+ ExitInfo |= IOIO_SEG_ES;\r
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
+ break;\r
+\r
+ //\r
+ // OUTS opcodes\r
+ //\r
+ case 0x6E:\r
+ case 0x6F:\r
+ ExitInfo |= IOIO_TYPE_OUTS;\r
+ ExitInfo |= IOIO_SEG_DS;\r
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
+ break;\r
+\r
+ //\r
+ // IN immediate opcodes\r
+ //\r
+ case 0xE4:\r
+ case 0xE5:\r
+ InstructionData->ImmediateSize = 1;\r
+ InstructionData->End++;\r
+ ExitInfo |= IOIO_TYPE_IN;\r
+ ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);\r
+ break;\r
+\r
+ //\r
+ // OUT immediate opcodes\r
+ //\r
+ case 0xE6:\r
+ case 0xE7:\r
+ InstructionData->ImmediateSize = 1;\r
+ InstructionData->End++;\r
+ ExitInfo |= IOIO_TYPE_OUT;\r
+ ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;\r
+ break;\r
+\r
+ //\r
+ // IN register opcodes\r
+ //\r
+ case 0xEC:\r
+ case 0xED:\r
+ ExitInfo |= IOIO_TYPE_IN;\r
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
+ break;\r
+\r
+ //\r
+ // OUT register opcodes\r
+ //\r
+ case 0xEE:\r
+ case 0xEF:\r
+ ExitInfo |= IOIO_TYPE_OUT;\r
+ ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
+ break;\r
+\r
+ default:\r
+ return 0;\r
+ }\r
+\r
+ switch (*(InstructionData->OpCodes)) {\r
+ //\r
+ // Single-byte opcodes\r
+ //\r
+ case 0x6C:\r
+ case 0x6E:\r
+ case 0xE4:\r
+ case 0xE6:\r
+ case 0xEC:\r
+ case 0xEE:\r
+ ExitInfo |= IOIO_DATA_8;\r
+ break;\r
+\r
+ //\r
+ // Length determined by instruction parsing\r
+ //\r
+ default:\r
+ ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16\r
+ : IOIO_DATA_32;\r
+ }\r
+\r
+ switch (InstructionData->AddrSize) {\r
+ case Size16Bits:\r
+ ExitInfo |= IOIO_ADDR_16;\r
+ break;\r
+\r
+ case Size32Bits:\r
+ ExitInfo |= IOIO_ADDR_32;\r
+ break;\r
+\r
+ case Size64Bits:\r
+ ExitInfo |= IOIO_ADDR_64;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ if (InstructionData->RepMode != 0) {\r
+ ExitInfo |= IOIO_REP;\r
+ }\r
+\r
+ return ExitInfo;\r
+}\r
+\r
+/**\r
+ Handle an IOIO event.\r
+\r
+ Use the VMGEXIT instruction to handle an IOIO event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+IoioExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 ExitInfo1, ExitInfo2, Status;\r
+ BOOLEAN IsString;\r
+\r
+ ExitInfo1 = IoioExitInfo (Regs, InstructionData);\r
+ if (ExitInfo1 == 0) {\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;\r
+ if (IsString) {\r
+ UINTN IoBytes, VmgExitBytes;\r
+ UINTN GhcbCount, OpCount;\r
+\r
+ Status = 0;\r
+\r
+ IoBytes = IOIO_DATA_BYTES (ExitInfo1);\r
+ GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;\r
+\r
+ OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;\r
+ while (OpCount != 0) {\r
+ ExitInfo2 = MIN (OpCount, GhcbCount);\r
+ VmgExitBytes = ExitInfo2 * IoBytes;\r
+\r
+ if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {\r
+ CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);\r
+ Regs->Rsi += VmgExitBytes;\r
+ }\r
+\r
+ Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
+ Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
+ CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);\r
+ Regs->Rdi += VmgExitBytes;\r
+ }\r
+\r
+ if ((ExitInfo1 & IOIO_REP) != 0) {\r
+ Regs->Rcx -= ExitInfo2;\r
+ }\r
+\r
+ OpCount -= ExitInfo2;\r
+ }\r
+ } else {\r
+ if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
+ Ghcb->SaveArea.Rax = 0;\r
+ } else {\r
+ CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
+ }\r
+\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Handle a INVD event.\r
+\r
+ Use the VMGEXIT instruction to handle a INVD event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+InvdExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);\r
+}\r
+\r
+/**\r
+ Fetch CPUID leaf/function via hypervisor/VMGEXIT.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in] EaxIn EAX input for cpuid instruction\r
+ @param[in] EcxIn ECX input for cpuid instruction\r
+ @param[in] Xcr0In XCR0 at time of cpuid instruction\r
+ @param[in, out] Eax Pointer to store leaf's EAX value\r
+ @param[in, out] Ebx Pointer to store leaf's EBX value\r
+ @param[in, out] Ecx Pointer to store leaf's ECX value\r
+ @param[in, out] Edx Pointer to store leaf's EDX value\r
+ @param[in, out] Status Pointer to store status from VMGEXIT (always 0\r
+ unless return value indicates failure)\r
+ @param[in, out] Unsupported Pointer to store indication of unsupported\r
+ VMGEXIT (always false unless return value\r
+ indicates failure)\r
+\r
+ @retval TRUE CPUID leaf fetch successfully.\r
+ @retval FALSE Error occurred while fetching CPUID leaf. Callers\r
+ should Status and Unsupported and handle\r
+ accordingly if they indicate a more precise\r
+ error condition.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+GetCpuidHyp (\r
+ IN OUT GHCB *Ghcb,\r
+ IN UINT32 EaxIn,\r
+ IN UINT32 EcxIn,\r
+ IN UINT64 XCr0,\r
+ IN OUT UINT32 *Eax,\r
+ IN OUT UINT32 *Ebx,\r
+ IN OUT UINT32 *Ecx,\r
+ IN OUT UINT32 *Edx,\r
+ IN OUT UINT64 *Status,\r
+ IN OUT BOOLEAN *UnsupportedExit\r
+ )\r
+{\r
+ *UnsupportedExit = FALSE;\r
+ Ghcb->SaveArea.Rax = EaxIn;\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+ Ghcb->SaveArea.Rcx = EcxIn;\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
+ if (EaxIn == CPUID_EXTENDED_STATE) {\r
+ Ghcb->SaveArea.XCr0 = XCr0;\r
+ VmgSetOffsetValid (Ghcb, GhcbXCr0);\r
+ }\r
+\r
+ *Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);\r
+ if (*Status != 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRbx) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
+ {\r
+ *UnsupportedExit = TRUE;\r
+ return FALSE;\r
+ }\r
+\r
+ if (Eax) {\r
+ *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax;\r
+ }\r
+\r
+ if (Ebx) {\r
+ *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx;\r
+ }\r
+\r
+ if (Ecx) {\r
+ *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx;\r
+ }\r
+\r
+ if (Edx) {\r
+ *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Check if SEV-SNP enabled.\r
+\r
+ @retval TRUE SEV-SNP is enabled.\r
+ @retval FALSE SEV-SNP is disabled.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+SnpEnabled (\r
+ VOID\r
+ )\r
+{\r
+ MSR_SEV_STATUS_REGISTER Msr;\r
+\r
+ Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);\r
+\r
+ return !!Msr.Bits.SevSnpBit;\r
+}\r
+\r
+/**\r
+ Calculate the total XSAVE area size for enabled XSAVE areas\r
+\r
+ @param[in] XFeaturesEnabled Bit-mask of enabled XSAVE features/areas as\r
+ indicated by XCR0/MSR_IA32_XSS bits\r
+ @param[in] XSaveBaseSize Base/legacy XSAVE area size (e.g. when\r
+ XCR0 is 1)\r
+ @param[in, out] XSaveSize Pointer to storage for calculated XSAVE area\r
+ size\r
+ @param[in] Compacted Whether or not the calculation is for the\r
+ normal XSAVE area size (leaf 0xD,0x0,EBX) or\r
+ compacted XSAVE area size (leaf 0xD,0x1,EBX)\r
+\r
+\r
+ @retval TRUE XSAVE size calculation was successful.\r
+ @retval FALSE XSAVE size calculation was unsuccessful.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+GetCpuidXSaveSize (\r
+ IN UINT64 XFeaturesEnabled,\r
+ IN UINT32 XSaveBaseSize,\r
+ IN OUT UINT32 *XSaveSize,\r
+ IN BOOLEAN Compacted\r
+ )\r
+{\r
+ SEV_SNP_CPUID_INFO *CpuidInfo;\r
+ UINT64 XFeaturesFound = 0;\r
+ UINT32 Idx;\r
+\r
+ *XSaveSize = XSaveBaseSize;\r
+ CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);\r
+\r
+ for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {\r
+ SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];\r
+\r
+ if (!((CpuidFn->EaxIn == 0xD) &&\r
+ ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1))))\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) ||\r
+ !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn)))\r
+ {\r
+ continue;\r
+ }\r
+\r
+ XFeaturesFound |= (1ULL << CpuidFn->EcxIn);\r
+ if (Compacted) {\r
+ *XSaveSize += CpuidFn->Eax;\r
+ } else {\r
+ *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Either the guest set unsupported XCR0/XSS bits, or the corresponding\r
+ * entries in the CPUID table were not present. This is an invalid state.\r
+ */\r
+ if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function\r
+\r
+ @param[in] EaxIn EAX input for cpuid instruction\r
+\r
+ @retval FALSE cpuid leaf/function is not indexed by ECX input\r
+ @retval TRUE cpuid leaf/function is indexed by ECX input\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsFunctionIndexed (\r
+ IN UINT32 EaxIn\r
+ )\r
+{\r
+ switch (EaxIn) {\r
+ case CPUID_CACHE_PARAMS:\r
+ case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS:\r
+ case CPUID_EXTENDED_TOPOLOGY:\r
+ case CPUID_EXTENDED_STATE:\r
+ case CPUID_INTEL_RDT_MONITORING:\r
+ case CPUID_INTEL_RDT_ALLOCATION:\r
+ case CPUID_INTEL_SGX:\r
+ case CPUID_INTEL_PROCESSOR_TRACE:\r
+ case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS:\r
+ case CPUID_V2_EXTENDED_TOPOLOGY:\r
+ case 0x8000001D: /* Cache Topology Information */\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Fetch CPUID leaf/function via SEV-SNP CPUID table.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in] EaxIn EAX input for cpuid instruction\r
+ @param[in] EcxIn ECX input for cpuid instruction\r
+ @param[in] Xcr0In XCR0 at time of cpuid instruction\r
+ @param[in, out] Eax Pointer to store leaf's EAX value\r
+ @param[in, out] Ebx Pointer to store leaf's EBX value\r
+ @param[in, out] Ecx Pointer to store leaf's ECX value\r
+ @param[in, out] Edx Pointer to store leaf's EDX value\r
+ @param[in, out] Status Pointer to store status from VMGEXIT (always 0\r
+ unless return value indicates failure)\r
+ @param[in, out] Unsupported Pointer to store indication of unsupported\r
+ VMGEXIT (always false unless return value\r
+ indicates failure)\r
+\r
+ @retval TRUE CPUID leaf fetch successfully.\r
+ @retval FALSE Error occurred while fetching CPUID leaf. Callers\r
+ should Status and Unsupported and handle\r
+ accordingly if they indicate a more precise\r
+ error condition.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+GetCpuidFw (\r
+ IN OUT GHCB *Ghcb,\r
+ IN UINT32 EaxIn,\r
+ IN UINT32 EcxIn,\r
+ IN UINT64 XCr0,\r
+ IN OUT UINT32 *Eax,\r
+ IN OUT UINT32 *Ebx,\r
+ IN OUT UINT32 *Ecx,\r
+ IN OUT UINT32 *Edx,\r
+ IN OUT UINT64 *Status,\r
+ IN OUT BOOLEAN *Unsupported\r
+ )\r
+{\r
+ SEV_SNP_CPUID_INFO *CpuidInfo;\r
+ BOOLEAN Found;\r
+ UINT32 Idx;\r
+\r
+ CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);\r
+ Found = FALSE;\r
+\r
+ for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {\r
+ SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];\r
+\r
+ if (CpuidFn->EaxIn != EaxIn) {\r
+ continue;\r
+ }\r
+\r
+ if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) {\r
+ continue;\r
+ }\r
+\r
+ *Eax = CpuidFn->Eax;\r
+ *Ebx = CpuidFn->Ebx;\r
+ *Ecx = CpuidFn->Ecx;\r
+ *Edx = CpuidFn->Edx;\r
+\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+\r
+ if (!Found) {\r
+ *Eax = *Ebx = *Ecx = *Edx = 0;\r
+ goto Out;\r
+ }\r
+\r
+ if (EaxIn == CPUID_VERSION_INFO) {\r
+ IA32_CR4 Cr4;\r
+ UINT32 Ebx2;\r
+ UINT32 Edx2;\r
+\r
+ if (!GetCpuidHyp (\r
+ Ghcb,\r
+ EaxIn,\r
+ EcxIn,\r
+ XCr0,\r
+ NULL,\r
+ &Ebx2,\r
+ NULL,\r
+ &Edx2,\r
+ Status,\r
+ Unsupported\r
+ ))\r
+ {\r
+ return FALSE;\r
+ }\r
+\r
+ /* initial APIC ID */\r
+ *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);\r
+ /* APIC enabled bit */\r
+ *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);\r
+ /* OSXSAVE enabled bit */\r
+ Cr4.UintN = AsmReadCr4 ();\r
+ *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)\r
+ : (*Ecx & ~BIT27);\r
+ } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {\r
+ IA32_CR4 Cr4;\r
+\r
+ Cr4.UintN = AsmReadCr4 ();\r
+ /* OSPKE enabled bit */\r
+ *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);\r
+ } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {\r
+ if (!GetCpuidHyp (\r
+ Ghcb,\r
+ EaxIn,\r
+ EcxIn,\r
+ XCr0,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ Edx,\r
+ Status,\r
+ Unsupported\r
+ ))\r
+ {\r
+ return FALSE;\r
+ }\r
+ } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) {\r
+ MSR_IA32_XSS_REGISTER XssMsr;\r
+ BOOLEAN Compacted;\r
+ UINT32 XSaveSize;\r
+\r
+ XssMsr.Uint64 = 0;\r
+ Compacted = FALSE;\r
+ if (EcxIn == 1) {\r
+ /*\r
+ * The PPR and APM aren't clear on what size should be encoded in\r
+ * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or\r
+ * XSAVES, as these are generally fixed to 1 on real CPUs. Report\r
+ * this undefined case as an error.\r
+ */\r
+ if (!(*Eax & (BIT3 | BIT1))) {\r
+ /* (XSAVES | XSAVEC) */\r
+ return FALSE;\r
+ }\r
+\r
+ Compacted = TRUE;\r
+ XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);\r
+ }\r
+\r
+ if (!GetCpuidXSaveSize (\r
+ XCr0 | XssMsr.Uint64,\r
+ *Ebx,\r
+ &XSaveSize,\r
+ Compacted\r
+ ))\r
+ {\r
+ return FALSE;\r
+ }\r
+\r
+ *Ebx = XSaveSize;\r
+ } else if (EaxIn == 0x8000001E) {\r
+ UINT32 Ebx2;\r
+ UINT32 Ecx2;\r
+\r
+ /* extended APIC ID */\r
+ if (!GetCpuidHyp (\r
+ Ghcb,\r
+ EaxIn,\r
+ EcxIn,\r
+ XCr0,\r
+ Eax,\r
+ &Ebx2,\r
+ &Ecx2,\r
+ NULL,\r
+ Status,\r
+ Unsupported\r
+ ))\r
+ {\r
+ return FALSE;\r
+ }\r
+\r
+ /* compute ID */\r
+ *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);\r
+ /* node ID */\r
+ *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);\r
+ }\r
+\r
+Out:\r
+ *Status = 0;\r
+ *Unsupported = FALSE;\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Handle a CPUID event.\r
+\r
+ Use VMGEXIT instruction or CPUID table to handle a CPUID event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+CpuidExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ BOOLEAN Unsupported;\r
+ UINT64 Status;\r
+ UINT32 EaxIn;\r
+ UINT32 EcxIn;\r
+ UINT64 XCr0;\r
+ UINT32 Eax;\r
+ UINT32 Ebx;\r
+ UINT32 Ecx;\r
+ UINT32 Edx;\r
+\r
+ EaxIn = (UINT32)(UINTN)Regs->Rax;\r
+ EcxIn = (UINT32)(UINTN)Regs->Rcx;\r
+\r
+ if (EaxIn == CPUID_EXTENDED_STATE) {\r
+ IA32_CR4 Cr4;\r
+\r
+ Cr4.UintN = AsmReadCr4 ();\r
+ Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
+ XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
+ }\r
+\r
+ if (SnpEnabled ()) {\r
+ if (!GetCpuidFw (\r
+ Ghcb,\r
+ EaxIn,\r
+ EcxIn,\r
+ XCr0,\r
+ &Eax,\r
+ &Ebx,\r
+ &Ecx,\r
+ &Edx,\r
+ &Status,\r
+ &Unsupported\r
+ ))\r
+ {\r
+ goto CpuidFail;\r
+ }\r
+ } else {\r
+ if (!GetCpuidHyp (\r
+ Ghcb,\r
+ EaxIn,\r
+ EcxIn,\r
+ XCr0,\r
+ &Eax,\r
+ &Ebx,\r
+ &Ecx,\r
+ &Edx,\r
+ &Status,\r
+ &Unsupported\r
+ ))\r
+ {\r
+ goto CpuidFail;\r
+ }\r
+ }\r
+\r
+ Regs->Rax = Eax;\r
+ Regs->Rbx = Ebx;\r
+ Regs->Rcx = Ecx;\r
+ Regs->Rdx = Edx;\r
+\r
+ return 0;\r
+\r
+CpuidFail:\r
+ if (Unsupported) {\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Handle a RDPMC event.\r
+\r
+ Use the VMGEXIT instruction to handle a RDPMC event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+RdpmcExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 Status;\r
+\r
+ Ghcb->SaveArea.Rcx = Regs->Rcx;\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
+ {\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ Regs->Rax = Ghcb->SaveArea.Rax;\r
+ Regs->Rdx = Ghcb->SaveArea.Rdx;\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Handle a RDTSC event.\r
+\r
+ Use the VMGEXIT instruction to handle a RDTSC event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+RdtscExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ UINT64 Status;\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
+ {\r
+ return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+ }\r
+\r
+ Regs->Rax = Ghcb->SaveArea.Rax;\r
+ Regs->Rdx = Ghcb->SaveArea.Rdx;\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Handle a DR7 register write event.\r
+\r
+ Use the VMGEXIT instruction to handle a DR7 write event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+Dr7WriteExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
+ SEV_ES_PER_CPU_DATA *SevEsData;\r
+ UINT64 *Register;\r
+ UINT64 Status;\r
+\r
+ Ext = &InstructionData->Ext;\r
+ SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
+\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ //\r
+ // MOV DRn always treats MOD == 3 no matter how encoded\r
+ //\r
+ Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+\r
+ //\r
+ // Using a value of 0 for ExitInfo1 means RAX holds the value\r
+ //\r
+ Ghcb->SaveArea.Rax = *Register;\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ SevEsData->Dr7 = *Register;\r
+ SevEsData->Dr7Cached = 1;\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Handle a DR7 register read event.\r
+\r
+ Use the VMGEXIT instruction to handle a DR7 read event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+Dr7ReadExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
+ SEV_ES_PER_CPU_DATA *SevEsData;\r
+ UINT64 *Register;\r
+\r
+ Ext = &InstructionData->Ext;\r
+ SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
+\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ //\r
+ // MOV DRn always treats MOD == 3 no matter how encoded\r
+ //\r
+ Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+\r
+ //\r
+ // If there is a cached valued for DR7, return that. Otherwise return the\r
+ // DR7 standard reset value of 0x400 (no debug breakpoints set).\r
+ //\r
+ *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Handle a #VC exception.\r
+\r
+ Performs the necessary processing to handle a #VC exception.\r
+\r
+ @param[in, out] Ghcb Pointer to the GHCB\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
+InternalVmgExitHandleVc (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ EFI_SYSTEM_CONTEXT_X64 *Regs;\r
+ NAE_EXIT NaeExit;\r
+ SEV_ES_INSTRUCTION_DATA InstructionData;\r
+ UINT64 ExitCode, Status;\r
+ EFI_STATUS VcRet;\r
+ BOOLEAN InterruptState;\r
+\r
+ VcRet = EFI_SUCCESS;\r
+\r
+ Regs = SystemContext.SystemContextX64;\r
+\r
+ VmgInit (Ghcb, &InterruptState);\r
+\r
+ ExitCode = Regs->ExceptionData;\r
+ switch (ExitCode) {\r
+ case SVM_EXIT_DR7_READ:\r
+ NaeExit = Dr7ReadExit;\r
+ break;\r
+\r
+ case SVM_EXIT_DR7_WRITE:\r
+ NaeExit = Dr7WriteExit;\r
+ break;\r
+\r
+ case SVM_EXIT_RDTSC:\r
+ NaeExit = RdtscExit;\r
+ break;\r
+\r
+ case SVM_EXIT_RDPMC:\r
+ NaeExit = RdpmcExit;\r
+ break;\r
+\r
+ case SVM_EXIT_CPUID:\r
+ NaeExit = CpuidExit;\r
+ break;\r
+\r
+ case SVM_EXIT_INVD:\r
+ NaeExit = InvdExit;\r
+ break;\r
+\r
+ case SVM_EXIT_IOIO_PROT:\r
+ NaeExit = IoioExit;\r
+ break;\r
+\r
+ case SVM_EXIT_MSR:\r
+ NaeExit = MsrExit;\r
+ break;\r
+\r
+ case SVM_EXIT_VMMCALL:\r
+ NaeExit = VmmCallExit;\r
+ break;\r
+\r
+ case SVM_EXIT_RDTSCP:\r
+ NaeExit = RdtscpExit;\r
+ break;\r
+\r
+ case SVM_EXIT_WBINVD:\r
+ NaeExit = WbinvdExit;\r
+ break;\r
+\r
+ case SVM_EXIT_MONITOR:\r
+ NaeExit = MonitorExit;\r
+ break;\r
+\r
+ case SVM_EXIT_MWAIT:\r
+ NaeExit = MwaitExit;\r
+ break;\r
+\r
+ case SVM_EXIT_NPF:\r
+ NaeExit = MmioExit;\r
+ break;\r
+\r
+ default:\r
+ NaeExit = UnsupportedExit;\r
+ }\r
+\r
+ InitInstructionData (&InstructionData, Ghcb, Regs);\r
+\r
+ Status = NaeExit (Ghcb, Regs, &InstructionData);\r
+ if (Status == 0) {\r
+ Regs->Rip += InstructionLength (&InstructionData);\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
+ VcRet = EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ VmgDone (Ghcb, InterruptState);\r
+\r
+ return VcRet;\r
+}\r
+\r
+/**\r
+ Routine to allow ASSERT from within #VC.\r
+\r
+ @param[in, out] SevEsData Pointer to the per-CPU data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgExitIssueAssert (\r
+ IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
+ )\r
+{\r
+ //\r
+ // Progress will be halted, so set VcCount to allow for ASSERT output\r
+ // to be seen.\r
+ //\r
+ SevEsData->VcCount = 0;\r
+\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+}\r
--- /dev/null
+/** @file\r
+ X64 #VC Exception Handler functon header file.\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
+#ifndef CC_EXIT_VC_HANDLER_H_\r
+#define CC_EXIT_VC_HANDLER_H_\r
+\r
+#include <Base.h>\r
+#include <Uefi.h>\r
+#include <Library/CcExitLib.h>\r
+\r
+/**\r
+ Handle a #VC exception.\r
+\r
+ Performs the necessary processing to handle a #VC exception.\r
+\r
+ @param[in, out] Ghcb Pointer to the GHCB\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
+InternalVmgExitHandleVc (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ );\r
+\r
+/**\r
+ Routine to allow ASSERT from within #VC.\r
+\r
+ @param[in, out] SevEsData Pointer to the per-CPU data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgExitIssueAssert (\r
+ IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include "CcExitTd.h"\r
+#include <Library/CcExitLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <IndustryStandard/Tdx.h>\r
+#include <IndustryStandard/InstructionParsing.h>\r
+\r
+typedef union {\r
+ struct {\r
+ UINT32 Eax;\r
+ UINT32 Edx;\r
+ } Regs;\r
+ UINT64 Val;\r
+} MSR_DATA;\r
+\r
+typedef union {\r
+ UINT8 Val;\r
+ struct {\r
+ UINT8 B : 1;\r
+ UINT8 X : 1;\r
+ UINT8 R : 1;\r
+ UINT8 W : 1;\r
+ } Bits;\r
+} REX;\r
+\r
+typedef union {\r
+ UINT8 Val;\r
+ struct {\r
+ UINT8 Rm : 3;\r
+ UINT8 Reg : 3;\r
+ UINT8 Mod : 2;\r
+ } Bits;\r
+} MODRM;\r
+\r
+typedef struct {\r
+ UINT64 Regs[4];\r
+} CPUID_DATA;\r
+\r
+/**\r
+ Handle an CPUID event.\r
+\r
+ Use the TDVMCALL instruction to handle cpuid #ve\r
+\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] Veinfo VE Info\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+**/\r
+STATIC\r
+UINT64\r
+EFIAPI\r
+CpuIdExit (\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
+ )\r
+{\r
+ CPUID_DATA CpuIdData;\r
+ UINT64 Status;\r
+\r
+ Status = TdVmCallCpuid (Regs->Rax, Regs->Rcx, &CpuIdData);\r
+\r
+ if (Status == 0) {\r
+ Regs->Rax = CpuIdData.Regs[0];\r
+ Regs->Rbx = CpuIdData.Regs[1];\r
+ Regs->Rcx = CpuIdData.Regs[2];\r
+ Regs->Rdx = CpuIdData.Regs[3];\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Handle an IO event.\r
+\r
+ Use the TDVMCALL instruction to handle either an IO read or an IO write.\r
+\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] Veinfo VE Info\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+**/\r
+STATIC\r
+UINT64\r
+EFIAPI\r
+IoExit (\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
+ )\r
+{\r
+ BOOLEAN Write;\r
+ UINTN Size;\r
+ UINTN Port;\r
+ UINT64 Val;\r
+ UINT64 RepCnt;\r
+ UINT64 Status;\r
+\r
+ Val = 0;\r
+ Write = Veinfo->ExitQualification.Io.Direction ? FALSE : TRUE;\r
+ Size = Veinfo->ExitQualification.Io.Size + 1;\r
+ Port = Veinfo->ExitQualification.Io.Port;\r
+\r
+ if (Veinfo->ExitQualification.Io.String) {\r
+ //\r
+ // If REP is set, get rep-cnt from Rcx\r
+ //\r
+ RepCnt = Veinfo->ExitQualification.Io.Rep ? Regs->Rcx : 1;\r
+\r
+ while (RepCnt) {\r
+ Val = 0;\r
+ if (Write == TRUE) {\r
+ CopyMem (&Val, (VOID *)Regs->Rsi, Size);\r
+ Regs->Rsi += Size;\r
+ }\r
+\r
+ Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));\r
+ if (Status != 0) {\r
+ break;\r
+ }\r
+\r
+ if (Write == FALSE) {\r
+ CopyMem ((VOID *)Regs->Rdi, &Val, Size);\r
+ Regs->Rdi += Size;\r
+ }\r
+\r
+ if (Veinfo->ExitQualification.Io.Rep) {\r
+ Regs->Rcx -= 1;\r
+ }\r
+\r
+ RepCnt -= 1;\r
+ }\r
+ } else {\r
+ if (Write == TRUE) {\r
+ CopyMem (&Val, (VOID *)&Regs->Rax, Size);\r
+ }\r
+\r
+ Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));\r
+ if ((Status == 0) && (Write == FALSE)) {\r
+ CopyMem ((VOID *)&Regs->Rax, &Val, Size);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Handle an READ MSR event.\r
+\r
+ Use the TDVMCALL instruction to handle msr read\r
+\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] Veinfo VE Info\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+**/\r
+STATIC\r
+UINT64\r
+ReadMsrExit (\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
+ )\r
+{\r
+ MSR_DATA Data;\r
+ UINT64 Status;\r
+\r
+ Status = TdVmCall (EXIT_REASON_MSR_READ, Regs->Rcx, 0, 0, 0, &Data);\r
+ if (Status == 0) {\r
+ Regs->Rax = Data.Regs.Eax;\r
+ Regs->Rdx = Data.Regs.Edx;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Handle an WRITE MSR event.\r
+\r
+ Use the TDVMCALL instruction to handle msr write\r
+\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] Veinfo VE Info\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+**/\r
+STATIC\r
+UINT64\r
+WriteMsrExit (\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
+ )\r
+{\r
+ UINT64 Status;\r
+ MSR_DATA Data;\r
+\r
+ Data.Regs.Eax = (UINT32)Regs->Rax;\r
+ Data.Regs.Edx = (UINT32)Regs->Rdx;\r
+\r
+ Status = TdVmCall (EXIT_REASON_MSR_WRITE, Regs->Rcx, Data.Val, 0, 0, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+TdxDecodeInstruction (\r
+ IN UINT8 *Rip\r
+ )\r
+{\r
+ UINTN i;\r
+\r
+ DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip));\r
+ for (i = 0; i < 15; i++) {\r
+ DEBUG ((DEBUG_INFO, "%02x:", Rip[i]));\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "\n"));\r
+}\r
+\r
+#define TDX_DECODER_BUG_ON(x) \\r
+ if ((x)) { \\r
+ TdxDecodeInstruction(Rip); \\r
+ TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \\r
+ }\r
+\r
+STATIC\r
+UINT64 *\r
+EFIAPI\r
+GetRegFromContext (\r
+ IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN UINTN RegIndex\r
+ )\r
+{\r
+ switch (RegIndex) {\r
+ case 0: return &Regs->Rax;\r
+ break;\r
+ case 1: return &Regs->Rcx;\r
+ break;\r
+ case 2: return &Regs->Rdx;\r
+ break;\r
+ case 3: return &Regs->Rbx;\r
+ break;\r
+ case 4: return &Regs->Rsp;\r
+ break;\r
+ case 5: return &Regs->Rbp;\r
+ break;\r
+ case 6: return &Regs->Rsi;\r
+ break;\r
+ case 7: return &Regs->Rdi;\r
+ break;\r
+ case 8: return &Regs->R8;\r
+ break;\r
+ case 9: return &Regs->R9;\r
+ break;\r
+ case 10: return &Regs->R10;\r
+ break;\r
+ case 11: return &Regs->R11;\r
+ break;\r
+ case 12: return &Regs->R12;\r
+ break;\r
+ case 13: return &Regs->R13;\r
+ break;\r
+ case 14: return &Regs->R14;\r
+ break;\r
+ case 15: return &Regs->R15;\r
+ break;\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Handle an MMIO event.\r
+\r
+ Use the TDVMCALL instruction to handle either an mmio read or an mmio write.\r
+\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] Veinfo VE Info\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+**/\r
+STATIC\r
+INTN\r
+EFIAPI\r
+MmioExit (\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
+ )\r
+{\r
+ UINT64 Status;\r
+ UINT32 MmioSize;\r
+ UINT32 RegSize;\r
+ UINT8 OpCode;\r
+ BOOLEAN SeenRex;\r
+ UINT64 *Reg;\r
+ UINT8 *Rip;\r
+ UINT64 Val;\r
+ UINT32 OpSize;\r
+ MODRM ModRm;\r
+ REX Rex;\r
+ TD_RETURN_DATA TdReturnData;\r
+ UINT8 Gpaw;\r
+ UINT64 TdSharedPageMask;\r
+\r
+ Rip = (UINT8 *)Regs->Rip;\r
+ Val = 0;\r
+ Rex.Val = 0;\r
+ SeenRex = FALSE;\r
+\r
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);\r
+ if (Status == TDX_EXIT_REASON_SUCCESS) {\r
+ Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f);\r
+ TdSharedPageMask = 1ULL << (Gpaw - 1);\r
+ } else {\r
+ DEBUG ((DEBUG_ERROR, "TDCALL failed with status=%llx\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ if ((Veinfo->GuestPA & TdSharedPageMask) == 0) {\r
+ DEBUG ((DEBUG_ERROR, "EPT-violation #VE on private memory is not allowed!"));\r
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+ CpuDeadLoop ();\r
+ }\r
+\r
+ //\r
+ // Default to 32bit transfer\r
+ //\r
+ OpSize = 4;\r
+\r
+ do {\r
+ OpCode = *Rip++;\r
+ if (OpCode == 0x66) {\r
+ OpSize = 2;\r
+ } else if ((OpCode == 0x64) || (OpCode == 0x65) || (OpCode == 0x67)) {\r
+ continue;\r
+ } else if ((OpCode >= 0x40) && (OpCode <= 0x4f)) {\r
+ SeenRex = TRUE;\r
+ Rex.Val = OpCode;\r
+ } else {\r
+ break;\r
+ }\r
+ } while (TRUE);\r
+\r
+ //\r
+ // We need to have at least 2 more bytes for this instruction\r
+ //\r
+ TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 13);\r
+\r
+ OpCode = *Rip++;\r
+ //\r
+ // Two-byte opecode, get next byte\r
+ //\r
+ if (OpCode == 0x0F) {\r
+ OpCode = *Rip++;\r
+ }\r
+\r
+ switch (OpCode) {\r
+ case 0x88:\r
+ case 0x8A:\r
+ case 0xB6:\r
+ MmioSize = 1;\r
+ break;\r
+ case 0xB7:\r
+ MmioSize = 2;\r
+ break;\r
+ default:\r
+ MmioSize = Rex.Bits.W ? 8 : OpSize;\r
+ break;\r
+ }\r
+\r
+ /* Punt on AH/BH/CH/DH unless it shows up. */\r
+ ModRm.Val = *Rip++;\r
+ TDX_DECODER_BUG_ON (MmioSize == 1 && ModRm.Bits.Reg > 4 && !SeenRex && OpCode != 0xB6);\r
+ Reg = GetRegFromContext (Regs, ModRm.Bits.Reg | ((int)Rex.Bits.R << 3));\r
+ TDX_DECODER_BUG_ON (!Reg);\r
+\r
+ if (ModRm.Bits.Rm == 4) {\r
+ ++Rip; /* SIB byte */\r
+ }\r
+\r
+ if ((ModRm.Bits.Mod == 2) || ((ModRm.Bits.Mod == 0) && (ModRm.Bits.Rm == 5))) {\r
+ Rip += 4; /* DISP32 */\r
+ } else if (ModRm.Bits.Mod == 1) {\r
+ ++Rip; /* DISP8 */\r
+ }\r
+\r
+ switch (OpCode) {\r
+ case 0x88:\r
+ case 0x89:\r
+ CopyMem ((void *)&Val, Reg, MmioSize);\r
+ Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);\r
+ break;\r
+ case 0xC7:\r
+ CopyMem ((void *)&Val, Rip, OpSize);\r
+ Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);\r
+ Rip += OpSize;\r
+ default:\r
+ //\r
+ // 32-bit write registers are zero extended to the full register\r
+ // Hence 'MOVZX r[32/64], r/m16' is\r
+ // hardcoded to reg size 8, and the straight MOV case has a reg\r
+ // size of 8 in the 32-bit read case.\r
+ //\r
+ switch (OpCode) {\r
+ case 0xB6:\r
+ RegSize = Rex.Bits.W ? 8 : OpSize;\r
+ break;\r
+ case 0xB7:\r
+ RegSize = 8;\r
+ break;\r
+ default:\r
+ RegSize = MmioSize == 4 ? 8 : MmioSize;\r
+ break;\r
+ }\r
+\r
+ Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 0, Veinfo->GuestPA, 0, &Val);\r
+ if (Status == 0) {\r
+ ZeroMem (Reg, RegSize);\r
+ CopyMem (Reg, (void *)&Val, MmioSize);\r
+ }\r
+ }\r
+\r
+ if (Status == 0) {\r
+ TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15);\r
+\r
+ //\r
+ // We change instruction length to reflect true size so handler can\r
+ // bump rip\r
+ //\r
+ Veinfo->ExitInstructionLength = (UINT32)((UINT64)Rip - Regs->Rip);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Handle a #VE exception.\r
+\r
+ Performs the necessary processing to handle a #VE 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 #VE not supported, (new) exception value to\r
+ propagate provided\r
+ @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to\r
+ propagate provided\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VmTdExitHandleVe (\r
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ UINT64 Status;\r
+ TD_RETURN_DATA ReturnData;\r
+ EFI_SYSTEM_CONTEXT_X64 *Regs;\r
+\r
+ Regs = SystemContext.SystemContextX64;\r
+ Status = TdCall (TDCALL_TDGETVEINFO, 0, 0, 0, &ReturnData);\r
+ ASSERT (Status == 0);\r
+ if (Status != 0) {\r
+ DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status = 0x%llx\n", Status));\r
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+ }\r
+\r
+ switch (ReturnData.VeInfo.ExitReason) {\r
+ case EXIT_REASON_CPUID:\r
+ Status = CpuIdExit (Regs, &ReturnData.VeInfo);\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "CPUID #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",\r
+ ReturnData.VeInfo.ExitReason,\r
+ ReturnData.VeInfo.ExitQualification.Val\r
+ ));\r
+ break;\r
+\r
+ case EXIT_REASON_HLT:\r
+ Status = TdVmCall (EXIT_REASON_HLT, 0, 0, 0, 0, 0);\r
+ break;\r
+\r
+ case EXIT_REASON_IO_INSTRUCTION:\r
+ Status = IoExit (Regs, &ReturnData.VeInfo);\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "IO_Instruction #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",\r
+ ReturnData.VeInfo.ExitReason,\r
+ ReturnData.VeInfo.ExitQualification.Val\r
+ ));\r
+ break;\r
+\r
+ case EXIT_REASON_MSR_READ:\r
+ Status = ReadMsrExit (Regs, &ReturnData.VeInfo);\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "RDMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",\r
+ ReturnData.VeInfo.ExitReason,\r
+ ReturnData.VeInfo.ExitQualification.Val,\r
+ Regs->Rcx,\r
+ Status\r
+ ));\r
+ break;\r
+\r
+ case EXIT_REASON_MSR_WRITE:\r
+ Status = WriteMsrExit (Regs, &ReturnData.VeInfo);\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "WRMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",\r
+ ReturnData.VeInfo.ExitReason,\r
+ ReturnData.VeInfo.ExitQualification.Val,\r
+ Regs->Rcx,\r
+ Status\r
+ ));\r
+ break;\r
+\r
+ case EXIT_REASON_EPT_VIOLATION:\r
+ Status = MmioExit (Regs, &ReturnData.VeInfo);\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "MMIO #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",\r
+ ReturnData.VeInfo.ExitReason,\r
+ ReturnData.VeInfo.ExitQualification.Val\r
+ ));\r
+ break;\r
+\r
+ case EXIT_REASON_VMCALL:\r
+ case EXIT_REASON_MWAIT_INSTRUCTION:\r
+ case EXIT_REASON_MONITOR_INSTRUCTION:\r
+ case EXIT_REASON_WBINVD:\r
+ case EXIT_REASON_RDPMC:\r
+ /* Handle as nops. */\r
+ break;\r
+\r
+ default:\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "Unsupported #VE happened, ExitReason is %d, ExitQualification = 0x%x.\n",\r
+ ReturnData.VeInfo.ExitReason,\r
+ ReturnData.VeInfo.ExitQualification.Val\r
+ ));\r
+\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+ }\r
+\r
+ if (Status) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "#VE Error (0x%llx) returned from host, ExitReason is %d, ExitQualification = 0x%x.\n",\r
+ Status,\r
+ ReturnData.VeInfo.ExitReason,\r
+ ReturnData.VeInfo.ExitQualification.Val\r
+ ));\r
+\r
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+ }\r
+\r
+ SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength;\r
+ return EFI_SUCCESS;\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/MemEncryptSevLib.h>\r
+#include <Library/CcExitLib.h>\r
+#include <Register/Amd/Msr.h>\r
+\r
+#include "CcExitVcHandler.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 PEI/DXE #VC nesting.\r
+ //\r
+ if (SevEsData->VcCount > VMGEXIT_MAXIMUM_VC_COUNT) {\r
+ VmgExitIssueAssert (SevEsData);\r
+ } else if (SevEsData->VcCount > 1) {\r
+ //\r
+ // Nested #VC\r
+ //\r
+ if (SevEsData->GhcbBackupPages == NULL) {\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 *)SevEsData->GhcbBackupPages;\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
--- /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
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SecCcExitLib\r
+ FILE_GUID = dafff819-f86c-4cff-a70e-83161e5bcf9a\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = CcExitLib|SEC\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = X64\r
+#\r
+\r
+[Sources.common]\r
+ CcExitLib.c\r
+ CcExitVcHandler.c\r
+ CcExitVcHandler.h\r
+ SecCcExitVcHandler.c\r
+ CcExitVeHandler.c\r
+ X64/TdVmcallCpuid.nasm\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ OvmfPkg/OvmfPkg.dec\r
+ UefiCpuPkg/UefiCpuPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ LocalApicLib\r
+ MemEncryptSevLib\r
+ PcdLib\r
+\r
+[FixedPcd]\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase\r
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize\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/MemEncryptSevLib.h>\r
+#include <Library/CcExitLib.h>\r
+#include <Register/Amd/Msr.h>\r
+\r
+#include "CcExitVcHandler.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
--- /dev/null
+;------------------------------------------------------------------------------\r
+;*\r
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>\r
+;* SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;*\r
+;*\r
+;------------------------------------------------------------------------------\r
+\r
+DEFAULT REL\r
+SECTION .text\r
+\r
+%define TDVMCALL_EXPOSE_REGS_MASK 0xffec\r
+%define TDVMCALL 0x0\r
+%define EXIT_REASON_CPUID 0xa\r
+\r
+%macro tdcall 0\r
+ db 0x66,0x0f,0x01,0xcc\r
+%endmacro\r
+\r
+%macro tdcall_push_regs 0\r
+ push rbp\r
+ mov rbp, rsp\r
+ push r15\r
+ push r14\r
+ push r13\r
+ push r12\r
+ push rbx\r
+ push rsi\r
+ push rdi\r
+%endmacro\r
+\r
+%macro tdcall_pop_regs 0\r
+ pop rdi\r
+ pop rsi\r
+ pop rbx\r
+ pop r12\r
+ pop r13\r
+ pop r14\r
+ pop r15\r
+ pop rbp\r
+%endmacro\r
+\r
+%define number_of_regs_pushed 8\r
+%define number_of_parameters 4\r
+\r
+;\r
+; Keep these in sync for push_regs/pop_regs, code below\r
+; uses them to find 5th or greater parameters\r
+;\r
+%define first_variable_on_stack_offset \\r
+ ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)\r
+%define second_variable_on_stack_offset \\r
+ ((first_variable_on_stack_offset) + 8)\r
+\r
+%macro tdcall_regs_preamble 2\r
+ mov rax, %1\r
+\r
+ xor rcx, rcx\r
+ mov ecx, %2\r
+\r
+ ; R10 = 0 (standard TDVMCALL)\r
+\r
+ xor r10d, r10d\r
+\r
+ ; Zero out unused (for standard TDVMCALL) registers to avoid leaking\r
+ ; secrets to the VMM.\r
+\r
+ xor ebx, ebx\r
+ xor esi, esi\r
+ xor edi, edi\r
+\r
+ xor edx, edx\r
+ xor ebp, ebp\r
+ xor r8d, r8d\r
+ xor r9d, r9d\r
+ xor r14, r14\r
+ xor r15, r15\r
+%endmacro\r
+\r
+%macro tdcall_regs_postamble 0\r
+ xor ebx, ebx\r
+ xor esi, esi\r
+ xor edi, edi\r
+\r
+ xor ecx, ecx\r
+ xor edx, edx\r
+ xor r8d, r8d\r
+ xor r9d, r9d\r
+ xor r10d, r10d\r
+ xor r11d, r11d\r
+%endmacro\r
+\r
+;------------------------------------------------------------------------------\r
+; 0 => RAX = TDCALL leaf / TDVMCALL\r
+; M => RCX = TDVMCALL register behavior\r
+; 0xa => R11 = TDVMCALL function / CPUID\r
+; RCX => R12 = p1\r
+; RDX => R13 = p2\r
+;\r
+; UINT64\r
+; EFIAPI\r
+; TdVmCallCpuid (\r
+; UINT64 EaxIn, // Rcx\r
+; UINT64 EcxIn, // Rdx\r
+; UINT64 *Results // R8\r
+; )\r
+global ASM_PFX(TdVmCallCpuid)\r
+ASM_PFX(TdVmCallCpuid):\r
+ tdcall_push_regs\r
+\r
+ mov r11, EXIT_REASON_CPUID\r
+ mov r12, rcx\r
+ mov r13, rdx\r
+\r
+ ; Save *results pointers\r
+ push r8\r
+\r
+ tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK\r
+\r
+ tdcall\r
+\r
+ ; ignore return data if TDCALL reports failure.\r
+ test rax, rax\r
+ jnz .no_return_data\r
+\r
+ ; Propagate TDVMCALL success/failure to return value.\r
+ mov rax, r10\r
+ test rax, rax\r
+ jnz .no_return_data\r
+\r
+ ; Retrieve *Results\r
+ pop r8\r
+ test r8, r8\r
+ jz .no_return_data\r
+ ; Caller pass in buffer so store results r12-r15 contains eax-edx\r
+ mov [r8 + 0], r12\r
+ mov [r8 + 8], r13\r
+ mov [r8 + 16], r14\r
+ mov [r8 + 24], r15\r
+\r
+.no_return_data:\r
+ tdcall_regs_postamble\r
+\r
+ tdcall_pop_regs\r
+\r
+ ret\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/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 PEI/DXE #VC nesting.\r
- //\r
- if (SevEsData->VcCount > VMGEXIT_MAXIMUM_VC_COUNT) {\r
- VmgExitIssueAssert (SevEsData);\r
- } else if (SevEsData->VcCount > 1) {\r
- //\r
- // Nested #VC\r
- //\r
- if (SevEsData->GhcbBackupPages == NULL) {\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 *)SevEsData->GhcbBackupPages;\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
+++ /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
-[Defines]\r
- INF_VERSION = 0x00010005\r
- BASE_NAME = SecVmgExitLib\r
- FILE_GUID = dafff819-f86c-4cff-a70e-83161e5bcf9a\r
- MODULE_TYPE = BASE\r
- VERSION_STRING = 1.0\r
- LIBRARY_CLASS = VmgExitLib|SEC\r
-\r
-#\r
-# The following information is for reference only and not required by the build tools.\r
-#\r
-# VALID_ARCHITECTURES = X64\r
-#\r
-\r
-[Sources.common]\r
- VmgExitLib.c\r
- VmgExitVcHandler.c\r
- VmgExitVcHandler.h\r
- SecVmgExitVcHandler.c\r
- VmTdExitVeHandler.c\r
- X64/TdVmcallCpuid.nasm\r
-\r
-[Packages]\r
- MdePkg/MdePkg.dec\r
- OvmfPkg/OvmfPkg.dec\r
- UefiCpuPkg/UefiCpuPkg.dec\r
-\r
-[LibraryClasses]\r
- BaseLib\r
- BaseMemoryLib\r
- DebugLib\r
- LocalApicLib\r
- MemEncryptSevLib\r
- PcdLib\r
-\r
-[FixedPcd]\r
- gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase\r
- gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize\r
- gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase\r
- gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize\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/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
+++ /dev/null
-/** @file\r
-\r
- Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#ifndef VMTD_EXIT_HANDLER_H_\r
-#define VMTD_EXIT_HANDLER_H_\r
-\r
-#include <Base.h>\r
-#include <Uefi.h>\r
-\r
-/**\r
- This function enable the TD guest to request the VMM to emulate CPUID\r
- operation, especially for non-architectural, CPUID leaves.\r
-\r
- @param[in] Eax Main leaf of the CPUID\r
- @param[in] Ecx Sub-leaf of the CPUID\r
- @param[out] Results Returned result of CPUID operation\r
-\r
- @return EFI_SUCCESS\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-TdVmCallCpuid (\r
- IN UINT64 Eax,\r
- IN UINT64 Ecx,\r
- OUT VOID *Results\r
- );\r
-\r
-#endif\r
+++ /dev/null
-/** @file\r
-\r
- Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include <Library/BaseLib.h>\r
-#include <Library/DebugLib.h>\r
-#include "VmTdExitHandler.h"\r
-#include <Library/VmgExitLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <IndustryStandard/Tdx.h>\r
-#include <IndustryStandard/InstructionParsing.h>\r
-\r
-typedef union {\r
- struct {\r
- UINT32 Eax;\r
- UINT32 Edx;\r
- } Regs;\r
- UINT64 Val;\r
-} MSR_DATA;\r
-\r
-typedef union {\r
- UINT8 Val;\r
- struct {\r
- UINT8 B : 1;\r
- UINT8 X : 1;\r
- UINT8 R : 1;\r
- UINT8 W : 1;\r
- } Bits;\r
-} REX;\r
-\r
-typedef union {\r
- UINT8 Val;\r
- struct {\r
- UINT8 Rm : 3;\r
- UINT8 Reg : 3;\r
- UINT8 Mod : 2;\r
- } Bits;\r
-} MODRM;\r
-\r
-typedef struct {\r
- UINT64 Regs[4];\r
-} CPUID_DATA;\r
-\r
-/**\r
- Handle an CPUID event.\r
-\r
- Use the TDVMCALL instruction to handle cpuid #ve\r
-\r
- @param[in, out] Regs x64 processor context\r
- @param[in] Veinfo VE Info\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-**/\r
-STATIC\r
-UINT64\r
-EFIAPI\r
-CpuIdExit (\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
- )\r
-{\r
- CPUID_DATA CpuIdData;\r
- UINT64 Status;\r
-\r
- Status = TdVmCallCpuid (Regs->Rax, Regs->Rcx, &CpuIdData);\r
-\r
- if (Status == 0) {\r
- Regs->Rax = CpuIdData.Regs[0];\r
- Regs->Rbx = CpuIdData.Regs[1];\r
- Regs->Rcx = CpuIdData.Regs[2];\r
- Regs->Rdx = CpuIdData.Regs[3];\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Handle an IO event.\r
-\r
- Use the TDVMCALL instruction to handle either an IO read or an IO write.\r
-\r
- @param[in, out] Regs x64 processor context\r
- @param[in] Veinfo VE Info\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-**/\r
-STATIC\r
-UINT64\r
-EFIAPI\r
-IoExit (\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
- )\r
-{\r
- BOOLEAN Write;\r
- UINTN Size;\r
- UINTN Port;\r
- UINT64 Val;\r
- UINT64 RepCnt;\r
- UINT64 Status;\r
-\r
- Val = 0;\r
- Write = Veinfo->ExitQualification.Io.Direction ? FALSE : TRUE;\r
- Size = Veinfo->ExitQualification.Io.Size + 1;\r
- Port = Veinfo->ExitQualification.Io.Port;\r
-\r
- if (Veinfo->ExitQualification.Io.String) {\r
- //\r
- // If REP is set, get rep-cnt from Rcx\r
- //\r
- RepCnt = Veinfo->ExitQualification.Io.Rep ? Regs->Rcx : 1;\r
-\r
- while (RepCnt) {\r
- Val = 0;\r
- if (Write == TRUE) {\r
- CopyMem (&Val, (VOID *)Regs->Rsi, Size);\r
- Regs->Rsi += Size;\r
- }\r
-\r
- Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));\r
- if (Status != 0) {\r
- break;\r
- }\r
-\r
- if (Write == FALSE) {\r
- CopyMem ((VOID *)Regs->Rdi, &Val, Size);\r
- Regs->Rdi += Size;\r
- }\r
-\r
- if (Veinfo->ExitQualification.Io.Rep) {\r
- Regs->Rcx -= 1;\r
- }\r
-\r
- RepCnt -= 1;\r
- }\r
- } else {\r
- if (Write == TRUE) {\r
- CopyMem (&Val, (VOID *)&Regs->Rax, Size);\r
- }\r
-\r
- Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));\r
- if ((Status == 0) && (Write == FALSE)) {\r
- CopyMem ((VOID *)&Regs->Rax, &Val, Size);\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Handle an READ MSR event.\r
-\r
- Use the TDVMCALL instruction to handle msr read\r
-\r
- @param[in, out] Regs x64 processor context\r
- @param[in] Veinfo VE Info\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-**/\r
-STATIC\r
-UINT64\r
-ReadMsrExit (\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
- )\r
-{\r
- MSR_DATA Data;\r
- UINT64 Status;\r
-\r
- Status = TdVmCall (EXIT_REASON_MSR_READ, Regs->Rcx, 0, 0, 0, &Data);\r
- if (Status == 0) {\r
- Regs->Rax = Data.Regs.Eax;\r
- Regs->Rdx = Data.Regs.Edx;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Handle an WRITE MSR event.\r
-\r
- Use the TDVMCALL instruction to handle msr write\r
-\r
- @param[in, out] Regs x64 processor context\r
- @param[in] Veinfo VE Info\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-**/\r
-STATIC\r
-UINT64\r
-WriteMsrExit (\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
- )\r
-{\r
- UINT64 Status;\r
- MSR_DATA Data;\r
-\r
- Data.Regs.Eax = (UINT32)Regs->Rax;\r
- Data.Regs.Edx = (UINT32)Regs->Rdx;\r
-\r
- Status = TdVmCall (EXIT_REASON_MSR_WRITE, Regs->Rcx, Data.Val, 0, 0, NULL);\r
-\r
- return Status;\r
-}\r
-\r
-STATIC\r
-VOID\r
-EFIAPI\r
-TdxDecodeInstruction (\r
- IN UINT8 *Rip\r
- )\r
-{\r
- UINTN i;\r
-\r
- DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip));\r
- for (i = 0; i < 15; i++) {\r
- DEBUG ((DEBUG_INFO, "%02x:", Rip[i]));\r
- }\r
-\r
- DEBUG ((DEBUG_INFO, "\n"));\r
-}\r
-\r
-#define TDX_DECODER_BUG_ON(x) \\r
- if ((x)) { \\r
- TdxDecodeInstruction(Rip); \\r
- TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \\r
- }\r
-\r
-STATIC\r
-UINT64 *\r
-EFIAPI\r
-GetRegFromContext (\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN UINTN RegIndex\r
- )\r
-{\r
- switch (RegIndex) {\r
- case 0: return &Regs->Rax;\r
- break;\r
- case 1: return &Regs->Rcx;\r
- break;\r
- case 2: return &Regs->Rdx;\r
- break;\r
- case 3: return &Regs->Rbx;\r
- break;\r
- case 4: return &Regs->Rsp;\r
- break;\r
- case 5: return &Regs->Rbp;\r
- break;\r
- case 6: return &Regs->Rsi;\r
- break;\r
- case 7: return &Regs->Rdi;\r
- break;\r
- case 8: return &Regs->R8;\r
- break;\r
- case 9: return &Regs->R9;\r
- break;\r
- case 10: return &Regs->R10;\r
- break;\r
- case 11: return &Regs->R11;\r
- break;\r
- case 12: return &Regs->R12;\r
- break;\r
- case 13: return &Regs->R13;\r
- break;\r
- case 14: return &Regs->R14;\r
- break;\r
- case 15: return &Regs->R15;\r
- break;\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- Handle an MMIO event.\r
-\r
- Use the TDVMCALL instruction to handle either an mmio read or an mmio write.\r
-\r
- @param[in, out] Regs x64 processor context\r
- @param[in] Veinfo VE Info\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-**/\r
-STATIC\r
-INTN\r
-EFIAPI\r
-MmioExit (\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN TDCALL_VEINFO_RETURN_DATA *Veinfo\r
- )\r
-{\r
- UINT64 Status;\r
- UINT32 MmioSize;\r
- UINT32 RegSize;\r
- UINT8 OpCode;\r
- BOOLEAN SeenRex;\r
- UINT64 *Reg;\r
- UINT8 *Rip;\r
- UINT64 Val;\r
- UINT32 OpSize;\r
- MODRM ModRm;\r
- REX Rex;\r
- TD_RETURN_DATA TdReturnData;\r
- UINT8 Gpaw;\r
- UINT64 TdSharedPageMask;\r
-\r
- Rip = (UINT8 *)Regs->Rip;\r
- Val = 0;\r
- Rex.Val = 0;\r
- SeenRex = FALSE;\r
-\r
- Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);\r
- if (Status == TDX_EXIT_REASON_SUCCESS) {\r
- Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f);\r
- TdSharedPageMask = 1ULL << (Gpaw - 1);\r
- } else {\r
- DEBUG ((DEBUG_ERROR, "TDCALL failed with status=%llx\n", Status));\r
- return Status;\r
- }\r
-\r
- if ((Veinfo->GuestPA & TdSharedPageMask) == 0) {\r
- DEBUG ((DEBUG_ERROR, "EPT-violation #VE on private memory is not allowed!"));\r
- TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
- CpuDeadLoop ();\r
- }\r
-\r
- //\r
- // Default to 32bit transfer\r
- //\r
- OpSize = 4;\r
-\r
- do {\r
- OpCode = *Rip++;\r
- if (OpCode == 0x66) {\r
- OpSize = 2;\r
- } else if ((OpCode == 0x64) || (OpCode == 0x65) || (OpCode == 0x67)) {\r
- continue;\r
- } else if ((OpCode >= 0x40) && (OpCode <= 0x4f)) {\r
- SeenRex = TRUE;\r
- Rex.Val = OpCode;\r
- } else {\r
- break;\r
- }\r
- } while (TRUE);\r
-\r
- //\r
- // We need to have at least 2 more bytes for this instruction\r
- //\r
- TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 13);\r
-\r
- OpCode = *Rip++;\r
- //\r
- // Two-byte opecode, get next byte\r
- //\r
- if (OpCode == 0x0F) {\r
- OpCode = *Rip++;\r
- }\r
-\r
- switch (OpCode) {\r
- case 0x88:\r
- case 0x8A:\r
- case 0xB6:\r
- MmioSize = 1;\r
- break;\r
- case 0xB7:\r
- MmioSize = 2;\r
- break;\r
- default:\r
- MmioSize = Rex.Bits.W ? 8 : OpSize;\r
- break;\r
- }\r
-\r
- /* Punt on AH/BH/CH/DH unless it shows up. */\r
- ModRm.Val = *Rip++;\r
- TDX_DECODER_BUG_ON (MmioSize == 1 && ModRm.Bits.Reg > 4 && !SeenRex && OpCode != 0xB6);\r
- Reg = GetRegFromContext (Regs, ModRm.Bits.Reg | ((int)Rex.Bits.R << 3));\r
- TDX_DECODER_BUG_ON (!Reg);\r
-\r
- if (ModRm.Bits.Rm == 4) {\r
- ++Rip; /* SIB byte */\r
- }\r
-\r
- if ((ModRm.Bits.Mod == 2) || ((ModRm.Bits.Mod == 0) && (ModRm.Bits.Rm == 5))) {\r
- Rip += 4; /* DISP32 */\r
- } else if (ModRm.Bits.Mod == 1) {\r
- ++Rip; /* DISP8 */\r
- }\r
-\r
- switch (OpCode) {\r
- case 0x88:\r
- case 0x89:\r
- CopyMem ((void *)&Val, Reg, MmioSize);\r
- Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);\r
- break;\r
- case 0xC7:\r
- CopyMem ((void *)&Val, Rip, OpSize);\r
- Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);\r
- Rip += OpSize;\r
- default:\r
- //\r
- // 32-bit write registers are zero extended to the full register\r
- // Hence 'MOVZX r[32/64], r/m16' is\r
- // hardcoded to reg size 8, and the straight MOV case has a reg\r
- // size of 8 in the 32-bit read case.\r
- //\r
- switch (OpCode) {\r
- case 0xB6:\r
- RegSize = Rex.Bits.W ? 8 : OpSize;\r
- break;\r
- case 0xB7:\r
- RegSize = 8;\r
- break;\r
- default:\r
- RegSize = MmioSize == 4 ? 8 : MmioSize;\r
- break;\r
- }\r
-\r
- Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 0, Veinfo->GuestPA, 0, &Val);\r
- if (Status == 0) {\r
- ZeroMem (Reg, RegSize);\r
- CopyMem (Reg, (void *)&Val, MmioSize);\r
- }\r
- }\r
-\r
- if (Status == 0) {\r
- TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15);\r
-\r
- //\r
- // We change instruction length to reflect true size so handler can\r
- // bump rip\r
- //\r
- Veinfo->ExitInstructionLength = (UINT32)((UINT64)Rip - Regs->Rip);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Handle a #VE exception.\r
-\r
- Performs the necessary processing to handle a #VE 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 #VE not supported, (new) exception value to\r
- propagate provided\r
- @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to\r
- propagate provided\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-VmTdExitHandleVe (\r
- IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
- IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
- )\r
-{\r
- UINT64 Status;\r
- TD_RETURN_DATA ReturnData;\r
- EFI_SYSTEM_CONTEXT_X64 *Regs;\r
-\r
- Regs = SystemContext.SystemContextX64;\r
- Status = TdCall (TDCALL_TDGETVEINFO, 0, 0, 0, &ReturnData);\r
- ASSERT (Status == 0);\r
- if (Status != 0) {\r
- DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status = 0x%llx\n", Status));\r
- TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
- }\r
-\r
- switch (ReturnData.VeInfo.ExitReason) {\r
- case EXIT_REASON_CPUID:\r
- Status = CpuIdExit (Regs, &ReturnData.VeInfo);\r
- DEBUG ((\r
- DEBUG_VERBOSE,\r
- "CPUID #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",\r
- ReturnData.VeInfo.ExitReason,\r
- ReturnData.VeInfo.ExitQualification.Val\r
- ));\r
- break;\r
-\r
- case EXIT_REASON_HLT:\r
- Status = TdVmCall (EXIT_REASON_HLT, 0, 0, 0, 0, 0);\r
- break;\r
-\r
- case EXIT_REASON_IO_INSTRUCTION:\r
- Status = IoExit (Regs, &ReturnData.VeInfo);\r
- DEBUG ((\r
- DEBUG_VERBOSE,\r
- "IO_Instruction #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",\r
- ReturnData.VeInfo.ExitReason,\r
- ReturnData.VeInfo.ExitQualification.Val\r
- ));\r
- break;\r
-\r
- case EXIT_REASON_MSR_READ:\r
- Status = ReadMsrExit (Regs, &ReturnData.VeInfo);\r
- DEBUG ((\r
- DEBUG_VERBOSE,\r
- "RDMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",\r
- ReturnData.VeInfo.ExitReason,\r
- ReturnData.VeInfo.ExitQualification.Val,\r
- Regs->Rcx,\r
- Status\r
- ));\r
- break;\r
-\r
- case EXIT_REASON_MSR_WRITE:\r
- Status = WriteMsrExit (Regs, &ReturnData.VeInfo);\r
- DEBUG ((\r
- DEBUG_VERBOSE,\r
- "WRMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",\r
- ReturnData.VeInfo.ExitReason,\r
- ReturnData.VeInfo.ExitQualification.Val,\r
- Regs->Rcx,\r
- Status\r
- ));\r
- break;\r
-\r
- case EXIT_REASON_EPT_VIOLATION:\r
- Status = MmioExit (Regs, &ReturnData.VeInfo);\r
- DEBUG ((\r
- DEBUG_VERBOSE,\r
- "MMIO #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",\r
- ReturnData.VeInfo.ExitReason,\r
- ReturnData.VeInfo.ExitQualification.Val\r
- ));\r
- break;\r
-\r
- case EXIT_REASON_VMCALL:\r
- case EXIT_REASON_MWAIT_INSTRUCTION:\r
- case EXIT_REASON_MONITOR_INSTRUCTION:\r
- case EXIT_REASON_WBINVD:\r
- case EXIT_REASON_RDPMC:\r
- /* Handle as nops. */\r
- break;\r
-\r
- default:\r
- DEBUG ((\r
- DEBUG_ERROR,\r
- "Unsupported #VE happened, ExitReason is %d, ExitQualification = 0x%x.\n",\r
- ReturnData.VeInfo.ExitReason,\r
- ReturnData.VeInfo.ExitQualification.Val\r
- ));\r
-\r
- ASSERT (FALSE);\r
- CpuDeadLoop ();\r
- }\r
-\r
- if (Status) {\r
- DEBUG ((\r
- DEBUG_ERROR,\r
- "#VE Error (0x%llx) returned from host, ExitReason is %d, ExitQualification = 0x%x.\n",\r
- Status,\r
- ReturnData.VeInfo.ExitReason,\r
- ReturnData.VeInfo.ExitQualification.Val\r
- ));\r
-\r
- TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
- }\r
-\r
- SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength;\r
- return EFI_SUCCESS;\r
-}\r
+++ /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 (\r
- (ExitInfo.Elements.Lower32Bits == 0) ||\r
- (ExitInfo.Elements.Lower32Bits == 1)\r
- );\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
- {\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
- VmgSetOffsetValid (Ghcb, GhcbSwExitCode);\r
- VmgSetOffsetValid (Ghcb, GhcbSwExitInfo1);\r
- VmgSetOffsetValid (Ghcb, GhcbSwExitInfo2);\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
- @param[in, out] InterruptState A pointer to hold the current interrupt\r
- state, used for restoring in VmgDone ()\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgInit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT BOOLEAN *InterruptState\r
- )\r
-{\r
- //\r
- // Be sure that an interrupt can't cause a #VC while the GHCB is\r
- // being used.\r
- //\r
- *InterruptState = GetInterruptState ();\r
- if (*InterruptState) {\r
- DisableInterrupts ();\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
- @param[in] InterruptState An indicator to conditionally (re)enable\r
- interrupts\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgDone (\r
- IN OUT GHCB *Ghcb,\r
- IN BOOLEAN InterruptState\r
- )\r
-{\r
- if (InterruptState) {\r
- EnableInterrupts ();\r
- }\r
-}\r
-\r
-/**\r
- Marks a field at the specified offset as valid in the GHCB.\r
-\r
- The ValidBitmap area represents the areas of the GHCB that have been marked\r
- valid. Set the bit in ValidBitmap for the input offset.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
- @param[in] Offset Qword offset in the GHCB to mark valid\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgSetOffsetValid (\r
- IN OUT GHCB *Ghcb,\r
- IN GHCB_REGISTER Offset\r
- )\r
-{\r
- UINT32 OffsetIndex;\r
- UINT32 OffsetBit;\r
-\r
- OffsetIndex = Offset / 8;\r
- OffsetBit = Offset % 8;\r
-\r
- Ghcb->SaveArea.ValidBitmap[OffsetIndex] |= (1 << OffsetBit);\r
-}\r
-\r
-/**\r
- Checks if a specified offset is valid in the GHCB.\r
-\r
- The ValidBitmap area represents the areas of the GHCB that have been marked\r
- valid. Return whether the bit in the ValidBitmap is set for the input offset.\r
-\r
- @param[in] Ghcb A pointer to the GHCB\r
- @param[in] Offset Qword offset in the GHCB to mark valid\r
-\r
- @retval TRUE Offset is marked valid in the GHCB\r
- @retval FALSE Offset is not marked valid in the GHCB\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-VmgIsOffsetValid (\r
- IN GHCB *Ghcb,\r
- IN GHCB_REGISTER Offset\r
- )\r
-{\r
- UINT32 OffsetIndex;\r
- UINT32 OffsetBit;\r
-\r
- OffsetIndex = Offset / 8;\r
- OffsetBit = Offset % 8;\r
-\r
- return ((Ghcb->SaveArea.ValidBitmap[OffsetIndex] & (1 << OffsetBit)) != 0);\r
-}\r
+++ /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
-[Defines]\r
- INF_VERSION = 0x00010005\r
- BASE_NAME = VmgExitLib\r
- FILE_GUID = 0e923c25-13cd-430b-8714-ffe85652a97b\r
- MODULE_TYPE = BASE\r
- VERSION_STRING = 1.0\r
- LIBRARY_CLASS = VmgExitLib|PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER\r
-\r
-#\r
-# The following information is for reference only and not required by the build tools.\r
-#\r
-# VALID_ARCHITECTURES = X64\r
-#\r
-\r
-[Sources.common]\r
- VmgExitLib.c\r
- VmgExitVcHandler.c\r
- VmgExitVcHandler.h\r
- PeiDxeVmgExitVcHandler.c\r
- VmTdExitVeHandler.c\r
- X64/TdVmcallCpuid.nasm\r
-\r
-[Packages]\r
- MdePkg/MdePkg.dec\r
- OvmfPkg/OvmfPkg.dec\r
- UefiCpuPkg/UefiCpuPkg.dec\r
-\r
-[LibraryClasses]\r
- BaseLib\r
- BaseMemoryLib\r
- DebugLib\r
- LocalApicLib\r
- MemEncryptSevLib\r
-\r
-[Pcd]\r
- gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase\r
- gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize\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/LocalApicLib.h>\r
-#include <Library/MemEncryptSevLib.h>\r
-#include <Library/VmgExitLib.h>\r
-#include <Register/Amd/Msr.h>\r
-#include <Register/Intel/Cpuid.h>\r
-#include <IndustryStandard/InstructionParsing.h>\r
-\r
-#include "VmgExitVcHandler.h"\r
-// #include <Library/MemEncryptSevLib.h>\r
-\r
-//\r
-// Instruction execution mode definition\r
-//\r
-typedef enum {\r
- LongMode64Bit = 0,\r
- LongModeCompat32Bit,\r
- LongModeCompat16Bit,\r
-} SEV_ES_INSTRUCTION_MODE;\r
-\r
-//\r
-// Instruction size definition (for operand and address)\r
-//\r
-typedef enum {\r
- Size8Bits = 0,\r
- Size16Bits,\r
- Size32Bits,\r
- Size64Bits,\r
-} SEV_ES_INSTRUCTION_SIZE;\r
-\r
-//\r
-// Intruction segment definition\r
-//\r
-typedef enum {\r
- SegmentEs = 0,\r
- SegmentCs,\r
- SegmentSs,\r
- SegmentDs,\r
- SegmentFs,\r
- SegmentGs,\r
-} SEV_ES_INSTRUCTION_SEGMENT;\r
-\r
-//\r
-// Instruction rep function definition\r
-//\r
-typedef enum {\r
- RepNone = 0,\r
- RepZ,\r
- RepNZ,\r
-} SEV_ES_INSTRUCTION_REP;\r
-\r
-typedef struct {\r
- UINT8 Rm;\r
- UINT8 Reg;\r
- UINT8 Mod;\r
-} SEV_ES_INSTRUCTION_MODRM_EXT;\r
-\r
-typedef struct {\r
- UINT8 Base;\r
- UINT8 Index;\r
- UINT8 Scale;\r
-} SEV_ES_INSTRUCTION_SIB_EXT;\r
-\r
-//\r
-// Instruction opcode definition\r
-//\r
-typedef struct {\r
- SEV_ES_INSTRUCTION_MODRM_EXT ModRm;\r
-\r
- SEV_ES_INSTRUCTION_SIB_EXT Sib;\r
-\r
- UINTN RegData;\r
- UINTN RmData;\r
-} SEV_ES_INSTRUCTION_OPCODE_EXT;\r
-\r
-//\r
-// Instruction parsing context definition\r
-//\r
-typedef struct {\r
- GHCB *Ghcb;\r
-\r
- SEV_ES_INSTRUCTION_MODE Mode;\r
- SEV_ES_INSTRUCTION_SIZE DataSize;\r
- SEV_ES_INSTRUCTION_SIZE AddrSize;\r
- BOOLEAN SegmentSpecified;\r
- SEV_ES_INSTRUCTION_SEGMENT Segment;\r
- SEV_ES_INSTRUCTION_REP RepMode;\r
-\r
- UINT8 *Begin;\r
- UINT8 *End;\r
-\r
- UINT8 *Prefixes;\r
- UINT8 *OpCodes;\r
- UINT8 *Displacement;\r
- UINT8 *Immediate;\r
-\r
- INSTRUCTION_REX_PREFIX RexPrefix;\r
-\r
- BOOLEAN ModRmPresent;\r
- INSTRUCTION_MODRM ModRm;\r
-\r
- BOOLEAN SibPresent;\r
- INSTRUCTION_SIB Sib;\r
-\r
- UINTN PrefixSize;\r
- UINTN OpCodeSize;\r
- UINTN DisplacementSize;\r
- UINTN ImmediateSize;\r
-\r
- SEV_ES_INSTRUCTION_OPCODE_EXT Ext;\r
-} SEV_ES_INSTRUCTION_DATA;\r
-\r
-//\r
-// Non-automatic Exit function prototype\r
-//\r
-typedef\r
-UINT64\r
-(*NAE_EXIT) (\r
- GHCB *Ghcb,\r
- EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- SEV_ES_INSTRUCTION_DATA *InstructionData\r
- );\r
-\r
-//\r
-// SEV-SNP Cpuid table entry/function\r
-//\r
-typedef PACKED struct {\r
- UINT32 EaxIn;\r
- UINT32 EcxIn;\r
- UINT64 Unused;\r
- UINT64 Unused2;\r
- UINT32 Eax;\r
- UINT32 Ebx;\r
- UINT32 Ecx;\r
- UINT32 Edx;\r
- UINT64 Reserved;\r
-} SEV_SNP_CPUID_FUNCTION;\r
-\r
-//\r
-// SEV-SNP Cpuid page format\r
-//\r
-typedef PACKED struct {\r
- UINT32 Count;\r
- UINT32 Reserved1;\r
- UINT64 Reserved2;\r
- SEV_SNP_CPUID_FUNCTION function[0];\r
-} SEV_SNP_CPUID_INFO;\r
-\r
-/**\r
- Return a pointer to the contents of the specified register.\r
-\r
- Based upon the input register, return a pointer to the registers contents\r
- in the x86 processor context.\r
-\r
- @param[in] Regs x64 processor context\r
- @param[in] Register Register to obtain pointer for\r
-\r
- @return Pointer to the contents of the requested register\r
-\r
-**/\r
-STATIC\r
-UINT64 *\r
-GetRegisterPointer (\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN UINT8 Register\r
- )\r
-{\r
- UINT64 *Reg;\r
-\r
- switch (Register) {\r
- case 0:\r
- Reg = &Regs->Rax;\r
- break;\r
- case 1:\r
- Reg = &Regs->Rcx;\r
- break;\r
- case 2:\r
- Reg = &Regs->Rdx;\r
- break;\r
- case 3:\r
- Reg = &Regs->Rbx;\r
- break;\r
- case 4:\r
- Reg = &Regs->Rsp;\r
- break;\r
- case 5:\r
- Reg = &Regs->Rbp;\r
- break;\r
- case 6:\r
- Reg = &Regs->Rsi;\r
- break;\r
- case 7:\r
- Reg = &Regs->Rdi;\r
- break;\r
- case 8:\r
- Reg = &Regs->R8;\r
- break;\r
- case 9:\r
- Reg = &Regs->R9;\r
- break;\r
- case 10:\r
- Reg = &Regs->R10;\r
- break;\r
- case 11:\r
- Reg = &Regs->R11;\r
- break;\r
- case 12:\r
- Reg = &Regs->R12;\r
- break;\r
- case 13:\r
- Reg = &Regs->R13;\r
- break;\r
- case 14:\r
- Reg = &Regs->R14;\r
- break;\r
- case 15:\r
- Reg = &Regs->R15;\r
- break;\r
- default:\r
- Reg = NULL;\r
- }\r
-\r
- ASSERT (Reg != NULL);\r
-\r
- return Reg;\r
-}\r
-\r
-/**\r
- Update the instruction parsing context for displacement bytes.\r
-\r
- @param[in, out] InstructionData Instruction parsing context\r
- @param[in] Size The instruction displacement size\r
-\r
-**/\r
-STATIC\r
-VOID\r
-UpdateForDisplacement (\r
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
- IN UINTN Size\r
- )\r
-{\r
- InstructionData->DisplacementSize = Size;\r
- InstructionData->Immediate += Size;\r
- InstructionData->End += Size;\r
-}\r
-\r
-/**\r
- Determine if an instruction address if RIP relative.\r
-\r
- Examine the instruction parsing context to determine if the address offset\r
- is relative to the instruction pointer.\r
-\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval TRUE Instruction addressing is RIP relative\r
- @retval FALSE Instruction addressing is not RIP relative\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-IsRipRelative (\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
-\r
- Ext = &InstructionData->Ext;\r
-\r
- return ((InstructionData->Mode == LongMode64Bit) &&\r
- (Ext->ModRm.Mod == 0) &&\r
- (Ext->ModRm.Rm == 5) &&\r
- (InstructionData->SibPresent == FALSE));\r
-}\r
-\r
-/**\r
- Return the effective address of a memory operand.\r
-\r
- Examine the instruction parsing context to obtain the effective memory\r
- address of a memory operand.\r
-\r
- @param[in] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @return The memory operand effective address\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-GetEffectiveMemoryAddress (\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
- UINT64 EffectiveAddress;\r
-\r
- Ext = &InstructionData->Ext;\r
- EffectiveAddress = 0;\r
-\r
- if (IsRipRelative (InstructionData)) {\r
- //\r
- // RIP-relative displacement is a 32-bit signed value\r
- //\r
- INT32 RipRelative;\r
-\r
- RipRelative = *(INT32 *)InstructionData->Displacement;\r
-\r
- UpdateForDisplacement (InstructionData, 4);\r
-\r
- //\r
- // Negative displacement is handled by standard UINT64 wrap-around.\r
- //\r
- return Regs->Rip + (UINT64)RipRelative;\r
- }\r
-\r
- switch (Ext->ModRm.Mod) {\r
- case 1:\r
- UpdateForDisplacement (InstructionData, 1);\r
- EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement));\r
- break;\r
- case 2:\r
- switch (InstructionData->AddrSize) {\r
- case Size16Bits:\r
- UpdateForDisplacement (InstructionData, 2);\r
- EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement));\r
- break;\r
- default:\r
- UpdateForDisplacement (InstructionData, 4);\r
- EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
- break;\r
- }\r
-\r
- break;\r
- }\r
-\r
- if (InstructionData->SibPresent) {\r
- INT64 Displacement;\r
-\r
- if (Ext->Sib.Index != 4) {\r
- CopyMem (\r
- &Displacement,\r
- GetRegisterPointer (Regs, Ext->Sib.Index),\r
- sizeof (Displacement)\r
- );\r
- Displacement *= (INT64)(1 << Ext->Sib.Scale);\r
-\r
- //\r
- // Negative displacement is handled by standard UINT64 wrap-around.\r
- //\r
- EffectiveAddress += (UINT64)Displacement;\r
- }\r
-\r
- if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {\r
- EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);\r
- } else {\r
- UpdateForDisplacement (InstructionData, 4);\r
- EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
- }\r
- } else {\r
- EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
- }\r
-\r
- return EffectiveAddress;\r
-}\r
-\r
-/**\r
- Decode a ModRM byte.\r
-\r
- Examine the instruction parsing context to decode a ModRM byte and the SIB\r
- byte, if present.\r
-\r
- @param[in] Regs x64 processor context\r
- @param[in, out] InstructionData Instruction parsing context\r
-\r
-**/\r
-STATIC\r
-VOID\r
-DecodeModRm (\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
- INSTRUCTION_REX_PREFIX *RexPrefix;\r
- INSTRUCTION_MODRM *ModRm;\r
- INSTRUCTION_SIB *Sib;\r
-\r
- RexPrefix = &InstructionData->RexPrefix;\r
- Ext = &InstructionData->Ext;\r
- ModRm = &InstructionData->ModRm;\r
- Sib = &InstructionData->Sib;\r
-\r
- InstructionData->ModRmPresent = TRUE;\r
- ModRm->Uint8 = *(InstructionData->End);\r
-\r
- InstructionData->Displacement++;\r
- InstructionData->Immediate++;\r
- InstructionData->End++;\r
-\r
- Ext->ModRm.Mod = ModRm->Bits.Mod;\r
- Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg;\r
- Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm;\r
-\r
- Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);\r
-\r
- if (Ext->ModRm.Mod == 3) {\r
- Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
- } else {\r
- if (ModRm->Bits.Rm == 4) {\r
- InstructionData->SibPresent = TRUE;\r
- Sib->Uint8 = *(InstructionData->End);\r
-\r
- InstructionData->Displacement++;\r
- InstructionData->Immediate++;\r
- InstructionData->End++;\r
-\r
- Ext->Sib.Scale = Sib->Bits.Scale;\r
- Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index;\r
- Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base;\r
- }\r
-\r
- Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);\r
- }\r
-}\r
-\r
-/**\r
- Decode instruction prefixes.\r
-\r
- Parse the instruction data to track the instruction prefixes that have\r
- been used.\r
-\r
- @param[in] Regs x64 processor context\r
- @param[in, out] InstructionData Instruction parsing context\r
-\r
-**/\r
-STATIC\r
-VOID\r
-DecodePrefixes (\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- SEV_ES_INSTRUCTION_MODE Mode;\r
- SEV_ES_INSTRUCTION_SIZE ModeDataSize;\r
- SEV_ES_INSTRUCTION_SIZE ModeAddrSize;\r
- UINT8 *Byte;\r
-\r
- //\r
- // Always in 64-bit mode\r
- //\r
- Mode = LongMode64Bit;\r
- ModeDataSize = Size32Bits;\r
- ModeAddrSize = Size64Bits;\r
-\r
- InstructionData->Mode = Mode;\r
- InstructionData->DataSize = ModeDataSize;\r
- InstructionData->AddrSize = ModeAddrSize;\r
-\r
- InstructionData->Prefixes = InstructionData->Begin;\r
-\r
- Byte = InstructionData->Prefixes;\r
- for ( ; ; Byte++, InstructionData->PrefixSize++) {\r
- //\r
- // Check the 0x40 to 0x4F range using an if statement here since some\r
- // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids\r
- // 16 case statements below.\r
- //\r
- if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {\r
- InstructionData->RexPrefix.Uint8 = *Byte;\r
- if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {\r
- InstructionData->DataSize = Size64Bits;\r
- }\r
-\r
- continue;\r
- }\r
-\r
- switch (*Byte) {\r
- case OVERRIDE_SEGMENT_CS:\r
- case OVERRIDE_SEGMENT_DS:\r
- case OVERRIDE_SEGMENT_ES:\r
- case OVERRIDE_SEGMENT_SS:\r
- if (Mode != LongMode64Bit) {\r
- InstructionData->SegmentSpecified = TRUE;\r
- InstructionData->Segment = (*Byte >> 3) & 3;\r
- }\r
-\r
- break;\r
-\r
- case OVERRIDE_SEGMENT_FS:\r
- case OVERRIDE_SEGMENT_GS:\r
- InstructionData->SegmentSpecified = TRUE;\r
- InstructionData->Segment = *Byte & 7;\r
- break;\r
-\r
- case OVERRIDE_OPERAND_SIZE:\r
- if (InstructionData->RexPrefix.Uint8 == 0) {\r
- InstructionData->DataSize =\r
- (Mode == LongMode64Bit) ? Size16Bits :\r
- (Mode == LongModeCompat32Bit) ? Size16Bits :\r
- (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
- }\r
-\r
- break;\r
-\r
- case OVERRIDE_ADDRESS_SIZE:\r
- InstructionData->AddrSize =\r
- (Mode == LongMode64Bit) ? Size32Bits :\r
- (Mode == LongModeCompat32Bit) ? Size16Bits :\r
- (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
- break;\r
-\r
- case LOCK_PREFIX:\r
- break;\r
-\r
- case REPZ_PREFIX:\r
- InstructionData->RepMode = RepZ;\r
- break;\r
-\r
- case REPNZ_PREFIX:\r
- InstructionData->RepMode = RepNZ;\r
- break;\r
-\r
- default:\r
- InstructionData->OpCodes = Byte;\r
- InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;\r
-\r
- InstructionData->End = Byte + InstructionData->OpCodeSize;\r
- InstructionData->Displacement = InstructionData->End;\r
- InstructionData->Immediate = InstructionData->End;\r
- return;\r
- }\r
- }\r
-}\r
-\r
-/**\r
- Determine instruction length\r
-\r
- Return the total length of the parsed instruction.\r
-\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @return Length of parsed instruction\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-InstructionLength (\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- return (UINT64)(InstructionData->End - InstructionData->Begin);\r
-}\r
-\r
-/**\r
- Initialize the instruction parsing context.\r
-\r
- Initialize the instruction parsing context, which includes decoding the\r
- instruction prefixes.\r
-\r
- @param[in, out] InstructionData Instruction parsing context\r
- @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in] Regs x64 processor context\r
-\r
-**/\r
-STATIC\r
-VOID\r
-InitInstructionData (\r
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
- IN GHCB *Ghcb,\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs\r
- )\r
-{\r
- SetMem (InstructionData, sizeof (*InstructionData), 0);\r
- InstructionData->Ghcb = Ghcb;\r
- InstructionData->Begin = (UINT8 *)Regs->Rip;\r
- InstructionData->End = (UINT8 *)Regs->Rip;\r
-\r
- DecodePrefixes (Regs, InstructionData);\r
-}\r
-\r
-/**\r
- Report an unsupported event to the hypervisor\r
-\r
- Use the VMGEXIT support to report an unsupported event to the hypervisor.\r
-\r
- @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-UnsupportedExit (\r
- IN GHCB *Ghcb,\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 Status;\r
-\r
- Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);\r
- if (Status == 0) {\r
- GHCB_EVENT_INJECTION Event;\r
-\r
- Event.Uint64 = 0;\r
- Event.Elements.Vector = GP_EXCEPTION;\r
- Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
- Event.Elements.Valid = 1;\r
-\r
- Status = Event.Uint64;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Validate that the MMIO memory access is not to encrypted memory.\r
-\r
- Examine the pagetable entry for the memory specified. MMIO should not be\r
- performed against encrypted memory. MMIO to the APIC page is always allowed.\r
-\r
- @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
- @param[in] MemoryAddress Memory address to validate\r
- @param[in] MemoryLength Memory length to validate\r
-\r
- @retval 0 Memory is not encrypted\r
- @return New exception value to propogate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-ValidateMmioMemory (\r
- IN GHCB *Ghcb,\r
- IN UINTN MemoryAddress,\r
- IN UINTN MemoryLength\r
- )\r
-{\r
- MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;\r
- GHCB_EVENT_INJECTION GpEvent;\r
- UINTN Address;\r
-\r
- //\r
- // Allow APIC accesses (which will have the encryption bit set during\r
- // SEC and PEI phases).\r
- //\r
- Address = MemoryAddress & ~(SIZE_4KB - 1);\r
- if (Address == GetLocalApicBaseAddress ()) {\r
- return 0;\r
- }\r
-\r
- State = MemEncryptSevGetAddressRangeState (\r
- 0,\r
- MemoryAddress,\r
- MemoryLength\r
- );\r
- if (State == MemEncryptSevAddressRangeUnencrypted) {\r
- return 0;\r
- }\r
-\r
- //\r
- // Any state other than unencrypted is an error, issue a #GP.\r
- //\r
- DEBUG ((\r
- DEBUG_ERROR,\r
- "MMIO using encrypted memory: %lx\n",\r
- (UINT64)MemoryAddress\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
- return GpEvent.Uint64;\r
-}\r
-\r
-/**\r
- Handle an MMIO event.\r
-\r
- Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in, out] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-MmioExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 ExitInfo1, ExitInfo2, Status;\r
- UINTN Bytes;\r
- UINT64 *Register;\r
- UINT8 OpCode, SignByte;\r
- UINTN Address;\r
-\r
- Bytes = 0;\r
-\r
- OpCode = *(InstructionData->OpCodes);\r
- if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {\r
- OpCode = *(InstructionData->OpCodes + 1);\r
- }\r
-\r
- switch (OpCode) {\r
- //\r
- // MMIO write (MOV reg/memX, regX)\r
- //\r
- case 0x88:\r
- Bytes = 1;\r
- //\r
- // fall through\r
- //\r
- case 0x89:\r
- DecodeModRm (Regs, InstructionData);\r
- Bytes = ((Bytes != 0) ? Bytes :\r
- (InstructionData->DataSize == Size16Bits) ? 2 :\r
- (InstructionData->DataSize == Size32Bits) ? 4 :\r
- (InstructionData->DataSize == Size64Bits) ? 8 :\r
- 0);\r
-\r
- if (InstructionData->Ext.ModRm.Mod == 3) {\r
- //\r
- // NPF on two register operands???\r
- //\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- ExitInfo1 = InstructionData->Ext.RmData;\r
- ExitInfo2 = Bytes;\r
- CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);\r
-\r
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- break;\r
-\r
- //\r
- // MMIO write (MOV moffsetX, aX)\r
- //\r
- case 0xA2:\r
- Bytes = 1;\r
- //\r
- // fall through\r
- //\r
- case 0xA3:\r
- Bytes = ((Bytes != 0) ? Bytes :\r
- (InstructionData->DataSize == Size16Bits) ? 2 :\r
- (InstructionData->DataSize == Size32Bits) ? 4 :\r
- (InstructionData->DataSize == Size64Bits) ? 8 :\r
- 0);\r
-\r
- InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
- InstructionData->End += InstructionData->ImmediateSize;\r
-\r
- //\r
- // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
- // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
- //\r
- STATIC_ASSERT (\r
- sizeof (UINTN) == sizeof (UINT64),\r
- "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
- );\r
-\r
- Address = 0;\r
- CopyMem (\r
- &Address,\r
- InstructionData->Immediate,\r
- InstructionData->ImmediateSize\r
- );\r
-\r
- Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- ExitInfo1 = Address;\r
- ExitInfo2 = Bytes;\r
- CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);\r
-\r
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- break;\r
-\r
- //\r
- // MMIO write (MOV reg/memX, immX)\r
- //\r
- case 0xC6:\r
- Bytes = 1;\r
- //\r
- // fall through\r
- //\r
- case 0xC7:\r
- DecodeModRm (Regs, InstructionData);\r
- Bytes = ((Bytes != 0) ? Bytes :\r
- (InstructionData->DataSize == Size16Bits) ? 2 :\r
- (InstructionData->DataSize == Size32Bits) ? 4 :\r
- 0);\r
-\r
- InstructionData->ImmediateSize = Bytes;\r
- InstructionData->End += Bytes;\r
-\r
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- ExitInfo1 = InstructionData->Ext.RmData;\r
- ExitInfo2 = Bytes;\r
- CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);\r
-\r
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- break;\r
-\r
- //\r
- // MMIO read (MOV regX, reg/memX)\r
- //\r
- case 0x8A:\r
- Bytes = 1;\r
- //\r
- // fall through\r
- //\r
- case 0x8B:\r
- DecodeModRm (Regs, InstructionData);\r
- Bytes = ((Bytes != 0) ? Bytes :\r
- (InstructionData->DataSize == Size16Bits) ? 2 :\r
- (InstructionData->DataSize == Size32Bits) ? 4 :\r
- (InstructionData->DataSize == Size64Bits) ? 8 :\r
- 0);\r
- if (InstructionData->Ext.ModRm.Mod == 3) {\r
- //\r
- // NPF on two register operands???\r
- //\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- ExitInfo1 = InstructionData->Ext.RmData;\r
- ExitInfo2 = Bytes;\r
-\r
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
- if (Bytes == 4) {\r
- //\r
- // Zero-extend for 32-bit operation\r
- //\r
- *Register = 0;\r
- }\r
-\r
- CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
- break;\r
-\r
- //\r
- // MMIO read (MOV aX, moffsetX)\r
- //\r
- case 0xA0:\r
- Bytes = 1;\r
- //\r
- // fall through\r
- //\r
- case 0xA1:\r
- Bytes = ((Bytes != 0) ? Bytes :\r
- (InstructionData->DataSize == Size16Bits) ? 2 :\r
- (InstructionData->DataSize == Size32Bits) ? 4 :\r
- (InstructionData->DataSize == Size64Bits) ? 8 :\r
- 0);\r
-\r
- InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
- InstructionData->End += InstructionData->ImmediateSize;\r
-\r
- //\r
- // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
- // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
- //\r
- STATIC_ASSERT (\r
- sizeof (UINTN) == sizeof (UINT64),\r
- "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
- );\r
-\r
- Address = 0;\r
- CopyMem (\r
- &Address,\r
- InstructionData->Immediate,\r
- InstructionData->ImmediateSize\r
- );\r
-\r
- Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- ExitInfo1 = Address;\r
- ExitInfo2 = Bytes;\r
-\r
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if (Bytes == 4) {\r
- //\r
- // Zero-extend for 32-bit operation\r
- //\r
- Regs->Rax = 0;\r
- }\r
-\r
- CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);\r
- break;\r
-\r
- //\r
- // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)\r
- //\r
- case 0xB6:\r
- Bytes = 1;\r
- //\r
- // fall through\r
- //\r
- case 0xB7:\r
- DecodeModRm (Regs, InstructionData);\r
- Bytes = (Bytes != 0) ? Bytes : 2;\r
-\r
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- ExitInfo1 = InstructionData->Ext.RmData;\r
- ExitInfo2 = Bytes;\r
-\r
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
- SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);\r
- CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
- break;\r
-\r
- //\r
- // MMIO read w/ sign-extension (MOVSX regX, reg/memX)\r
- //\r
- case 0xBE:\r
- Bytes = 1;\r
- //\r
- // fall through\r
- //\r
- case 0xBF:\r
- DecodeModRm (Regs, InstructionData);\r
- Bytes = (Bytes != 0) ? Bytes : 2;\r
-\r
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- ExitInfo1 = InstructionData->Ext.RmData;\r
- ExitInfo2 = Bytes;\r
-\r
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if (Bytes == 1) {\r
- UINT8 *Data;\r
-\r
- Data = (UINT8 *)Ghcb->SharedBuffer;\r
- SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;\r
- } else {\r
- UINT16 *Data;\r
-\r
- Data = (UINT16 *)Ghcb->SharedBuffer;\r
- SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;\r
- }\r
-\r
- Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
- SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);\r
- CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
- break;\r
-\r
- default:\r
- DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));\r
- Status = GP_EXCEPTION;\r
- ASSERT (FALSE);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Handle a MWAIT event.\r
-\r
- Use the VMGEXIT instruction to handle a MWAIT event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-MwaitExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- DecodeModRm (Regs, InstructionData);\r
-\r
- Ghcb->SaveArea.Rax = Regs->Rax;\r
- VmgSetOffsetValid (Ghcb, GhcbRax);\r
- Ghcb->SaveArea.Rcx = Regs->Rcx;\r
- VmgSetOffsetValid (Ghcb, GhcbRcx);\r
-\r
- return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);\r
-}\r
-\r
-/**\r
- Handle a MONITOR event.\r
-\r
- Use the VMGEXIT instruction to handle a MONITOR event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-MonitorExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- DecodeModRm (Regs, InstructionData);\r
-\r
- Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA\r
- VmgSetOffsetValid (Ghcb, GhcbRax);\r
- Ghcb->SaveArea.Rcx = Regs->Rcx;\r
- VmgSetOffsetValid (Ghcb, GhcbRcx);\r
- Ghcb->SaveArea.Rdx = Regs->Rdx;\r
- VmgSetOffsetValid (Ghcb, GhcbRdx);\r
-\r
- return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);\r
-}\r
-\r
-/**\r
- Handle a WBINVD event.\r
-\r
- Use the VMGEXIT instruction to handle a WBINVD event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-WbinvdExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);\r
-}\r
-\r
-/**\r
- Handle a RDTSCP event.\r
-\r
- Use the VMGEXIT instruction to handle a RDTSCP event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-RdtscpExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 Status;\r
-\r
- DecodeModRm (Regs, InstructionData);\r
-\r
- Status = VmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
- !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
- !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
- {\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- Regs->Rax = Ghcb->SaveArea.Rax;\r
- Regs->Rcx = Ghcb->SaveArea.Rcx;\r
- Regs->Rdx = Ghcb->SaveArea.Rdx;\r
-\r
- return 0;\r
-}\r
-\r
-/**\r
- Handle a VMMCALL event.\r
-\r
- Use the VMGEXIT instruction to handle a VMMCALL event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-VmmCallExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 Status;\r
-\r
- DecodeModRm (Regs, InstructionData);\r
-\r
- Ghcb->SaveArea.Rax = Regs->Rax;\r
- VmgSetOffsetValid (Ghcb, GhcbRax);\r
- Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);\r
- VmgSetOffsetValid (Ghcb, GhcbCpl);\r
-\r
- Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- Regs->Rax = Ghcb->SaveArea.Rax;\r
-\r
- return 0;\r
-}\r
-\r
-/**\r
- Handle an MSR event.\r
-\r
- Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-MsrExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 ExitInfo1, Status;\r
-\r
- ExitInfo1 = 0;\r
-\r
- switch (*(InstructionData->OpCodes + 1)) {\r
- case 0x30: // WRMSR\r
- ExitInfo1 = 1;\r
- Ghcb->SaveArea.Rax = Regs->Rax;\r
- VmgSetOffsetValid (Ghcb, GhcbRax);\r
- Ghcb->SaveArea.Rdx = Regs->Rdx;\r
- VmgSetOffsetValid (Ghcb, GhcbRdx);\r
- //\r
- // fall through\r
- //\r
- case 0x32: // RDMSR\r
- Ghcb->SaveArea.Rcx = Regs->Rcx;\r
- VmgSetOffsetValid (Ghcb, GhcbRcx);\r
- break;\r
- default:\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if (ExitInfo1 == 0) {\r
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
- !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
- {\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- Regs->Rax = Ghcb->SaveArea.Rax;\r
- Regs->Rdx = Ghcb->SaveArea.Rdx;\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-/**\r
- Build the IOIO event information.\r
-\r
- The IOIO event information identifies the type of IO operation to be performed\r
- by the hypervisor. Build this information based on the instruction data.\r
-\r
- @param[in] Regs x64 processor context\r
- @param[in, out] InstructionData Instruction parsing context\r
-\r
- @return IOIO event information value\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-IoioExitInfo (\r
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 ExitInfo;\r
-\r
- ExitInfo = 0;\r
-\r
- switch (*(InstructionData->OpCodes)) {\r
- //\r
- // INS opcodes\r
- //\r
- case 0x6C:\r
- case 0x6D:\r
- ExitInfo |= IOIO_TYPE_INS;\r
- ExitInfo |= IOIO_SEG_ES;\r
- ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
- break;\r
-\r
- //\r
- // OUTS opcodes\r
- //\r
- case 0x6E:\r
- case 0x6F:\r
- ExitInfo |= IOIO_TYPE_OUTS;\r
- ExitInfo |= IOIO_SEG_DS;\r
- ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
- break;\r
-\r
- //\r
- // IN immediate opcodes\r
- //\r
- case 0xE4:\r
- case 0xE5:\r
- InstructionData->ImmediateSize = 1;\r
- InstructionData->End++;\r
- ExitInfo |= IOIO_TYPE_IN;\r
- ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);\r
- break;\r
-\r
- //\r
- // OUT immediate opcodes\r
- //\r
- case 0xE6:\r
- case 0xE7:\r
- InstructionData->ImmediateSize = 1;\r
- InstructionData->End++;\r
- ExitInfo |= IOIO_TYPE_OUT;\r
- ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;\r
- break;\r
-\r
- //\r
- // IN register opcodes\r
- //\r
- case 0xEC:\r
- case 0xED:\r
- ExitInfo |= IOIO_TYPE_IN;\r
- ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
- break;\r
-\r
- //\r
- // OUT register opcodes\r
- //\r
- case 0xEE:\r
- case 0xEF:\r
- ExitInfo |= IOIO_TYPE_OUT;\r
- ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
- break;\r
-\r
- default:\r
- return 0;\r
- }\r
-\r
- switch (*(InstructionData->OpCodes)) {\r
- //\r
- // Single-byte opcodes\r
- //\r
- case 0x6C:\r
- case 0x6E:\r
- case 0xE4:\r
- case 0xE6:\r
- case 0xEC:\r
- case 0xEE:\r
- ExitInfo |= IOIO_DATA_8;\r
- break;\r
-\r
- //\r
- // Length determined by instruction parsing\r
- //\r
- default:\r
- ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16\r
- : IOIO_DATA_32;\r
- }\r
-\r
- switch (InstructionData->AddrSize) {\r
- case Size16Bits:\r
- ExitInfo |= IOIO_ADDR_16;\r
- break;\r
-\r
- case Size32Bits:\r
- ExitInfo |= IOIO_ADDR_32;\r
- break;\r
-\r
- case Size64Bits:\r
- ExitInfo |= IOIO_ADDR_64;\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-\r
- if (InstructionData->RepMode != 0) {\r
- ExitInfo |= IOIO_REP;\r
- }\r
-\r
- return ExitInfo;\r
-}\r
-\r
-/**\r
- Handle an IOIO event.\r
-\r
- Use the VMGEXIT instruction to handle an IOIO event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-IoioExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 ExitInfo1, ExitInfo2, Status;\r
- BOOLEAN IsString;\r
-\r
- ExitInfo1 = IoioExitInfo (Regs, InstructionData);\r
- if (ExitInfo1 == 0) {\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;\r
- if (IsString) {\r
- UINTN IoBytes, VmgExitBytes;\r
- UINTN GhcbCount, OpCount;\r
-\r
- Status = 0;\r
-\r
- IoBytes = IOIO_DATA_BYTES (ExitInfo1);\r
- GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;\r
-\r
- OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;\r
- while (OpCount != 0) {\r
- ExitInfo2 = MIN (OpCount, GhcbCount);\r
- VmgExitBytes = ExitInfo2 * IoBytes;\r
-\r
- if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {\r
- CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);\r
- Regs->Rsi += VmgExitBytes;\r
- }\r
-\r
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
- Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
- CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);\r
- Regs->Rdi += VmgExitBytes;\r
- }\r
-\r
- if ((ExitInfo1 & IOIO_REP) != 0) {\r
- Regs->Rcx -= ExitInfo2;\r
- }\r
-\r
- OpCount -= ExitInfo2;\r
- }\r
- } else {\r
- if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
- Ghcb->SaveArea.Rax = 0;\r
- } else {\r
- CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
- }\r
-\r
- VmgSetOffsetValid (Ghcb, GhcbRax);\r
-\r
- Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
- if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
- }\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-/**\r
- Handle a INVD event.\r
-\r
- Use the VMGEXIT instruction to handle a INVD event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-InvdExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);\r
-}\r
-\r
-/**\r
- Fetch CPUID leaf/function via hypervisor/VMGEXIT.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in] EaxIn EAX input for cpuid instruction\r
- @param[in] EcxIn ECX input for cpuid instruction\r
- @param[in] Xcr0In XCR0 at time of cpuid instruction\r
- @param[in, out] Eax Pointer to store leaf's EAX value\r
- @param[in, out] Ebx Pointer to store leaf's EBX value\r
- @param[in, out] Ecx Pointer to store leaf's ECX value\r
- @param[in, out] Edx Pointer to store leaf's EDX value\r
- @param[in, out] Status Pointer to store status from VMGEXIT (always 0\r
- unless return value indicates failure)\r
- @param[in, out] Unsupported Pointer to store indication of unsupported\r
- VMGEXIT (always false unless return value\r
- indicates failure)\r
-\r
- @retval TRUE CPUID leaf fetch successfully.\r
- @retval FALSE Error occurred while fetching CPUID leaf. Callers\r
- should Status and Unsupported and handle\r
- accordingly if they indicate a more precise\r
- error condition.\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-GetCpuidHyp (\r
- IN OUT GHCB *Ghcb,\r
- IN UINT32 EaxIn,\r
- IN UINT32 EcxIn,\r
- IN UINT64 XCr0,\r
- IN OUT UINT32 *Eax,\r
- IN OUT UINT32 *Ebx,\r
- IN OUT UINT32 *Ecx,\r
- IN OUT UINT32 *Edx,\r
- IN OUT UINT64 *Status,\r
- IN OUT BOOLEAN *UnsupportedExit\r
- )\r
-{\r
- *UnsupportedExit = FALSE;\r
- Ghcb->SaveArea.Rax = EaxIn;\r
- VmgSetOffsetValid (Ghcb, GhcbRax);\r
- Ghcb->SaveArea.Rcx = EcxIn;\r
- VmgSetOffsetValid (Ghcb, GhcbRcx);\r
- if (EaxIn == CPUID_EXTENDED_STATE) {\r
- Ghcb->SaveArea.XCr0 = XCr0;\r
- VmgSetOffsetValid (Ghcb, GhcbXCr0);\r
- }\r
-\r
- *Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);\r
- if (*Status != 0) {\r
- return FALSE;\r
- }\r
-\r
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
- !VmgIsOffsetValid (Ghcb, GhcbRbx) ||\r
- !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
- !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
- {\r
- *UnsupportedExit = TRUE;\r
- return FALSE;\r
- }\r
-\r
- if (Eax) {\r
- *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax;\r
- }\r
-\r
- if (Ebx) {\r
- *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx;\r
- }\r
-\r
- if (Ecx) {\r
- *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx;\r
- }\r
-\r
- if (Edx) {\r
- *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Check if SEV-SNP enabled.\r
-\r
- @retval TRUE SEV-SNP is enabled.\r
- @retval FALSE SEV-SNP is disabled.\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-SnpEnabled (\r
- VOID\r
- )\r
-{\r
- MSR_SEV_STATUS_REGISTER Msr;\r
-\r
- Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);\r
-\r
- return !!Msr.Bits.SevSnpBit;\r
-}\r
-\r
-/**\r
- Calculate the total XSAVE area size for enabled XSAVE areas\r
-\r
- @param[in] XFeaturesEnabled Bit-mask of enabled XSAVE features/areas as\r
- indicated by XCR0/MSR_IA32_XSS bits\r
- @param[in] XSaveBaseSize Base/legacy XSAVE area size (e.g. when\r
- XCR0 is 1)\r
- @param[in, out] XSaveSize Pointer to storage for calculated XSAVE area\r
- size\r
- @param[in] Compacted Whether or not the calculation is for the\r
- normal XSAVE area size (leaf 0xD,0x0,EBX) or\r
- compacted XSAVE area size (leaf 0xD,0x1,EBX)\r
-\r
-\r
- @retval TRUE XSAVE size calculation was successful.\r
- @retval FALSE XSAVE size calculation was unsuccessful.\r
-**/\r
-STATIC\r
-BOOLEAN\r
-GetCpuidXSaveSize (\r
- IN UINT64 XFeaturesEnabled,\r
- IN UINT32 XSaveBaseSize,\r
- IN OUT UINT32 *XSaveSize,\r
- IN BOOLEAN Compacted\r
- )\r
-{\r
- SEV_SNP_CPUID_INFO *CpuidInfo;\r
- UINT64 XFeaturesFound = 0;\r
- UINT32 Idx;\r
-\r
- *XSaveSize = XSaveBaseSize;\r
- CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);\r
-\r
- for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {\r
- SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];\r
-\r
- if (!((CpuidFn->EaxIn == 0xD) &&\r
- ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1))))\r
- {\r
- continue;\r
- }\r
-\r
- if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) ||\r
- !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn)))\r
- {\r
- continue;\r
- }\r
-\r
- XFeaturesFound |= (1ULL << CpuidFn->EcxIn);\r
- if (Compacted) {\r
- *XSaveSize += CpuidFn->Eax;\r
- } else {\r
- *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);\r
- }\r
- }\r
-\r
- /*\r
- * Either the guest set unsupported XCR0/XSS bits, or the corresponding\r
- * entries in the CPUID table were not present. This is an invalid state.\r
- */\r
- if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function\r
-\r
- @param[in] EaxIn EAX input for cpuid instruction\r
-\r
- @retval FALSE cpuid leaf/function is not indexed by ECX input\r
- @retval TRUE cpuid leaf/function is indexed by ECX input\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-IsFunctionIndexed (\r
- IN UINT32 EaxIn\r
- )\r
-{\r
- switch (EaxIn) {\r
- case CPUID_CACHE_PARAMS:\r
- case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS:\r
- case CPUID_EXTENDED_TOPOLOGY:\r
- case CPUID_EXTENDED_STATE:\r
- case CPUID_INTEL_RDT_MONITORING:\r
- case CPUID_INTEL_RDT_ALLOCATION:\r
- case CPUID_INTEL_SGX:\r
- case CPUID_INTEL_PROCESSOR_TRACE:\r
- case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS:\r
- case CPUID_V2_EXTENDED_TOPOLOGY:\r
- case 0x8000001D: /* Cache Topology Information */\r
- return TRUE;\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-/**\r
- Fetch CPUID leaf/function via SEV-SNP CPUID table.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in] EaxIn EAX input for cpuid instruction\r
- @param[in] EcxIn ECX input for cpuid instruction\r
- @param[in] Xcr0In XCR0 at time of cpuid instruction\r
- @param[in, out] Eax Pointer to store leaf's EAX value\r
- @param[in, out] Ebx Pointer to store leaf's EBX value\r
- @param[in, out] Ecx Pointer to store leaf's ECX value\r
- @param[in, out] Edx Pointer to store leaf's EDX value\r
- @param[in, out] Status Pointer to store status from VMGEXIT (always 0\r
- unless return value indicates failure)\r
- @param[in, out] Unsupported Pointer to store indication of unsupported\r
- VMGEXIT (always false unless return value\r
- indicates failure)\r
-\r
- @retval TRUE CPUID leaf fetch successfully.\r
- @retval FALSE Error occurred while fetching CPUID leaf. Callers\r
- should Status and Unsupported and handle\r
- accordingly if they indicate a more precise\r
- error condition.\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-GetCpuidFw (\r
- IN OUT GHCB *Ghcb,\r
- IN UINT32 EaxIn,\r
- IN UINT32 EcxIn,\r
- IN UINT64 XCr0,\r
- IN OUT UINT32 *Eax,\r
- IN OUT UINT32 *Ebx,\r
- IN OUT UINT32 *Ecx,\r
- IN OUT UINT32 *Edx,\r
- IN OUT UINT64 *Status,\r
- IN OUT BOOLEAN *Unsupported\r
- )\r
-{\r
- SEV_SNP_CPUID_INFO *CpuidInfo;\r
- BOOLEAN Found;\r
- UINT32 Idx;\r
-\r
- CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);\r
- Found = FALSE;\r
-\r
- for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {\r
- SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];\r
-\r
- if (CpuidFn->EaxIn != EaxIn) {\r
- continue;\r
- }\r
-\r
- if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) {\r
- continue;\r
- }\r
-\r
- *Eax = CpuidFn->Eax;\r
- *Ebx = CpuidFn->Ebx;\r
- *Ecx = CpuidFn->Ecx;\r
- *Edx = CpuidFn->Edx;\r
-\r
- Found = TRUE;\r
- break;\r
- }\r
-\r
- if (!Found) {\r
- *Eax = *Ebx = *Ecx = *Edx = 0;\r
- goto Out;\r
- }\r
-\r
- if (EaxIn == CPUID_VERSION_INFO) {\r
- IA32_CR4 Cr4;\r
- UINT32 Ebx2;\r
- UINT32 Edx2;\r
-\r
- if (!GetCpuidHyp (\r
- Ghcb,\r
- EaxIn,\r
- EcxIn,\r
- XCr0,\r
- NULL,\r
- &Ebx2,\r
- NULL,\r
- &Edx2,\r
- Status,\r
- Unsupported\r
- ))\r
- {\r
- return FALSE;\r
- }\r
-\r
- /* initial APIC ID */\r
- *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);\r
- /* APIC enabled bit */\r
- *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);\r
- /* OSXSAVE enabled bit */\r
- Cr4.UintN = AsmReadCr4 ();\r
- *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)\r
- : (*Ecx & ~BIT27);\r
- } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {\r
- IA32_CR4 Cr4;\r
-\r
- Cr4.UintN = AsmReadCr4 ();\r
- /* OSPKE enabled bit */\r
- *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);\r
- } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {\r
- if (!GetCpuidHyp (\r
- Ghcb,\r
- EaxIn,\r
- EcxIn,\r
- XCr0,\r
- NULL,\r
- NULL,\r
- NULL,\r
- Edx,\r
- Status,\r
- Unsupported\r
- ))\r
- {\r
- return FALSE;\r
- }\r
- } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) {\r
- MSR_IA32_XSS_REGISTER XssMsr;\r
- BOOLEAN Compacted;\r
- UINT32 XSaveSize;\r
-\r
- XssMsr.Uint64 = 0;\r
- Compacted = FALSE;\r
- if (EcxIn == 1) {\r
- /*\r
- * The PPR and APM aren't clear on what size should be encoded in\r
- * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or\r
- * XSAVES, as these are generally fixed to 1 on real CPUs. Report\r
- * this undefined case as an error.\r
- */\r
- if (!(*Eax & (BIT3 | BIT1))) {\r
- /* (XSAVES | XSAVEC) */\r
- return FALSE;\r
- }\r
-\r
- Compacted = TRUE;\r
- XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);\r
- }\r
-\r
- if (!GetCpuidXSaveSize (\r
- XCr0 | XssMsr.Uint64,\r
- *Ebx,\r
- &XSaveSize,\r
- Compacted\r
- ))\r
- {\r
- return FALSE;\r
- }\r
-\r
- *Ebx = XSaveSize;\r
- } else if (EaxIn == 0x8000001E) {\r
- UINT32 Ebx2;\r
- UINT32 Ecx2;\r
-\r
- /* extended APIC ID */\r
- if (!GetCpuidHyp (\r
- Ghcb,\r
- EaxIn,\r
- EcxIn,\r
- XCr0,\r
- Eax,\r
- &Ebx2,\r
- &Ecx2,\r
- NULL,\r
- Status,\r
- Unsupported\r
- ))\r
- {\r
- return FALSE;\r
- }\r
-\r
- /* compute ID */\r
- *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);\r
- /* node ID */\r
- *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);\r
- }\r
-\r
-Out:\r
- *Status = 0;\r
- *Unsupported = FALSE;\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Handle a CPUID event.\r
-\r
- Use VMGEXIT instruction or CPUID table to handle a CPUID event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-CpuidExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- BOOLEAN Unsupported;\r
- UINT64 Status;\r
- UINT32 EaxIn;\r
- UINT32 EcxIn;\r
- UINT64 XCr0;\r
- UINT32 Eax;\r
- UINT32 Ebx;\r
- UINT32 Ecx;\r
- UINT32 Edx;\r
-\r
- EaxIn = (UINT32)(UINTN)Regs->Rax;\r
- EcxIn = (UINT32)(UINTN)Regs->Rcx;\r
-\r
- if (EaxIn == CPUID_EXTENDED_STATE) {\r
- IA32_CR4 Cr4;\r
-\r
- Cr4.UintN = AsmReadCr4 ();\r
- Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
- XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
- }\r
-\r
- if (SnpEnabled ()) {\r
- if (!GetCpuidFw (\r
- Ghcb,\r
- EaxIn,\r
- EcxIn,\r
- XCr0,\r
- &Eax,\r
- &Ebx,\r
- &Ecx,\r
- &Edx,\r
- &Status,\r
- &Unsupported\r
- ))\r
- {\r
- goto CpuidFail;\r
- }\r
- } else {\r
- if (!GetCpuidHyp (\r
- Ghcb,\r
- EaxIn,\r
- EcxIn,\r
- XCr0,\r
- &Eax,\r
- &Ebx,\r
- &Ecx,\r
- &Edx,\r
- &Status,\r
- &Unsupported\r
- ))\r
- {\r
- goto CpuidFail;\r
- }\r
- }\r
-\r
- Regs->Rax = Eax;\r
- Regs->Rbx = Ebx;\r
- Regs->Rcx = Ecx;\r
- Regs->Rdx = Edx;\r
-\r
- return 0;\r
-\r
-CpuidFail:\r
- if (Unsupported) {\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Handle a RDPMC event.\r
-\r
- Use the VMGEXIT instruction to handle a RDPMC event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-RdpmcExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 Status;\r
-\r
- Ghcb->SaveArea.Rcx = Regs->Rcx;\r
- VmgSetOffsetValid (Ghcb, GhcbRcx);\r
-\r
- Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
- !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
- {\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- Regs->Rax = Ghcb->SaveArea.Rax;\r
- Regs->Rdx = Ghcb->SaveArea.Rdx;\r
-\r
- return 0;\r
-}\r
-\r
-/**\r
- Handle a RDTSC event.\r
-\r
- Use the VMGEXIT instruction to handle a RDTSC event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-RdtscExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- UINT64 Status;\r
-\r
- Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
- !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
- {\r
- return UnsupportedExit (Ghcb, Regs, InstructionData);\r
- }\r
-\r
- Regs->Rax = Ghcb->SaveArea.Rax;\r
- Regs->Rdx = Ghcb->SaveArea.Rdx;\r
-\r
- return 0;\r
-}\r
-\r
-/**\r
- Handle a DR7 register write event.\r
-\r
- Use the VMGEXIT instruction to handle a DR7 write event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
- @return New exception value to propagate\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-Dr7WriteExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
- SEV_ES_PER_CPU_DATA *SevEsData;\r
- UINT64 *Register;\r
- UINT64 Status;\r
-\r
- Ext = &InstructionData->Ext;\r
- SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
-\r
- DecodeModRm (Regs, InstructionData);\r
-\r
- //\r
- // MOV DRn always treats MOD == 3 no matter how encoded\r
- //\r
- Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
-\r
- //\r
- // Using a value of 0 for ExitInfo1 means RAX holds the value\r
- //\r
- Ghcb->SaveArea.Rax = *Register;\r
- VmgSetOffsetValid (Ghcb, GhcbRax);\r
-\r
- Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);\r
- if (Status != 0) {\r
- return Status;\r
- }\r
-\r
- SevEsData->Dr7 = *Register;\r
- SevEsData->Dr7Cached = 1;\r
-\r
- return 0;\r
-}\r
-\r
-/**\r
- Handle a DR7 register read event.\r
-\r
- Use the VMGEXIT instruction to handle a DR7 read event.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
- Block\r
- @param[in, out] Regs x64 processor context\r
- @param[in] InstructionData Instruction parsing context\r
-\r
- @retval 0 Event handled successfully\r
-\r
-**/\r
-STATIC\r
-UINT64\r
-Dr7ReadExit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
- IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
- )\r
-{\r
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
- SEV_ES_PER_CPU_DATA *SevEsData;\r
- UINT64 *Register;\r
-\r
- Ext = &InstructionData->Ext;\r
- SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
-\r
- DecodeModRm (Regs, InstructionData);\r
-\r
- //\r
- // MOV DRn always treats MOD == 3 no matter how encoded\r
- //\r
- Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
-\r
- //\r
- // If there is a cached valued for DR7, return that. Otherwise return the\r
- // DR7 standard reset value of 0x400 (no debug breakpoints set).\r
- //\r
- *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;\r
-\r
- return 0;\r
-}\r
-\r
-/**\r
- Handle a #VC exception.\r
-\r
- Performs the necessary processing to handle a #VC exception.\r
-\r
- @param[in, out] Ghcb Pointer to the GHCB\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
-InternalVmgExitHandleVc (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
- IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
- )\r
-{\r
- EFI_SYSTEM_CONTEXT_X64 *Regs;\r
- NAE_EXIT NaeExit;\r
- SEV_ES_INSTRUCTION_DATA InstructionData;\r
- UINT64 ExitCode, Status;\r
- EFI_STATUS VcRet;\r
- BOOLEAN InterruptState;\r
-\r
- VcRet = EFI_SUCCESS;\r
-\r
- Regs = SystemContext.SystemContextX64;\r
-\r
- VmgInit (Ghcb, &InterruptState);\r
-\r
- ExitCode = Regs->ExceptionData;\r
- switch (ExitCode) {\r
- case SVM_EXIT_DR7_READ:\r
- NaeExit = Dr7ReadExit;\r
- break;\r
-\r
- case SVM_EXIT_DR7_WRITE:\r
- NaeExit = Dr7WriteExit;\r
- break;\r
-\r
- case SVM_EXIT_RDTSC:\r
- NaeExit = RdtscExit;\r
- break;\r
-\r
- case SVM_EXIT_RDPMC:\r
- NaeExit = RdpmcExit;\r
- break;\r
-\r
- case SVM_EXIT_CPUID:\r
- NaeExit = CpuidExit;\r
- break;\r
-\r
- case SVM_EXIT_INVD:\r
- NaeExit = InvdExit;\r
- break;\r
-\r
- case SVM_EXIT_IOIO_PROT:\r
- NaeExit = IoioExit;\r
- break;\r
-\r
- case SVM_EXIT_MSR:\r
- NaeExit = MsrExit;\r
- break;\r
-\r
- case SVM_EXIT_VMMCALL:\r
- NaeExit = VmmCallExit;\r
- break;\r
-\r
- case SVM_EXIT_RDTSCP:\r
- NaeExit = RdtscpExit;\r
- break;\r
-\r
- case SVM_EXIT_WBINVD:\r
- NaeExit = WbinvdExit;\r
- break;\r
-\r
- case SVM_EXIT_MONITOR:\r
- NaeExit = MonitorExit;\r
- break;\r
-\r
- case SVM_EXIT_MWAIT:\r
- NaeExit = MwaitExit;\r
- break;\r
-\r
- case SVM_EXIT_NPF:\r
- NaeExit = MmioExit;\r
- break;\r
-\r
- default:\r
- NaeExit = UnsupportedExit;\r
- }\r
-\r
- InitInstructionData (&InstructionData, Ghcb, Regs);\r
-\r
- Status = NaeExit (Ghcb, Regs, &InstructionData);\r
- if (Status == 0) {\r
- Regs->Rip += InstructionLength (&InstructionData);\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
- VcRet = EFI_PROTOCOL_ERROR;\r
- }\r
-\r
- VmgDone (Ghcb, InterruptState);\r
-\r
- return VcRet;\r
-}\r
-\r
-/**\r
- Routine to allow ASSERT from within #VC.\r
-\r
- @param[in, out] SevEsData Pointer to the per-CPU data\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgExitIssueAssert (\r
- IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
- )\r
-{\r
- //\r
- // Progress will be halted, so set VcCount to allow for ASSERT output\r
- // to be seen.\r
- //\r
- SevEsData->VcCount = 0;\r
-\r
- ASSERT (FALSE);\r
- CpuDeadLoop ();\r
-}\r
+++ /dev/null
-/** @file\r
- X64 #VC Exception Handler functon header file.\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
-#ifndef __VMG_EXIT_VC_HANDLER_H__\r
-#define __VMG_EXIT_VC_HANDLER_H__\r
-\r
-#include <Base.h>\r
-#include <Uefi.h>\r
-#include <Library/VmgExitLib.h>\r
-\r
-/**\r
- Handle a #VC exception.\r
-\r
- Performs the necessary processing to handle a #VC exception.\r
-\r
- @param[in, out] Ghcb Pointer to the GHCB\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
-InternalVmgExitHandleVc (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
- IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
- );\r
-\r
-/**\r
- Routine to allow ASSERT from within #VC.\r
-\r
- @param[in, out] SevEsData Pointer to the per-CPU data\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgExitIssueAssert (\r
- IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
- );\r
-\r
-#endif\r
+++ /dev/null
-;------------------------------------------------------------------------------\r
-;*\r
-;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>\r
-;* SPDX-License-Identifier: BSD-2-Clause-Patent\r
-;*\r
-;*\r
-;------------------------------------------------------------------------------\r
-\r
-DEFAULT REL\r
-SECTION .text\r
-\r
-%define TDVMCALL_EXPOSE_REGS_MASK 0xffec\r
-%define TDVMCALL 0x0\r
-%define EXIT_REASON_CPUID 0xa\r
-\r
-%macro tdcall 0\r
- db 0x66,0x0f,0x01,0xcc\r
-%endmacro\r
-\r
-%macro tdcall_push_regs 0\r
- push rbp\r
- mov rbp, rsp\r
- push r15\r
- push r14\r
- push r13\r
- push r12\r
- push rbx\r
- push rsi\r
- push rdi\r
-%endmacro\r
-\r
-%macro tdcall_pop_regs 0\r
- pop rdi\r
- pop rsi\r
- pop rbx\r
- pop r12\r
- pop r13\r
- pop r14\r
- pop r15\r
- pop rbp\r
-%endmacro\r
-\r
-%define number_of_regs_pushed 8\r
-%define number_of_parameters 4\r
-\r
-;\r
-; Keep these in sync for push_regs/pop_regs, code below\r
-; uses them to find 5th or greater parameters\r
-;\r
-%define first_variable_on_stack_offset \\r
- ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)\r
-%define second_variable_on_stack_offset \\r
- ((first_variable_on_stack_offset) + 8)\r
-\r
-%macro tdcall_regs_preamble 2\r
- mov rax, %1\r
-\r
- xor rcx, rcx\r
- mov ecx, %2\r
-\r
- ; R10 = 0 (standard TDVMCALL)\r
-\r
- xor r10d, r10d\r
-\r
- ; Zero out unused (for standard TDVMCALL) registers to avoid leaking\r
- ; secrets to the VMM.\r
-\r
- xor ebx, ebx\r
- xor esi, esi\r
- xor edi, edi\r
-\r
- xor edx, edx\r
- xor ebp, ebp\r
- xor r8d, r8d\r
- xor r9d, r9d\r
- xor r14, r14\r
- xor r15, r15\r
-%endmacro\r
-\r
-%macro tdcall_regs_postamble 0\r
- xor ebx, ebx\r
- xor esi, esi\r
- xor edi, edi\r
-\r
- xor ecx, ecx\r
- xor edx, edx\r
- xor r8d, r8d\r
- xor r9d, r9d\r
- xor r10d, r10d\r
- xor r11d, r11d\r
-%endmacro\r
-\r
-;------------------------------------------------------------------------------\r
-; 0 => RAX = TDCALL leaf / TDVMCALL\r
-; M => RCX = TDVMCALL register behavior\r
-; 0xa => R11 = TDVMCALL function / CPUID\r
-; RCX => R12 = p1\r
-; RDX => R13 = p2\r
-;\r
-; UINT64\r
-; EFIAPI\r
-; TdVmCallCpuid (\r
-; UINT64 EaxIn, // Rcx\r
-; UINT64 EcxIn, // Rdx\r
-; UINT64 *Results // R8\r
-; )\r
-global ASM_PFX(TdVmCallCpuid)\r
-ASM_PFX(TdVmCallCpuid):\r
- tdcall_push_regs\r
-\r
- mov r11, EXIT_REASON_CPUID\r
- mov r12, rcx\r
- mov r13, rdx\r
-\r
- ; Save *results pointers\r
- push r8\r
-\r
- tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK\r
-\r
- tdcall\r
-\r
- ; ignore return data if TDCALL reports failure.\r
- test rax, rax\r
- jnz .no_return_data\r
-\r
- ; Propagate TDVMCALL success/failure to return value.\r
- mov rax, r10\r
- test rax, rax\r
- jnz .no_return_data\r
-\r
- ; Retrieve *Results\r
- pop r8\r
- test r8, r8\r
- jz .no_return_data\r
- ; Caller pass in buffer so store results r12-r15 contains eax-edx\r
- mov [r8 + 0], r12\r
- mov [r8 + 8], r13\r
- mov [r8 + 16], r14\r
- mov [r8 + 24], r15\r
-\r
-.no_return_data:\r
- tdcall_regs_postamble\r
-\r
- tdcall_pop_regs\r
-\r
- ret\r
\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf\r
SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf\r
PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf\r
FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf\r
!else\r
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
!endif\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf\r
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf\r
\r
[LibraryClasses.common.PEI_CORE]\r
\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
\r
[LibraryClasses.common.SEC]\r
TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf\r
#\r
OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf {\r
<LibraryClasses>\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
}\r
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf\r
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {\r
\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
TdxLib|MdePkg/Library/TdxLib/TdxLib.inf\r
TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf\r
\r
#\r
OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf {\r
<LibraryClasses>\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
}\r
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf\r
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {\r
\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/CcExitLib.inf\r
TdxLib|MdePkg/Library/TdxLib/TdxLib.inf\r
TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf\r
\r
!else\r
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf\r
!endif\r
- VmgExitLib|OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf\r
+ CcExitLib|OvmfPkg/Library/CcExitLib/SecCcExitLib.inf\r
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf\r
CcProbeLib|OvmfPkg/Library/CcProbeLib/SecPeiCcProbeLib.inf\r
\r
#\r
OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf {\r
<LibraryClasses>\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
}\r
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf\r
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {\r
\r
[LibraryClasses.common]\r
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
TdxLib|MdePkg/Library/TdxLib/TdxLib.inf\r
\r
[LibraryClasses.common.SEC]\r
#include <PiPei.h>\r
#include <Register/Amd/Msr.h>\r
#include <Register/Intel/SmramSaveStateMap.h>\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
#include <ConfidentialComputingGuestAttr.h>\r
\r
#include "Platform.h"\r
MtrrLib\r
MemEncryptSevLib\r
PcdLib\r
- VmgExitLib\r
+ CcExitLib\r
PlatformInitLib\r
\r
[Pcd]\r
UefiBootServicesTableLib\r
UefiDriverEntryPoint\r
UefiRuntimeLib\r
- VmgExitLib\r
+ CcExitLib\r
\r
[Guids]\r
gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED\r
\r
#include <Library/UefiRuntimeLib.h>\r
#include <Library/MemEncryptSevLib.h>\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
#include <Register/Amd/Msr.h>\r
\r
#include "QemuFlash.h"\r
--- /dev/null
+/** @file\r
+ Public header file for the CcExitLib.\r
+\r
+ This library class defines some routines used for below CcExit handler.\r
+ - Invoking the VMGEXIT instruction in support of SEV-ES and to handle\r
+ #VC exceptions.\r
+ - Handle #VE exception in TDX.\r
+\r
+ Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+ Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef CC_EXIT_LIB_H_\r
+#define CC_EXIT_LIB_H_\r
+\r
+#include <Protocol/DebugSupport.h>\r
+#include <Register/Amd/Ghcb.h>\r
+\r
+#define VE_EXCEPTION 20\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
+/**\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
+ @param[in, out] InterruptState A pointer to hold the current interrupt\r
+ state, used for restoring in VmgDone ()\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgInit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT BOOLEAN *InterruptState\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
+ @param[in] InterruptState An indicator to conditionally (re)enable\r
+ interrupts\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgDone (\r
+ IN OUT GHCB *Ghcb,\r
+ IN BOOLEAN InterruptState\r
+ );\r
+\r
+/**\r
+ Marks a specified offset as valid in the GHCB.\r
+\r
+ The ValidBitmap area represents the areas of the GHCB that have been marked\r
+ valid. Set the bit in ValidBitmap for the input offset.\r
+\r
+ @param[in, out] Ghcb A pointer to the GHCB\r
+ @param[in] Offset Qword offset in the GHCB to mark valid\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgSetOffsetValid (\r
+ IN OUT GHCB *Ghcb,\r
+ IN GHCB_REGISTER Offset\r
+ );\r
+\r
+/**\r
+ Checks if a specified offset is valid in the GHCB.\r
+\r
+ The ValidBitmap area represents the areas of the GHCB that have been marked\r
+ valid. Return whether the bit in the ValidBitmap is set for the input offset.\r
+\r
+ @param[in] Ghcb A pointer to the GHCB\r
+ @param[in] Offset Qword offset in the GHCB to mark valid\r
+\r
+ @retval TRUE Offset is marked valid in the GHCB\r
+ @retval FALSE Offset is not marked valid in the GHCB\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+VmgIsOffsetValid (\r
+ IN GHCB *Ghcb,\r
+ IN GHCB_REGISTER Offset\r
+ );\r
+\r
+/**\r
+ Handle a #VC exception.\r
+\r
+ Performs the necessary processing to handle a #VC exception.\r
+\r
+ The base library function returns an error equal to VC_EXCEPTION,\r
+ to be propagated to the standard exception handling stack.\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
+/**\r
+ Handle a #VE exception.\r
+\r
+ Performs the necessary processing to handle a #VE exception.\r
+\r
+ The base library function returns an error equal to VE_EXCEPTION,\r
+ to be propagated to the standard exception handling stack.\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 #VE not supported, (new) exception value to\r
+ propagate provided\r
+ @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to\r
+ propagate provided\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VmTdExitHandleVe (\r
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ );\r
+\r
+#endif\r
+++ /dev/null
-/** @file\r
- Public header file for the VMGEXIT Support library class.\r
-\r
- This library class defines some routines used when invoking the VMGEXIT\r
- instruction in support of SEV-ES and to handle #VC exceptions.\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
-#ifndef __VMG_EXIT_LIB_H__\r
-#define __VMG_EXIT_LIB_H__\r
-\r
-#include <Protocol/DebugSupport.h>\r
-#include <Register/Amd/Ghcb.h>\r
-\r
-#define VE_EXCEPTION 20\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
-/**\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
- @param[in, out] InterruptState A pointer to hold the current interrupt\r
- state, used for restoring in VmgDone ()\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgInit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT BOOLEAN *InterruptState\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
- @param[in] InterruptState An indicator to conditionally (re)enable\r
- interrupts\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgDone (\r
- IN OUT GHCB *Ghcb,\r
- IN BOOLEAN InterruptState\r
- );\r
-\r
-/**\r
- Marks a specified offset as valid in the GHCB.\r
-\r
- The ValidBitmap area represents the areas of the GHCB that have been marked\r
- valid. Set the bit in ValidBitmap for the input offset.\r
-\r
- @param[in, out] Ghcb A pointer to the GHCB\r
- @param[in] Offset Qword offset in the GHCB to mark valid\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgSetOffsetValid (\r
- IN OUT GHCB *Ghcb,\r
- IN GHCB_REGISTER Offset\r
- );\r
-\r
-/**\r
- Checks if a specified offset is valid in the GHCB.\r
-\r
- The ValidBitmap area represents the areas of the GHCB that have been marked\r
- valid. Return whether the bit in the ValidBitmap is set for the input offset.\r
-\r
- @param[in] Ghcb A pointer to the GHCB\r
- @param[in] Offset Qword offset in the GHCB to mark valid\r
-\r
- @retval TRUE Offset is marked valid in the GHCB\r
- @retval FALSE Offset is not marked valid in the GHCB\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-VmgIsOffsetValid (\r
- IN GHCB *Ghcb,\r
- IN GHCB_REGISTER Offset\r
- );\r
-\r
-/**\r
- Handle a #VC exception.\r
-\r
- Performs the necessary processing to handle a #VC exception.\r
-\r
- The base library function returns an error equal to VC_EXCEPTION,\r
- to be propagated to the standard exception handling stack.\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
-/**\r
- Handle a #VE exception.\r
-\r
- Performs the necessary processing to handle a #VE exception.\r
-\r
- The base library function returns an error equal to VE_EXCEPTION,\r
- to be propagated to the standard exception handling stack.\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 #VE not supported, (new) exception value to\r
- propagate provided\r
- @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to\r
- propagate provided\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-VmTdExitHandleVe (\r
- IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
- IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
- );\r
-\r
-#endif\r
--- /dev/null
+/** @file\r
+ CcExit Base Support Library.\r
+\r
+ Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+ Copyright (c) 2020 - 2022, Intel Corporation. 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/CcExitLib.h>\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
+ The base library function returns an error in the form of a\r
+ GHCB_EVENT_INJECTION representing a GP_EXCEPTION.\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_EVENT_INJECTION Event;\r
+\r
+ Event.Uint64 = 0;\r
+ Event.Elements.Vector = GP_EXCEPTION;\r
+ Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
+ Event.Elements.Valid = 1;\r
+\r
+ return Event.Uint64;\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
+ @param[in, out] InterruptState A pointer to hold the current interrupt\r
+ state, used for restoring in VmgDone ()\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgInit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT BOOLEAN *InterruptState\r
+ )\r
+{\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
+ @param[in] InterruptState An indicator to conditionally (re)enable\r
+ interrupts\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgDone (\r
+ IN OUT GHCB *Ghcb,\r
+ IN BOOLEAN InterruptState\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Marks a field at the specified offset as valid in the GHCB.\r
+\r
+ The ValidBitmap area represents the areas of the GHCB that have been marked\r
+ valid. Set the bit in ValidBitmap for the input offset.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
+ @param[in] Offset Qword offset in the GHCB to mark valid\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VmgSetOffsetValid (\r
+ IN OUT GHCB *Ghcb,\r
+ IN GHCB_REGISTER Offset\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Checks if a specified offset is valid in the GHCB.\r
+\r
+ The ValidBitmap area represents the areas of the GHCB that have been marked\r
+ valid. Return whether the bit in the ValidBitmap is set for the input offset.\r
+\r
+ @param[in] Ghcb A pointer to the GHCB\r
+ @param[in] Offset Qword offset in the GHCB to mark valid\r
+\r
+ @retval TRUE Offset is marked valid in the GHCB\r
+ @retval FALSE Offset is not marked valid in the GHCB\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+VmgIsOffsetValid (\r
+ IN GHCB *Ghcb,\r
+ IN GHCB_REGISTER Offset\r
+ )\r
+{\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Handle a #VC exception.\r
+\r
+ Performs the necessary processing to handle a #VC exception.\r
+\r
+ The base library function returns an error equal to VC_EXCEPTION,\r
+ to be propagated to the standard exception handling stack.\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
+ *ExceptionType = VC_EXCEPTION;\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Handle a #VE exception.\r
+\r
+ Performs the necessary processing to handle a #VE 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 #VE not supported, (new) exception value to\r
+ propagate provided\r
+ @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to\r
+ propagate provided\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VmTdExitHandleVe (\r
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ *ExceptionType = VE_EXCEPTION;\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
--- /dev/null
+## @file\r
+# CcExit Base Support Library.\r
+#\r
+# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+# Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = CcExitLibNull\r
+ MODULE_UNI_FILE = CcExitLibNull.uni\r
+ FILE_GUID = 3cd7368f-ef9b-4a9b-9571-2ed93813677e\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = CcExitLib\r
+\r
+[Sources.common]\r
+ CcExitLibNull.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UefiCpuPkg/UefiCpuPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+\r
--- /dev/null
+// /** @file\r
+// CcExitLib instance.\r
+//\r
+// Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+// Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "CcExitLib NULL instance"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "CcExitLib NULL instance."\r
+\r
PeCoffGetEntryPointLib\r
MemoryAllocationLib\r
DebugLib\r
- VmgExitLib\r
+ CcExitLib\r
HobLib\r
MemoryAllocationLib\r
SynchronizationLib\r
- VmgExitLib\r
+ CcExitLib\r
\r
[Pcd]\r
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard # CONSUMES\r
**/\r
\r
#include <Library/DebugLib.h>\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
#include "CpuExceptionCommon.h"\r
\r
/**\r
**/\r
\r
#include <PiPei.h>\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
#include "CpuExceptionCommon.h"\r
\r
CONST UINTN mDoFarReturnFlag = 0;\r
PrintLib\r
LocalApicLib\r
PeCoffGetEntryPointLib\r
- VmgExitLib\r
+ CcExitLib\r
\r
[Pcd]\r
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard\r
LocalApicLib\r
PeCoffGetEntryPointLib\r
DebugLib\r
- VmgExitLib\r
+ CcExitLib\r
\r
[Pcd]\r
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard\r
PrintLib\r
LocalApicLib\r
PeCoffGetEntryPointLib\r
- VmgExitLib\r
+ CcExitLib\r
\r
[Pcd]\r
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard\r
**/\r
\r
#include "MpLib.h"\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
\r
/**\r
Get Protected mode code segment with 16-bit default addressing\r
DebugAgentLib\r
SynchronizationLib\r
PcdLib\r
- VmgExitLib\r
+ CcExitLib\r
MicrocodeLib\r
\r
[Protocols]\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/DebugAgentLib.h>\r
#include <Library/DxeServicesTableLib.h>\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
#include <Register/Amd/Fam17Msr.h>\r
#include <Register/Amd/Ghcb.h>\r
\r
**/\r
\r
#include "MpLib.h"\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
#include <Register/Amd/Fam17Msr.h>\r
#include <Register/Amd/Ghcb.h>\r
\r
SynchronizationLib\r
PeiServicesLib\r
PcdLib\r
- VmgExitLib\r
+ CcExitLib\r
MicrocodeLib\r
\r
[Pcd]\r
**/\r
\r
#include "MpLib.h"\r
-#include <Library/VmgExitLib.h>\r
+#include <Library/CcExitLib.h>\r
#include <Register/Amd/Fam17Msr.h>\r
#include <Register/Amd/Ghcb.h>\r
\r
+++ /dev/null
-/** @file\r
-\r
- Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-#include <Base.h>\r
-#include <Uefi.h>\r
-#include <Library/VmgExitLib.h>\r
-\r
-/**\r
- Handle a #VE exception.\r
-\r
- Performs the necessary processing to handle a #VE 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 #VE not supported, (new) exception value to\r
- propagate provided\r
- @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to\r
- propagate provided\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-VmTdExitHandleVe (\r
- IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
- IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
- )\r
-{\r
- *ExceptionType = VE_EXCEPTION;\r
-\r
- return EFI_UNSUPPORTED;\r
-}\r
+++ /dev/null
-/** @file\r
- VMGEXIT Base 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/VmgExitLib.h>\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
- The base library function returns an error in the form of a\r
- GHCB_EVENT_INJECTION representing a GP_EXCEPTION.\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_EVENT_INJECTION Event;\r
-\r
- Event.Uint64 = 0;\r
- Event.Elements.Vector = GP_EXCEPTION;\r
- Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
- Event.Elements.Valid = 1;\r
-\r
- return Event.Uint64;\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
- @param[in, out] InterruptState A pointer to hold the current interrupt\r
- state, used for restoring in VmgDone ()\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgInit (\r
- IN OUT GHCB *Ghcb,\r
- IN OUT BOOLEAN *InterruptState\r
- )\r
-{\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
- @param[in] InterruptState An indicator to conditionally (re)enable\r
- interrupts\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgDone (\r
- IN OUT GHCB *Ghcb,\r
- IN BOOLEAN InterruptState\r
- )\r
-{\r
-}\r
-\r
-/**\r
- Marks a field at the specified offset as valid in the GHCB.\r
-\r
- The ValidBitmap area represents the areas of the GHCB that have been marked\r
- valid. Set the bit in ValidBitmap for the input offset.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
- @param[in] Offset Qword offset in the GHCB to mark valid\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VmgSetOffsetValid (\r
- IN OUT GHCB *Ghcb,\r
- IN GHCB_REGISTER Offset\r
- )\r
-{\r
-}\r
-\r
-/**\r
- Checks if a specified offset is valid in the GHCB.\r
-\r
- The ValidBitmap area represents the areas of the GHCB that have been marked\r
- valid. Return whether the bit in the ValidBitmap is set for the input offset.\r
-\r
- @param[in] Ghcb A pointer to the GHCB\r
- @param[in] Offset Qword offset in the GHCB to mark valid\r
-\r
- @retval TRUE Offset is marked valid in the GHCB\r
- @retval FALSE Offset is not marked valid in the GHCB\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-VmgIsOffsetValid (\r
- IN GHCB *Ghcb,\r
- IN GHCB_REGISTER Offset\r
- )\r
-{\r
- return FALSE;\r
-}\r
-\r
-/**\r
- Handle a #VC exception.\r
-\r
- Performs the necessary processing to handle a #VC exception.\r
-\r
- The base library function returns an error equal to VC_EXCEPTION,\r
- to be propagated to the standard exception handling stack.\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
- *ExceptionType = VC_EXCEPTION;\r
-\r
- return EFI_UNSUPPORTED;\r
-}\r
+++ /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
-[Defines]\r
- INF_VERSION = 0x00010005\r
- BASE_NAME = VmgExitLibNull\r
- MODULE_UNI_FILE = VmgExitLibNull.uni\r
- FILE_GUID = 3cd7368f-ef9b-4a9b-9571-2ed93813677e\r
- MODULE_TYPE = BASE\r
- VERSION_STRING = 1.0\r
- LIBRARY_CLASS = VmgExitLib\r
-\r
-[Sources.common]\r
- VmgExitLibNull.c\r
- VmTdExitNull.c\r
-\r
-[Packages]\r
- MdePkg/MdePkg.dec\r
- UefiCpuPkg/UefiCpuPkg.dec\r
-\r
-[LibraryClasses]\r
- BaseLib\r
-\r
+++ /dev/null
-// /** @file\r
-// VMGEXIT support library instance.\r
-//\r
-// VMGEXIT support library instance.\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
-\r
-#string STR_MODULE_ABSTRACT #language en-US "VMGEXIT support NULL library instance"\r
-\r
-#string STR_MODULE_DESCRIPTION #language en-US "VMGEXIT support NULL library instance."\r
-\r
##\r
MpInitLib|Include/Library/MpInitLib.h\r
\r
- ## @libraryclass Provides function to support VMGEXIT processing.\r
- VmgExitLib|Include/Library/VmgExitLib.h\r
+ ## @libraryclass Provides function to support CcExit processing.\r
+ CcExitLib|Include/Library/CcExitLib.h\r
\r
## @libraryclass Provides function to get CPU cache information.\r
CpuCacheInfoLib|Include/Library/CpuCacheInfoLib.h\r
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf\r
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf\r
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf\r
SmmCpuRendezvousLib|UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf\r
CpuPageTableLib|UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf\r
UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf\r
UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf\r
UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf\r
- UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf\r
UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf\r
UefiCpuPkg/SecCore/SecCore.inf\r
VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf\r
VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf\r
VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf\r
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf\r
+ CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf\r
ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf\r
\r
[LibraryClasses.common]\r