]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/VmgExitLib: Add support for IOIO_PROT NAE events
authorTom Lendacky <thomas.lendacky@amd.com>
Wed, 12 Aug 2020 20:21:37 +0000 (15:21 -0500)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 17 Aug 2020 02:46:39 +0000 (02:46 +0000)
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198

Under SEV-ES, a IOIO_PROT intercept generates a #VC exception. VMGEXIT
must be used to allow the hypervisor to handle this intercept.

Add support to construct the required GHCB values to support a IOIO_PROT
NAE event.  Parse the instruction that generated the #VC exception,
setting the required register values in the GHCB and creating the proper
SW_EXITINFO1 value in the GHCB.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
OvmfPkg/Include/IndustryStandard/InstructionParsing.h [new file with mode: 0644]
OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c

diff --git a/OvmfPkg/Include/IndustryStandard/InstructionParsing.h b/OvmfPkg/Include/IndustryStandard/InstructionParsing.h
new file mode 100644 (file)
index 0000000..149ff32
--- /dev/null
@@ -0,0 +1,83 @@
+/** @file\r
+  Instruction parsing support definitions.\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 __INSTRUCTION_PARSING_H__\r
+#define __INSTRUCTION_PARSING_H__\r
+\r
+#include <Base.h>\r
+#include <Uefi.h>\r
+\r
+//\r
+// Instruction REX prefix definition\r
+//\r
+typedef union {\r
+  struct {\r
+    UINT8  BitB:1;\r
+    UINT8  BitX:1;\r
+    UINT8  BitR:1;\r
+    UINT8  BitW:1;\r
+    UINT8  Rex:4;\r
+  } Bits;\r
+\r
+  UINT8  Uint8;\r
+} INSTRUCTION_REX_PREFIX;\r
+\r
+//\r
+// Instruction ModRM definition\r
+//\r
+typedef union {\r
+  struct {\r
+    UINT8  Rm:3;\r
+    UINT8  Reg:3;\r
+    UINT8  Mod:2;\r
+  } Bits;\r
+\r
+  UINT8  Uint8;\r
+} INSTRUCTION_MODRM;\r
+\r
+//\r
+// Instruction SIB definition\r
+//\r
+typedef union {\r
+  struct {\r
+    UINT8  Base:3;\r
+    UINT8  Index:3;\r
+    UINT8  Scale:2;\r
+  } Bits;\r
+\r
+  UINT8  Uint8;\r
+} INSTRUCTION_SIB;\r
+\r
+//\r
+// Legacy Instruction Prefixes\r
+//\r
+#define OVERRIDE_SEGMENT_CS          0x2E\r
+#define OVERRIDE_SEGMENT_DS          0x3E\r
+#define OVERRIDE_SEGMENT_ES          0x26\r
+#define OVERRIDE_SEGMENT_SS          0x36\r
+#define OVERRIDE_SEGMENT_FS          0x64\r
+#define OVERRIDE_SEGMENT_GS          0x65\r
+#define OVERRIDE_OPERAND_SIZE        0x66\r
+#define OVERRIDE_ADDRESS_SIZE        0x67\r
+#define LOCK_PREFIX                  0xF0\r
+#define REPNZ_PREFIX                 0xF2\r
+#define REPZ_PREFIX                  0xF3\r
+\r
+//\r
+// REX Prefixes\r
+//\r
+#define REX_PREFIX_START             0x40\r
+#define REX_PREFIX_STOP              0x4F\r
+#define REX_64BIT_OPERAND_SIZE_MASK  0x08\r
+\r
+//\r
+// Two-byte Opcode Flag\r
+//\r
+#define TWO_BYTE_OPCODE_ESCAPE       0x0F\r
+\r
+#endif\r
index b6a955ed8088b4ce6aa85de918ec44e3815db36f..04e8b8aebf7db6b84e5342d06e12cca2bcf9a01c 100644 (file)
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/VmgExitLib.h>\r
 #include <Register/Amd/Msr.h>\r
+#include <IndustryStandard/InstructionParsing.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
+/**\r
+  Checks the GHCB to determine if the specified register has been marked valid.\r
+\r
+  The ValidBitmap area represents the areas of the GHCB that have been marked\r
+  valid. Return an indication of whether the area of the GHCB that holds the\r
+  specified register has been marked valid.\r
+\r
+  @param[in] Ghcb    Pointer to the Guest-Hypervisor Communication Block\r
+  @param[in] Reg     Offset in the GHCB of the register to check\r
+\r
+  @retval TRUE       Register has been marked vald in the GHCB\r
+  @retval FALSE      Register has not been marked valid in the GHCB\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+GhcbIsRegValid (\r
+  IN GHCB                *Ghcb,\r
+  IN GHCB_REGISTER       Reg\r
+  )\r
+{\r
+  UINT32  RegIndex;\r
+  UINT32  RegBit;\r
+\r
+  RegIndex = Reg / 8;\r
+  RegBit   = Reg & 0x07;\r
+\r
+  return ((Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit)) != 0);\r
+}\r
+\r
+/**\r
+  Marks a register as valid in the GHCB.\r
+\r
+  The ValidBitmap area represents the areas of the GHCB that have been marked\r
+  valid. Set the area of the GHCB that holds the specified register as valid.\r
+\r
+  @param[in, out] Ghcb    Pointer to the Guest-Hypervisor Communication Block\r
+  @param[in] Reg          Offset in the GHCB of the register to mark valid\r
+\r
+**/\r
+STATIC\r
+VOID\r
+GhcbSetRegValid (\r
+  IN OUT GHCB                *Ghcb,\r
+  IN     GHCB_REGISTER       Reg\r
+  )\r
+{\r
+  UINT32  RegIndex;\r
+  UINT32  RegBit;\r
+\r
+  RegIndex = Reg / 8;\r
+  RegBit   = Reg & 0x07;\r
+\r
+  Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);\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
+      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
+      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
+      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
+  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
+  // 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 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, Status;\r
+\r
+  ExitInfo1 = IoioExitInfo (Regs, InstructionData);\r
+  if (ExitInfo1 == 0) {\r
+    return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+  }\r
+\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
+  GhcbSetRegValid (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 (!GhcbIsRegValid (Ghcb, GhcbRax)) {\r
+      return UnsupportedExit (Ghcb, Regs, InstructionData);\r
+    }\r
+    CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
+  }\r
+\r
+  return 0;\r
+}\r
 \r
 /**\r
   Handle a #VC exception.\r
@@ -38,6 +561,8 @@ VmgExitHandleVc (
   MSR_SEV_ES_GHCB_REGISTER  Msr;\r
   EFI_SYSTEM_CONTEXT_X64    *Regs;\r
   GHCB                      *Ghcb;\r
+  NAE_EXIT                  NaeExit;\r
+  SEV_ES_INSTRUCTION_DATA   InstructionData;\r
   UINT64                    ExitCode, Status;\r
   EFI_STATUS                VcRet;\r
 \r
@@ -54,24 +579,31 @@ VmgExitHandleVc (
 \r
   ExitCode = Regs->ExceptionData;\r
   switch (ExitCode) {\r
+  case SVM_EXIT_IOIO_PROT:\r
+    NaeExit = IoioExit;\r
+    break;\r
+\r
   default:\r
-    Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, ExitCode, 0);\r
-    if (Status == 0) {\r
-      Regs->ExceptionData = 0;\r
-      *ExceptionType = GP_EXCEPTION;\r
-    } else {\r
-      GHCB_EVENT_INJECTION  Event;\r
+    NaeExit = UnsupportedExit;\r
+  }\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
+  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
-      *ExceptionType = Event.Elements.Vector;\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