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

Move common X86 instruction codes from CcExitVcHandler.c to separate
files (CcInstruction.h / CcInstruction.c) so that these codes can be
re-used in TDX.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
OvmfPkg/Library/CcExitLib/CcExitLib.inf
OvmfPkg/Library/CcExitLib/CcExitVcHandler.c
OvmfPkg/Library/CcExitLib/CcInstruction.c [new file with mode: 0644]
OvmfPkg/Library/CcExitLib/CcInstruction.h [new file with mode: 0644]
OvmfPkg/Library/CcExitLib/SecCcExitLib.inf

index 131fa62675222bac6cc6333b951733c65816a072..bc75cd5f5a045b63aa25266f3341df04a9470fe0 100644 (file)
@@ -25,6 +25,7 @@
   CcExitLib.c\r
   CcExitVcHandler.c\r
   CcExitVcHandler.h\r
+  CcInstruction.c\r
   PeiDxeCcExitVcHandler.c\r
   CcExitVeHandler.c\r
   X64/TdVmcallCpuid.nasm\r
index 985e5479775ca5bc149d398ec99ff76ea9afbf8d..7fe11c53249ed648cd61bb26752621e7074cfd3c 100644 (file)
 #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
+#include "CcInstruction.h"\r
 \r
 //\r
 // Non-automatic Exit function prototype\r
