]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/CcExitLib: Refactor TDX MmioExit
authorMin M Xu <min.m.xu@intel.com>
Tue, 17 Jan 2023 07:43:30 +0000 (15:43 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 18 Jan 2023 03:47:31 +0000 (03:47 +0000)
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4169

The previous TDX MmioExit doesn't handle the Mmio instructions correctly
in some scenarios. This patch refactors the implementation to fix the
issues.

Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Ryan Afranji <afranji@google.com>
Reported-by: Ryan Afranji <afranji@google.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
OvmfPkg/Library/CcExitLib/CcExitVeHandler.c

index 30d547d5fe5537ba7e87b24e028355c58174354b..b8979ec2c0c01dbd96ad9107484d8488579329b9 100644 (file)
 #include <Library/BaseMemoryLib.h>\r
 #include <IndustryStandard/Tdx.h>\r
 #include <IndustryStandard/InstructionParsing.h>\r
+#include "CcInstruction.h"\r
+\r
+#define TDX_MMIO_READ   0\r
+#define TDX_MMIO_WRITE  1\r
 \r
 typedef union {\r
   struct {\r
@@ -216,14 +220,15 @@ STATIC
 VOID\r
 EFIAPI\r
 TdxDecodeInstruction (\r
-  IN UINT8  *Rip\r
+  IN UINT8   *Rip,\r
+  IN UINT32  Length\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
+  for (i = 0; i < MIN (15, Length); i++) {\r
+    DEBUG ((DEBUG_INFO, "%02x ", Rip[i]));\r
   }\r
 \r
   DEBUG ((DEBUG_INFO, "\n"));\r
@@ -233,52 +238,339 @@ TdxDecodeInstruction (
   if ((x)) {                                \\r
     TdxDecodeInstruction(Rip);              \\r
     TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \\r
+    CpuDeadLoop (); \\r
   }\r
 \r
+/**\r
+ * Tdx MMIO access via TdVmcall.\r
+ *\r
+ * @param MmioSize      Size of the MMIO access\r
+ * @param ReadOrWrite   Read or write operation\r
+ * @param GuestPA       Guest physical address\r
+ * @param Val           Pointer to the value which is read or written\r
+\r
+ * @retval EFI_SUCCESS  Successfully access the mmio\r
+ * @retval Others       Other errors as indicated\r
+ */\r
 STATIC\r
-UINT64 *\r
-EFIAPI\r
-GetRegFromContext (\r
-  IN EFI_SYSTEM_CONTEXT_X64  *Regs,\r
-  IN UINTN                   RegIndex\r
+EFI_STATUS\r
+TdxMmioReadWrite (\r
+  IN UINT32  MmioSize,\r
+  IN UINT32  ReadOrWrite,\r
+  IN UINT64  GuestPA,\r
+  IN UINT64  *Val\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
+  UINT64  TdStatus;\r
+\r
+  if ((MmioSize != 1) && (MmioSize != 2) && (MmioSize != 4) && (MmioSize != 8)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: Invalid MmioSize - %d\n", __FUNCTION__, MmioSize));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Val == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TdStatus = 0;\r
+  if (ReadOrWrite == TDX_MMIO_READ) {\r
+    TdStatus = TdVmCall (TDVMCALL_MMIO, MmioSize, TDX_MMIO_READ, GuestPA, 0, Val);\r
+  } else if (ReadOrWrite == TDX_MMIO_WRITE) {\r
+    TdStatus = TdVmCall (TDVMCALL_MMIO, MmioSize, TDX_MMIO_WRITE, GuestPA, *Val, 0);\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (TdStatus != 0) {\r
+    DEBUG ((DEBUG_ERROR, "%a: TdVmcall failed with %llx\n", __FUNCTION__, TdStatus));\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+typedef struct {\r
+  UINT8                   OpCode;\r
+  UINT32                  Bytes;\r
+  EFI_PHYSICAL_ADDRESS    Address;\r
+  UINT64                  Val;\r
+  UINT64                  *Register;\r
+  UINT32                  ReadOrWrite;\r
+} MMIO_EXIT_PARSED_INSTRUCTION;\r
+\r
+/**\r
+ * Parse the MMIO instructions.\r
+ *\r
+ * @param Regs              Pointer to the EFI_SYSTEM_CONTEXT_X64 which includes the instructions\r
+ * @param InstructionData   Pointer to the CC_INSTRUCTION_DATA\r
+ * @param ParsedInstruction Pointer to the parsed instruction data\r
+ *\r
+ * @retval EFI_SUCCESS      Successfully parsed the instructions\r
+ * @retval Others           Other error as indicated\r
+ */\r
+STATIC\r
+EFI_STATUS\r
+ParseMmioExitInstructions (\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64     *Regs,\r
+  IN OUT CC_INSTRUCTION_DATA        *InstructionData,\r
+  OUT MMIO_EXIT_PARSED_INSTRUCTION  *ParsedInstruction\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT8                 OpCode;\r
+  UINT8                 SignByte;\r
+  UINT32                Bytes;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  UINT64                Val;\r
+  UINT64                *Register;\r
+  UINT32                ReadOrWrite;\r
+\r
+  Address  = 0;\r
+  Bytes    = 0;\r
+  Register = NULL;\r
+  Status   = EFI_SUCCESS;\r
+  Val      = 0;\r
+\r
+  Status = CcInitInstructionData (InstructionData, NULL, Regs);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: Initialize InstructionData failed! (%r)\n", __FUNCTION__, Status));\r
+    return Status;\r
+  }\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
+      CcDecodeModRm (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
+        DEBUG ((DEBUG_ERROR, "%a: Parse Ext.ModRm.Mod error! (OpCode: 0x%x)\n", __FUNCTION__, OpCode));\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+\r
+      Address     = InstructionData->Ext.RmData;\r
+      Val         = InstructionData->Ext.RegData;\r
+      ReadOrWrite = TDX_MMIO_WRITE;\r
+\r
       break;\r
-    case 10: return &Regs->R10;\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
+      CopyMem (&Address, InstructionData->Immediate, InstructionData->ImmediateSize);\r
+\r
+      Val         = Regs->Rax;\r
+      ReadOrWrite = TDX_MMIO_WRITE;\r
       break;\r
-    case 11: return &Regs->R11;\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
+      CcDecodeModRm (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
+      InstructionData->ImmediateSize = Bytes;\r
+      InstructionData->End          += Bytes;\r
+\r
+      Val = 0;\r
+      CopyMem (&Val, InstructionData->Immediate, InstructionData->ImmediateSize);\r
+\r
+      Address     = InstructionData->Ext.RmData;\r
+      ReadOrWrite = TDX_MMIO_WRITE;\r
+\r
       break;\r
-    case 12: return &Regs->R12;\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
+      CcDecodeModRm (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
+        DEBUG ((DEBUG_ERROR, "%a: Parse Ext.ModRm.Mod error! (OpCode: 0x%x)\n", __FUNCTION__, OpCode));\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+\r
+      Address     = InstructionData->Ext.RmData;\r
+      ReadOrWrite = TDX_MMIO_READ;\r
+\r
+      Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+      if (Register == NULL) {\r
+        return EFI_ABORTED;\r
+      }\r
+\r
+      if (Bytes == 4) {\r
+        //\r
+        // Zero-extend for 32-bit operation\r
+        //\r
+        *Register = 0;\r
+      }\r
+\r
       break;\r
-    case 13: return &Regs->R13;\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
+      Address = 0;\r
+      CopyMem (\r
+        &Address,\r
+        InstructionData->Immediate,\r
+        InstructionData->ImmediateSize\r
+        );\r
+\r
+      if (Bytes == 4) {\r
+        //\r
+        // Zero-extend for 32-bit operation\r
+        //\r
+        Regs->Rax = 0;\r
+      }\r
+\r
+      Register    = &Regs->Rax;\r
+      ReadOrWrite = TDX_MMIO_READ;\r
+\r
       break;\r
-    case 14: return &Regs->R14;\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
+      CcDecodeModRm (Regs, InstructionData);\r
+      Bytes   = (Bytes != 0) ? Bytes : 2;\r
+      Address = InstructionData->Ext.RmData;\r
+\r
+      Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+      if (Register == NULL) {\r
+        return EFI_ABORTED;\r
+      }\r
+\r
+      SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);\r
+\r
+      ReadOrWrite = TDX_MMIO_READ;\r
+\r
       break;\r
-    case 15: return &Regs->R15;\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
+      CcDecodeModRm (Regs, InstructionData);\r
+      Bytes = (Bytes != 0) ? Bytes : 2;\r
+\r
+      Address = InstructionData->Ext.RmData;\r
+\r
+      if (Bytes == 1) {\r
+        UINT8  *Data;\r
+        Data     = (UINT8 *)&Val;\r
+        SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;\r
+      } else {\r
+        UINT16  *Data;\r
+        Data     = (UINT16 *)&Val;\r
+        SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;\r
+      }\r
+\r
+      Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+      if (Register == NULL) {\r
+        return EFI_ABORTED;\r
+      }\r
+\r
+      SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);\r
+\r
+      ReadOrWrite = TDX_MMIO_READ;\r
+\r
       break;\r
+\r
+    default:\r
+      DEBUG ((DEBUG_ERROR, "%a: Invalid MMIO opcode (%x)\n", __FUNCTION__, OpCode));\r
+      Status = EFI_UNSUPPORTED;\r
   }\r
 \r
-  return NULL;\r
+  if (!EFI_ERROR (Status)) {\r
+    ParsedInstruction->OpCode      = OpCode;\r
+    ParsedInstruction->Address     = Address;\r
+    ParsedInstruction->Bytes       = Bytes;\r
+    ParsedInstruction->Register    = Register;\r
+    ParsedInstruction->Val         = Val;\r
+    ParsedInstruction->ReadOrWrite = ReadOrWrite;\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -290,160 +582,84 @@ GetRegFromContext (
   @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
+UINT64\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
+  UINT64                        TdStatus;\r
+  EFI_STATUS                    Status;\r
+  TD_RETURN_DATA                TdReturnData;\r
+  UINT8                         Gpaw;\r
+  UINT64                        Val;\r
+  UINT64                        TdSharedPageMask;\r
+  CC_INSTRUCTION_DATA           InstructionData;\r
+  MMIO_EXIT_PARSED_INSTRUCTION  ParsedInstruction;\r
+\r
+  TdStatus = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);\r
+  if (TdStatus == 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
+    DEBUG ((DEBUG_ERROR, "%a: TDCALL failed with status=%llx\n", __FUNCTION__, TdStatus));\r
+    goto FatalError;\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
+    DEBUG ((DEBUG_ERROR, "%a: EPT-violation #VE on private memory is not allowed!", __FUNCTION__));\r
+    goto FatalError;\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
+  Status = ParseMmioExitInstructions (Regs, &InstructionData, &ParsedInstruction);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FatalError;\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
+  if (Veinfo->GuestPA != (ParsedInstruction.Address | TdSharedPageMask)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: Address is not correct! (%d: 0x%llx != 0x%llx)\n",\r
+      __FUNCTION__,\r
+      ParsedInstruction.OpCode,\r
+      Veinfo->GuestPA,\r
+      ParsedInstruction.Address\r
+      ));\r
+    goto FatalError;\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
+  if (ParsedInstruction.ReadOrWrite == TDX_MMIO_WRITE ) {\r
+    Status = TdxMmioReadWrite (ParsedInstruction.Bytes, TDX_MMIO_WRITE, Veinfo->GuestPA, &ParsedInstruction.Val);\r
+  } else if (ParsedInstruction.ReadOrWrite == TDX_MMIO_READ) {\r
+    Val    = 0;\r
+    Status = TdxMmioReadWrite (ParsedInstruction.Bytes, TDX_MMIO_READ, Veinfo->GuestPA, &Val);\r
+    if (!EFI_ERROR (Status)) {\r
+      CopyMem (ParsedInstruction.Register, &Val, ParsedInstruction.Bytes);\r
+    }\r
+  } else {\r
+    goto FatalError;\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
+  if (EFI_ERROR (Status)) {\r
+    goto FatalError;\r
   }\r
 \r
-  if (Status == 0) {\r
-    TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15);\r
+  //\r
+  // We change instruction length to reflect true size so handler can\r
+  // bump rip\r
+  //\r
+  Veinfo->ExitInstructionLength =  (UINT32)(CcInstructionLength (&InstructionData));\r
+  TdxDecodeInstruction ((UINT8 *)Regs->Rip, Veinfo->ExitInstructionLength);\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
+  return 0;\r
 \r
-  return Status;\r
+FatalError:\r
+  TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+  CpuDeadLoop ();\r
+  return 0;\r
 }\r
 \r
 /**\r
@@ -479,6 +695,7 @@ CcExitHandleVe (
   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
+    CpuDeadLoop ();\r
   }\r
 \r
   switch (ReturnData.VeInfo.ExitReason) {\r
@@ -571,6 +788,7 @@ CcExitHandleVe (
       ));\r
 \r
     TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+    CpuDeadLoop ();\r
   }\r
 \r
   SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength;\r