@@ -125,9 +25,9 @@ typedef struct {
 typedef\r
 UINT64\r
 (*NAE_EXIT) (\r
-  GHCB                     *Ghcb,\r
-  EFI_SYSTEM_CONTEXT_X64   *Regs,\r
-  SEV_ES_INSTRUCTION_DATA  *InstructionData\r
+  GHCB                    *Ghcb,\r
+  EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  CC_INSTRUCTION_DATA     *InstructionData\r
   );\r
 \r
 //\r
@@ -155,439 +55,6 @@ typedef PACKED struct {
   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
@@ -604,9 +71,9 @@ InitInstructionData (
 STATIC\r
 UINT64\r
 UnsupportedExit (\r
-  IN GHCB                     *Ghcb,\r
-  IN EFI_SYSTEM_CONTEXT_X64   *Regs,\r
-  IN SEV_ES_INSTRUCTION_DATA  *InstructionData\r
+  IN GHCB                    *Ghcb,\r
+  IN EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64  Status;\r
@@ -703,9 +170,9 @@ ValidateMmioMemory (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN OUT CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64  ExitInfo1, ExitInfo2, Status;\r
@@ -731,7 +198,7 @@ MmioExit (
     // fall through\r
     //\r
     case 0x89:\r
-      DecodeModRm (Regs, InstructionData);\r
+      CcDecodeModRm (Regs, InstructionData);\r
       Bytes = ((Bytes != 0) ? Bytes :\r
                (InstructionData->DataSize == Size16Bits) ? 2 :\r
                (InstructionData->DataSize == Size32Bits) ? 4 :\r
@@ -824,7 +291,7 @@ MmioExit (
     // fall through\r
     //\r
     case 0xC7:\r
-      DecodeModRm (Regs, InstructionData);\r
+      CcDecodeModRm (Regs, InstructionData);\r
       Bytes = ((Bytes != 0) ? Bytes :\r
                (InstructionData->DataSize == Size16Bits) ? 2 :\r
                (InstructionData->DataSize == Size32Bits) ? 4 :\r
@@ -860,7 +327,7 @@ MmioExit (
     // fall through\r
     //\r
     case 0x8B:\r
-      DecodeModRm (Regs, InstructionData);\r
+      CcDecodeModRm (Regs, InstructionData);\r
       Bytes = ((Bytes != 0) ? Bytes :\r
                (InstructionData->DataSize == Size16Bits) ? 2 :\r
                (InstructionData->DataSize == Size32Bits) ? 4 :\r
@@ -888,7 +355,7 @@ MmioExit (
         return Status;\r
       }\r
 \r
-      Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+      Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
       if (Bytes == 4) {\r
         //\r
         // Zero-extend for 32-bit operation\r
@@ -967,7 +434,7 @@ MmioExit (
     // fall through\r
     //\r
     case 0xB7:\r
-      DecodeModRm (Regs, InstructionData);\r
+      CcDecodeModRm (Regs, InstructionData);\r
       Bytes = (Bytes != 0) ? Bytes : 2;\r
 \r
       Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
@@ -985,7 +452,7 @@ MmioExit (
         return Status;\r
       }\r
 \r
-      Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+      Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
       SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);\r
       CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
       break;\r
@@ -999,7 +466,7 @@ MmioExit (
     // fall through\r
     //\r
     case 0xBF:\r
-      DecodeModRm (Regs, InstructionData);\r
+      CcDecodeModRm (Regs, InstructionData);\r
       Bytes = (Bytes != 0) ? Bytes : 2;\r
 \r
       Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
@@ -1029,7 +496,7 @@ MmioExit (
         SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;\r
       }\r
 \r
-      Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
+      Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
       SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);\r
       CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
       break;\r
@@ -1060,12 +527,12 @@ MmioExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
-  DecodeModRm (Regs, InstructionData);\r
+  CcDecodeModRm (Regs, InstructionData);\r
 \r
   Ghcb->SaveArea.Rax = Regs->Rax;\r
   CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
@@ -1092,12 +559,12 @@ MwaitExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
-  DecodeModRm (Regs, InstructionData);\r
+  CcDecodeModRm (Regs, InstructionData);\r
 \r
   Ghcb->SaveArea.Rax = Regs->Rax;  // Identity mapped, so VA = PA\r
   CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
@@ -1126,9 +593,9 @@ MonitorExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   return CcExitVmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);\r
@@ -1151,14 +618,14 @@ WbinvdExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64  Status;\r
 \r
-  DecodeModRm (Regs, InstructionData);\r
+  CcDecodeModRm (Regs, InstructionData);\r
 \r
   Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);\r
   if (Status != 0) {\r
@@ -1196,14 +663,14 @@ RdtscpExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64  Status;\r
 \r
-  DecodeModRm (Regs, InstructionData);\r
+  CcDecodeModRm (Regs, InstructionData);\r
 \r
   Ghcb->SaveArea.Rax = Regs->Rax;\r
   CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
@@ -1241,9 +708,9 @@ VmmCallExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64  ExitInfo1, Status;\r
@@ -1302,8 +769,8 @@ MsrExit (
 STATIC\r
 UINT64\r
 IoioExitInfo (\r
-  IN     EFI_SYSTEM_CONTEXT_X64   *Regs,\r
-  IN OUT SEV_ES_INSTRUCTION_DATA  *InstructionData\r
+  IN     EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN OUT CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64  ExitInfo;\r
@@ -1437,9 +904,9 @@ IoioExitInfo (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64   ExitInfo1, ExitInfo2, Status;\r
@@ -1531,9 +998,9 @@ IoioExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   return CcExitVmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);\r
@@ -1949,9 +1416,9 @@ Out:
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   BOOLEAN  Unsupported;\r
@@ -2041,9 +1508,9 @@ CpuidFail:
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64  Status;\r
@@ -2085,9 +1552,9 @@ RdpmcExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
   UINT64  Status;\r
@@ -2126,25 +1593,25 @@ RdtscExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_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
+  CC_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
+  CcDecodeModRm (Regs, InstructionData);\r
 \r
   //\r
   // MOV DRn always treats MOD == 3 no matter how encoded\r
   //\r
-  Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+  Register = CcGetRegisterPointer (Regs, Ext->ModRm.Rm);\r
 \r
   //\r
   // Using a value of 0 for ExitInfo1 means RAX holds the value\r
@@ -2179,24 +1646,24 @@ Dr7WriteExit (
 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
+  IN OUT GHCB                    *Ghcb,\r
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN     CC_INSTRUCTION_DATA     *InstructionData\r
   )\r
 {\r
-  SEV_ES_INSTRUCTION_OPCODE_EXT  *Ext;\r
-  SEV_ES_PER_CPU_DATA            *SevEsData;\r
-  UINT64                         *Register;\r
+  CC_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
+  CcDecodeModRm (Regs, InstructionData);\r
 \r
   //\r
   // MOV DRn always treats MOD == 3 no matter how encoded\r
   //\r
-  Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+  Register = CcGetRegisterPointer (Regs, Ext->ModRm.Rm);\r
 \r
   //\r
   // If there is a cached valued for DR7, return that. Otherwise return the\r
@@ -2232,12 +1699,12 @@ InternalVmgExitHandleVc (
   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
+  EFI_SYSTEM_CONTEXT_X64  *Regs;\r
+  NAE_EXIT                NaeExit;\r
+  CC_INSTRUCTION_DATA     InstructionData;\r
+  UINT64                  ExitCode, Status;\r
+  EFI_STATUS              VcRet;\r
+  BOOLEAN                 InterruptState;\r
 \r
   VcRet = EFI_SUCCESS;\r
 \r
@@ -2307,11 +1774,11 @@ InternalVmgExitHandleVc (
       NaeExit = UnsupportedExit;\r
   }\r
 \r
-  InitInstructionData (&InstructionData, Ghcb, Regs);\r
+  CcInitInstructionData (&InstructionData, Ghcb, Regs);\r
 \r
   Status = NaeExit (Ghcb, Regs, &InstructionData);\r
   if (Status == 0) {\r
-    Regs->Rip += InstructionLength (&InstructionData);\r
+    Regs->Rip += CcInstructionLength (&InstructionData);\r
   } else {\r
     GHCB_EVENT_INJECTION  Event;\r
 \r
diff --git a/OvmfPkg/Library/CcExitLib/CcInstruction.c b/OvmfPkg/Library/CcExitLib/CcInstruction.c
new file mode 100644 (file)
index 0000000..0fb54b3
--- /dev/null
@@ -0,0 +1,454 @@
+/** @file\r
+  X64 Instruction function.\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 <Register/Intel/Cpuid.h>\r
+#include <IndustryStandard/InstructionParsing.h>\r
+#include "CcInstruction.h"\r
+\r
+#define MAX_INSTRUCTION_LENGTH  15\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
+UINT64 *\r
+CcGetRegisterPointer (\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 CC_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 CC_INSTRUCTION_DATA  *InstructionData\r
+  )\r
+{\r
+  CC_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 CC_INSTRUCTION_DATA     *InstructionData\r
+  )\r
+{\r
+  CC_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
+        CcGetRegisterPointer (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 += *CcGetRegisterPointer (Regs, Ext->Sib.Base);\r
+    } else {\r
+      UpdateForDisplacement (InstructionData, 4);\r
+      EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
+    }\r
+  } else {\r
+    EffectiveAddress += *CcGetRegisterPointer (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
+VOID\r
+CcDecodeModRm (\r
+  IN     EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN OUT CC_INSTRUCTION_DATA     *InstructionData\r
+  )\r
+{\r
+  CC_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 = *CcGetRegisterPointer (Regs, Ext->ModRm.Reg);\r
+\r
+  if (Ext->ModRm.Mod == 3) {\r
+    Ext->RmData = *CcGetRegisterPointer (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
+  @retval         EFI_SUCCESS      Successfully decode Prefixes\r
+  @retval         Others           Other error as indicated\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+DecodePrefixes (\r
+  IN     EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN OUT CC_INSTRUCTION_DATA     *InstructionData\r
+  )\r
+{\r
+  CC_INSTRUCTION_MODE  Mode;\r
+  CC_INSTRUCTION_SIZE  ModeDataSize;\r
+  CC_INSTRUCTION_SIZE  ModeAddrSize;\r
+  UINT8                *Byte;\r
+  UINT8                ParsedLength;\r
+\r
+  ParsedLength = 0;\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 ( ; ParsedLength <= MAX_INSTRUCTION_LENGTH; Byte++, InstructionData->PrefixSize++, ParsedLength++) {\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 EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_ABORTED;\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
+UINT64\r
+CcInstructionLength (\r
+  IN CC_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
+  @retval         EFI_SUCCESS      Successfully initialize InstructionData\r
+  @retval         Others           Other error as indicated\r
+**/\r
+EFI_STATUS\r
+CcInitInstructionData (\r
+  IN OUT CC_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
+  return DecodePrefixes (Regs, InstructionData);\r
+}\r
diff --git a/OvmfPkg/Library/CcExitLib/CcInstruction.h b/OvmfPkg/Library/CcExitLib/CcInstruction.h
new file mode 100644 (file)
index 0000000..a8223a6
--- /dev/null
@@ -0,0 +1,197 @@
+/** @file\r
+  Confidential Computing X64 Instruction\r
+\r
+  Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
+  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef CC_INSTRUCTION_H_\r
+#define CC_INSTRUCTION_H_\r
+\r
+#include <Base.h>\r
+#include <Uefi.h>\r
+#include <Register/Amd/Ghcb.h>\r
+#include <IndustryStandard/InstructionParsing.h>\r
+#include <Protocol/DebugSupport.h>\r
+\r
+//\r
+// Instruction execution mode definition\r
+//\r
+typedef enum {\r
+  LongMode64Bit = 0,\r
+  LongModeCompat32Bit,\r
+  LongModeCompat16Bit,\r
+} CC_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
+} CC_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
+} CC_INSTRUCTION_SEGMENT;\r
+\r
+//\r
+// Instruction rep function definition\r
+//\r
+typedef enum {\r
+  RepNone = 0,\r
+  RepZ,\r
+  RepNZ,\r
+} CC_INSTRUCTION_REP;\r
+\r
+typedef struct {\r
+  UINT8    Rm;\r
+  UINT8    Reg;\r
+  UINT8    Mod;\r
+} CC_INSTRUCTION_MODRM_EXT;\r
+\r
+typedef struct {\r
+  UINT8    Base;\r
+  UINT8    Index;\r
+  UINT8    Scale;\r
+} CC_INSTRUCTION_SIB_EXT;\r
+\r
+//\r
+// Instruction opcode definition\r
+//\r
+typedef struct {\r
+  CC_INSTRUCTION_MODRM_EXT    ModRm;\r
+\r
+  CC_INSTRUCTION_SIB_EXT      Sib;\r
+\r
+  UINTN                       RegData;\r
+  UINTN                       RmData;\r
+} CC_INSTRUCTION_OPCODE_EXT;\r
+\r
+//\r
+// Instruction parsing context definition\r
+//\r
+typedef struct {\r
+  GHCB                         *Ghcb;\r
+\r
+  CC_INSTRUCTION_MODE          Mode;\r
+  CC_INSTRUCTION_SIZE          DataSize;\r
+  CC_INSTRUCTION_SIZE          AddrSize;\r
+  BOOLEAN                      SegmentSpecified;\r
+  CC_INSTRUCTION_SEGMENT       Segment;\r
+  CC_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
+  CC_INSTRUCTION_OPCODE_EXT    Ext;\r
+} CC_INSTRUCTION_DATA;\r
+\r
+EFI_STATUS\r
+CcInitInstructionData (\r
+  IN OUT CC_INSTRUCTION_DATA     *InstructionData,\r
+  IN     GHCB                    *Ghcb,\r
+  IN     EFI_SYSTEM_CONTEXT_X64  *Regs\r
+  );\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
+UINT64 *\r
+CcGetRegisterPointer (\r
+  IN EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN UINT8                   Register\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
+VOID\r
+CcDecodeModRm (\r
+  IN     EFI_SYSTEM_CONTEXT_X64  *Regs,\r
+  IN OUT CC_INSTRUCTION_DATA     *InstructionData\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
+UINT64\r
+CcInstructionLength (\r
+  IN CC_INSTRUCTION_DATA  *InstructionData\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
+  @retval         EFI_SUCCESS      Successfully initialize InstructionData\r
+  @retval         Others           Other error as indicated\r
+**/\r
+EFI_STATUS\r
+CcInitInstructionData (\r
+  IN OUT CC_INSTRUCTION_DATA     *InstructionData,\r
+  IN     GHCB                    *Ghcb,\r
+  IN     EFI_SYSTEM_CONTEXT_X64  *Regs\r
+  );\r
+\r
+#endif\r
index 1ee22ce0aea192842d62b95c836b38aabe0b5d81..811269dd2c061cd7cbd16e4b185f114a97020c11 100644 (file)
@@ -24,6 +24,7 @@
   CcExitLib.c\r
   CcExitVcHandler.c\r
   CcExitVcHandler.h\r
+  CcInstruction.c\r
   SecCcExitVcHandler.c\r
   CcExitVeHandler.c\r
   X64/TdVmcallCpuid.nasm\r