From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mx.groups.io with SMTP id smtpd.web11.90720.1673308590013112462 for ; Mon, 09 Jan 2023 15:56:31 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=dWGpJJ5u; spf=pass (domain: intel.com, ip: 192.55.52.120, mailfrom: min.m.xu@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1673308591; x=1704844591; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+WUVXbNq3OOfKogkWB7ZZcK/mwpZFPQn3ShYpow38QY=; b=dWGpJJ5u1fwC/WNszzjLAOahJVbOqHSz8W2s15CKLrPoGfEVtSP+VeC3 Kf9s/fH7MdGx4PXt81rO8X24S1bHAyEqyit/tQk7N9MmGEx9vPvFObn7t gRQTH3iifZHyhfjnEiepVuHX88fUzU1GSGM+L8YWKITwI6q1u08loBBiQ dphTSMERkgfu4sgmlmKW0rKhmbP+L7x4DayHY0wj+BHl7D4NER1xyzfWl by77jNaTlymDoBrbi4NoeXsC9U5Lc68lmqdd+Kid2aCfd3wEHW1Kd8liB AJF0mNJjglSyOo9xELtVBRGJB5N5iNNPDMH8RoaTxK12Jr2T3d0mBoyvP A==; X-IronPort-AV: E=McAfee;i="6500,9779,10585"; a="321715277" X-IronPort-AV: E=Sophos;i="5.96,313,1665471600"; d="scan'208";a="321715277" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jan 2023 15:56:30 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10585"; a="689221917" X-IronPort-AV: E=Sophos;i="5.96,313,1665471600"; d="scan'208";a="689221917" Received: from caij-mobl.ccr.corp.intel.com (HELO mxu9-mobl1.ccr.corp.intel.com) ([10.255.29.89]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jan 2023 15:56:28 -0800 From: "Min Xu" To: devel@edk2.groups.io Cc: Min M Xu , Gerd Hoffmann , Erdem Aktas , James Bottomley , Jiewen Yao , Tom Lendacky Subject: [PATCH V2 1/2] OvmfPkg/CcExitLib: Move common X86 instruction code to separate file Date: Tue, 10 Jan 2023 07:56:11 +0800 Message-Id: <20230109235612.439-2-min.m.xu@intel.com> X-Mailer: git-send-email 2.29.2.windows.2 In-Reply-To: <20230109235612.439-1-min.m.xu@intel.com> References: <20230109235612.439-1-min.m.xu@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Min M Xu 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 Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Reviewed-by: Jiewen Yao Reviewed-by: Tom Lendacky Signed-off-by: Min Xu --- OvmfPkg/Library/CcExitLib/CcExitLib.inf | 1 + OvmfPkg/Library/CcExitLib/CcExitVcHandler.c | 697 +++----------------- OvmfPkg/Library/CcExitLib/CcInstruction.c | 454 +++++++++++++ OvmfPkg/Library/CcExitLib/CcInstruction.h | 197 ++++++ OvmfPkg/Library/CcExitLib/SecCcExitLib.inf | 1 + 5 files changed, 735 insertions(+), 615 deletions(-) create mode 100644 OvmfPkg/Library/CcExitLib/CcInstruction.c create mode 100644 OvmfPkg/Library/CcExitLib/CcInstruction.h diff --git a/OvmfPkg/Library/CcExitLib/CcExitLib.inf b/OvmfPkg/Library/CcExitLib/CcExitLib.inf index 131fa6267522..bc75cd5f5a04 100644 --- a/OvmfPkg/Library/CcExitLib/CcExitLib.inf +++ b/OvmfPkg/Library/CcExitLib/CcExitLib.inf @@ -25,6 +25,7 @@ CcExitLib.c CcExitVcHandler.c CcExitVcHandler.h + CcInstruction.c PeiDxeCcExitVcHandler.c CcExitVeHandler.c X64/TdVmcallCpuid.nasm diff --git a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c index 985e5479775c..7fe11c53249e 100644 --- a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c +++ b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c @@ -17,107 +17,7 @@ #include #include "CcExitVcHandler.h" - -// -// Instruction execution mode definition -// -typedef enum { - LongMode64Bit = 0, - LongModeCompat32Bit, - LongModeCompat16Bit, -} SEV_ES_INSTRUCTION_MODE; - -// -// Instruction size definition (for operand and address) -// -typedef enum { - Size8Bits = 0, - Size16Bits, - Size32Bits, - Size64Bits, -} SEV_ES_INSTRUCTION_SIZE; - -// -// Intruction segment definition -// -typedef enum { - SegmentEs = 0, - SegmentCs, - SegmentSs, - SegmentDs, - SegmentFs, - SegmentGs, -} SEV_ES_INSTRUCTION_SEGMENT; - -// -// Instruction rep function definition -// -typedef enum { - RepNone = 0, - RepZ, - RepNZ, -} SEV_ES_INSTRUCTION_REP; - -typedef struct { - UINT8 Rm; - UINT8 Reg; - UINT8 Mod; -} SEV_ES_INSTRUCTION_MODRM_EXT; - -typedef struct { - UINT8 Base; - UINT8 Index; - UINT8 Scale; -} SEV_ES_INSTRUCTION_SIB_EXT; - -// -// Instruction opcode definition -// -typedef struct { - SEV_ES_INSTRUCTION_MODRM_EXT ModRm; - - SEV_ES_INSTRUCTION_SIB_EXT Sib; - - UINTN RegData; - UINTN RmData; -} SEV_ES_INSTRUCTION_OPCODE_EXT; - -// -// Instruction parsing context definition -// -typedef struct { - GHCB *Ghcb; - - SEV_ES_INSTRUCTION_MODE Mode; - SEV_ES_INSTRUCTION_SIZE DataSize; - SEV_ES_INSTRUCTION_SIZE AddrSize; - BOOLEAN SegmentSpecified; - SEV_ES_INSTRUCTION_SEGMENT Segment; - SEV_ES_INSTRUCTION_REP RepMode; - - UINT8 *Begin; - UINT8 *End; - - UINT8 *Prefixes; - UINT8 *OpCodes; - UINT8 *Displacement; - UINT8 *Immediate; - - INSTRUCTION_REX_PREFIX RexPrefix; - - BOOLEAN ModRmPresent; - INSTRUCTION_MODRM ModRm; - - BOOLEAN SibPresent; - INSTRUCTION_SIB Sib; - - UINTN PrefixSize; - UINTN OpCodeSize; - UINTN DisplacementSize; - UINTN ImmediateSize; - - SEV_ES_INSTRUCTION_OPCODE_EXT Ext; -} SEV_ES_INSTRUCTION_DATA; +#include "CcInstruction.h" // // Non-automatic Exit function prototype @@ -125,9 +25,9 @@ typedef struct { typedef UINT64 (*NAE_EXIT) ( - GHCB *Ghcb, - EFI_SYSTEM_CONTEXT_X64 *Regs, - SEV_ES_INSTRUCTION_DATA *InstructionData + GHCB *Ghcb, + EFI_SYSTEM_CONTEXT_X64 *Regs, + CC_INSTRUCTION_DATA *InstructionData ); // @@ -155,439 +55,6 @@ typedef PACKED struct { SEV_SNP_CPUID_FUNCTION function[0]; } SEV_SNP_CPUID_INFO; -/** - Return a pointer to the contents of the specified register. - - Based upon the input register, return a pointer to the registers contents - in the x86 processor context. - - @param[in] Regs x64 processor context - @param[in] Register Register to obtain pointer for - - @return Pointer to the contents of the requested register - -**/ -STATIC -UINT64 * -GetRegisterPointer ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN UINT8 Register - ) -{ - UINT64 *Reg; - - switch (Register) { - case 0: - Reg = &Regs->Rax; - break; - case 1: - Reg = &Regs->Rcx; - break; - case 2: - Reg = &Regs->Rdx; - break; - case 3: - Reg = &Regs->Rbx; - break; - case 4: - Reg = &Regs->Rsp; - break; - case 5: - Reg = &Regs->Rbp; - break; - case 6: - Reg = &Regs->Rsi; - break; - case 7: - Reg = &Regs->Rdi; - break; - case 8: - Reg = &Regs->R8; - break; - case 9: - Reg = &Regs->R9; - break; - case 10: - Reg = &Regs->R10; - break; - case 11: - Reg = &Regs->R11; - break; - case 12: - Reg = &Regs->R12; - break; - case 13: - Reg = &Regs->R13; - break; - case 14: - Reg = &Regs->R14; - break; - case 15: - Reg = &Regs->R15; - break; - default: - Reg = NULL; - } - - ASSERT (Reg != NULL); - - return Reg; -} - -/** - Update the instruction parsing context for displacement bytes. - - @param[in, out] InstructionData Instruction parsing context - @param[in] Size The instruction displacement size - -**/ -STATIC -VOID -UpdateForDisplacement ( - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData, - IN UINTN Size - ) -{ - InstructionData->DisplacementSize = Size; - InstructionData->Immediate += Size; - InstructionData->End += Size; -} - -/** - Determine if an instruction address if RIP relative. - - Examine the instruction parsing context to determine if the address offset - is relative to the instruction pointer. - - @param[in] InstructionData Instruction parsing context - - @retval TRUE Instruction addressing is RIP relative - @retval FALSE Instruction addressing is not RIP relative - -**/ -STATIC -BOOLEAN -IsRipRelative ( - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - - Ext = &InstructionData->Ext; - - return ((InstructionData->Mode == LongMode64Bit) && - (Ext->ModRm.Mod == 0) && - (Ext->ModRm.Rm == 5) && - (InstructionData->SibPresent == FALSE)); -} - -/** - Return the effective address of a memory operand. - - Examine the instruction parsing context to obtain the effective memory - address of a memory operand. - - @param[in] Regs x64 processor context - @param[in] InstructionData Instruction parsing context - - @return The memory operand effective address - -**/ -STATIC -UINT64 -GetEffectiveMemoryAddress ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - UINT64 EffectiveAddress; - - Ext = &InstructionData->Ext; - EffectiveAddress = 0; - - if (IsRipRelative (InstructionData)) { - // - // RIP-relative displacement is a 32-bit signed value - // - INT32 RipRelative; - - RipRelative = *(INT32 *)InstructionData->Displacement; - - UpdateForDisplacement (InstructionData, 4); - - // - // Negative displacement is handled by standard UINT64 wrap-around. - // - return Regs->Rip + (UINT64)RipRelative; - } - - switch (Ext->ModRm.Mod) { - case 1: - UpdateForDisplacement (InstructionData, 1); - EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement)); - break; - case 2: - switch (InstructionData->AddrSize) { - case Size16Bits: - UpdateForDisplacement (InstructionData, 2); - EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement)); - break; - default: - UpdateForDisplacement (InstructionData, 4); - EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement)); - break; - } - - break; - } - - if (InstructionData->SibPresent) { - INT64 Displacement; - - if (Ext->Sib.Index != 4) { - CopyMem ( - &Displacement, - GetRegisterPointer (Regs, Ext->Sib.Index), - sizeof (Displacement) - ); - Displacement *= (INT64)(1 << Ext->Sib.Scale); - - // - // Negative displacement is handled by standard UINT64 wrap-around. - // - EffectiveAddress += (UINT64)Displacement; - } - - if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) { - EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base); - } else { - UpdateForDisplacement (InstructionData, 4); - EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement)); - } - } else { - EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm); - } - - return EffectiveAddress; -} - -/** - Decode a ModRM byte. - - Examine the instruction parsing context to decode a ModRM byte and the SIB - byte, if present. - - @param[in] Regs x64 processor context - @param[in, out] InstructionData Instruction parsing context - -**/ -STATIC -VOID -DecodeModRm ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - INSTRUCTION_REX_PREFIX *RexPrefix; - INSTRUCTION_MODRM *ModRm; - INSTRUCTION_SIB *Sib; - - RexPrefix = &InstructionData->RexPrefix; - Ext = &InstructionData->Ext; - ModRm = &InstructionData->ModRm; - Sib = &InstructionData->Sib; - - InstructionData->ModRmPresent = TRUE; - ModRm->Uint8 = *(InstructionData->End); - - InstructionData->Displacement++; - InstructionData->Immediate++; - InstructionData->End++; - - Ext->ModRm.Mod = ModRm->Bits.Mod; - Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg; - Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm; - - Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg); - - if (Ext->ModRm.Mod == 3) { - Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm); - } else { - if (ModRm->Bits.Rm == 4) { - InstructionData->SibPresent = TRUE; - Sib->Uint8 = *(InstructionData->End); - - InstructionData->Displacement++; - InstructionData->Immediate++; - InstructionData->End++; - - Ext->Sib.Scale = Sib->Bits.Scale; - Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index; - Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base; - } - - Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData); - } -} - -/** - Decode instruction prefixes. - - Parse the instruction data to track the instruction prefixes that have - been used. - - @param[in] Regs x64 processor context - @param[in, out] InstructionData Instruction parsing context - -**/ -STATIC -VOID -DecodePrefixes ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - SEV_ES_INSTRUCTION_MODE Mode; - SEV_ES_INSTRUCTION_SIZE ModeDataSize; - SEV_ES_INSTRUCTION_SIZE ModeAddrSize; - UINT8 *Byte; - - // - // Always in 64-bit mode - // - Mode = LongMode64Bit; - ModeDataSize = Size32Bits; - ModeAddrSize = Size64Bits; - - InstructionData->Mode = Mode; - InstructionData->DataSize = ModeDataSize; - InstructionData->AddrSize = ModeAddrSize; - - InstructionData->Prefixes = InstructionData->Begin; - - Byte = InstructionData->Prefixes; - for ( ; ; Byte++, InstructionData->PrefixSize++) { - // - // Check the 0x40 to 0x4F range using an if statement here since some - // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids - // 16 case statements below. - // - if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) { - InstructionData->RexPrefix.Uint8 = *Byte; - if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) { - InstructionData->DataSize = Size64Bits; - } - - continue; - } - - switch (*Byte) { - case OVERRIDE_SEGMENT_CS: - case OVERRIDE_SEGMENT_DS: - case OVERRIDE_SEGMENT_ES: - case OVERRIDE_SEGMENT_SS: - if (Mode != LongMode64Bit) { - InstructionData->SegmentSpecified = TRUE; - InstructionData->Segment = (*Byte >> 3) & 3; - } - - break; - - case OVERRIDE_SEGMENT_FS: - case OVERRIDE_SEGMENT_GS: - InstructionData->SegmentSpecified = TRUE; - InstructionData->Segment = *Byte & 7; - break; - - case OVERRIDE_OPERAND_SIZE: - if (InstructionData->RexPrefix.Uint8 == 0) { - InstructionData->DataSize = - (Mode == LongMode64Bit) ? Size16Bits : - (Mode == LongModeCompat32Bit) ? Size16Bits : - (Mode == LongModeCompat16Bit) ? Size32Bits : 0; - } - - break; - - case OVERRIDE_ADDRESS_SIZE: - InstructionData->AddrSize = - (Mode == LongMode64Bit) ? Size32Bits : - (Mode == LongModeCompat32Bit) ? Size16Bits : - (Mode == LongModeCompat16Bit) ? Size32Bits : 0; - break; - - case LOCK_PREFIX: - break; - - case REPZ_PREFIX: - InstructionData->RepMode = RepZ; - break; - - case REPNZ_PREFIX: - InstructionData->RepMode = RepNZ; - break; - - default: - InstructionData->OpCodes = Byte; - InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1; - - InstructionData->End = Byte + InstructionData->OpCodeSize; - InstructionData->Displacement = InstructionData->End; - InstructionData->Immediate = InstructionData->End; - return; - } - } -} - -/** - Determine instruction length - - Return the total length of the parsed instruction. - - @param[in] InstructionData Instruction parsing context - - @return Length of parsed instruction - -**/ -STATIC -UINT64 -InstructionLength ( - IN SEV_ES_INSTRUCTION_DATA *InstructionData - ) -{ - return (UINT64)(InstructionData->End - InstructionData->Begin); -} - -/** - Initialize the instruction parsing context. - - Initialize the instruction parsing context, which includes decoding the - instruction prefixes. - - @param[in, out] InstructionData Instruction parsing context - @param[in] Ghcb Pointer to the Guest-Hypervisor Communication - Block - @param[in] Regs x64 processor context - -**/ -STATIC -VOID -InitInstructionData ( - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData, - IN GHCB *Ghcb, - IN EFI_SYSTEM_CONTEXT_X64 *Regs - ) -{ - SetMem (InstructionData, sizeof (*InstructionData), 0); - InstructionData->Ghcb = Ghcb; - InstructionData->Begin = (UINT8 *)Regs->Rip; - InstructionData->End = (UINT8 *)Regs->Rip; - - DecodePrefixes (Regs, InstructionData); -} - /** Report an unsupported event to the hypervisor @@ -604,9 +71,9 @@ InitInstructionData ( STATIC UINT64 UnsupportedExit ( - IN GHCB *Ghcb, - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN GHCB *Ghcb, + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { UINT64 Status; @@ -703,9 +170,9 @@ ValidateMmioMemory ( STATIC UINT64 MmioExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT CC_INSTRUCTION_DATA *InstructionData ) { UINT64 ExitInfo1, ExitInfo2, Status; @@ -731,7 +198,7 @@ MmioExit ( // fall through // case 0x89: - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Bytes = ((Bytes != 0) ? Bytes : (InstructionData->DataSize == Size16Bits) ? 2 : (InstructionData->DataSize == Size32Bits) ? 4 : @@ -824,7 +291,7 @@ MmioExit ( // fall through // case 0xC7: - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Bytes = ((Bytes != 0) ? Bytes : (InstructionData->DataSize == Size16Bits) ? 2 : (InstructionData->DataSize == Size32Bits) ? 4 : @@ -860,7 +327,7 @@ MmioExit ( // fall through // case 0x8B: - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Bytes = ((Bytes != 0) ? Bytes : (InstructionData->DataSize == Size16Bits) ? 2 : (InstructionData->DataSize == Size32Bits) ? 4 : @@ -888,7 +355,7 @@ MmioExit ( return Status; } - Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); + Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); if (Bytes == 4) { // // Zero-extend for 32-bit operation @@ -967,7 +434,7 @@ MmioExit ( // fall through // case 0xB7: - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Bytes = (Bytes != 0) ? Bytes : 2; Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); @@ -985,7 +452,7 @@ MmioExit ( return Status; } - Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); + Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0); CopyMem (Register, Ghcb->SharedBuffer, Bytes); break; @@ -999,7 +466,7 @@ MmioExit ( // fall through // case 0xBF: - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Bytes = (Bytes != 0) ? Bytes : 2; Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes); @@ -1029,7 +496,7 @@ MmioExit ( SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00; } - Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); + Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg); SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte); CopyMem (Register, Ghcb->SharedBuffer, Bytes); break; @@ -1060,12 +527,12 @@ MmioExit ( STATIC UINT64 MwaitExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Ghcb->SaveArea.Rax = Regs->Rax; CcExitVmgSetOffsetValid (Ghcb, GhcbRax); @@ -1092,12 +559,12 @@ MwaitExit ( STATIC UINT64 MonitorExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA CcExitVmgSetOffsetValid (Ghcb, GhcbRax); @@ -1126,9 +593,9 @@ MonitorExit ( STATIC UINT64 WbinvdExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { return CcExitVmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0); @@ -1151,14 +618,14 @@ WbinvdExit ( STATIC UINT64 RdtscpExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { UINT64 Status; - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0); if (Status != 0) { @@ -1196,14 +663,14 @@ RdtscpExit ( STATIC UINT64 VmmCallExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { UINT64 Status; - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Ghcb->SaveArea.Rax = Regs->Rax; CcExitVmgSetOffsetValid (Ghcb, GhcbRax); @@ -1241,9 +708,9 @@ VmmCallExit ( STATIC UINT64 MsrExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { UINT64 ExitInfo1, Status; @@ -1302,8 +769,8 @@ MsrExit ( STATIC UINT64 IoioExitInfo ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT CC_INSTRUCTION_DATA *InstructionData ) { UINT64 ExitInfo; @@ -1437,9 +904,9 @@ IoioExitInfo ( STATIC UINT64 IoioExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { UINT64 ExitInfo1, ExitInfo2, Status; @@ -1531,9 +998,9 @@ IoioExit ( STATIC UINT64 InvdExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { return CcExitVmgExit (Ghcb, SVM_EXIT_INVD, 0, 0); @@ -1949,9 +1416,9 @@ Out: STATIC UINT64 CpuidExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { BOOLEAN Unsupported; @@ -2041,9 +1508,9 @@ CpuidFail: STATIC UINT64 RdpmcExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { UINT64 Status; @@ -2085,9 +1552,9 @@ RdpmcExit ( STATIC UINT64 RdtscExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { UINT64 Status; @@ -2126,25 +1593,25 @@ RdtscExit ( STATIC UINT64 Dr7WriteExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - SEV_ES_PER_CPU_DATA *SevEsData; - UINT64 *Register; - UINT64 Status; + CC_INSTRUCTION_OPCODE_EXT *Ext; + SEV_ES_PER_CPU_DATA *SevEsData; + UINT64 *Register; + UINT64 Status; Ext = &InstructionData->Ext; SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1); - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); // // MOV DRn always treats MOD == 3 no matter how encoded // - Register = GetRegisterPointer (Regs, Ext->ModRm.Rm); + Register = CcGetRegisterPointer (Regs, Ext->ModRm.Rm); // // Using a value of 0 for ExitInfo1 means RAX holds the value @@ -2179,24 +1646,24 @@ Dr7WriteExit ( STATIC UINT64 Dr7ReadExit ( - IN OUT GHCB *Ghcb, - IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, - IN SEV_ES_INSTRUCTION_DATA *InstructionData + IN OUT GHCB *Ghcb, + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData ) { - SEV_ES_INSTRUCTION_OPCODE_EXT *Ext; - SEV_ES_PER_CPU_DATA *SevEsData; - UINT64 *Register; + CC_INSTRUCTION_OPCODE_EXT *Ext; + SEV_ES_PER_CPU_DATA *SevEsData; + UINT64 *Register; Ext = &InstructionData->Ext; SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1); - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); // // MOV DRn always treats MOD == 3 no matter how encoded // - Register = GetRegisterPointer (Regs, Ext->ModRm.Rm); + Register = CcGetRegisterPointer (Regs, Ext->ModRm.Rm); // // If there is a cached valued for DR7, return that. Otherwise return the @@ -2232,12 +1699,12 @@ InternalVmgExitHandleVc ( IN OUT EFI_SYSTEM_CONTEXT SystemContext ) { - EFI_SYSTEM_CONTEXT_X64 *Regs; - NAE_EXIT NaeExit; - SEV_ES_INSTRUCTION_DATA InstructionData; - UINT64 ExitCode, Status; - EFI_STATUS VcRet; - BOOLEAN InterruptState; + EFI_SYSTEM_CONTEXT_X64 *Regs; + NAE_EXIT NaeExit; + CC_INSTRUCTION_DATA InstructionData; + UINT64 ExitCode, Status; + EFI_STATUS VcRet; + BOOLEAN InterruptState; VcRet = EFI_SUCCESS; @@ -2307,11 +1774,11 @@ InternalVmgExitHandleVc ( NaeExit = UnsupportedExit; } - InitInstructionData (&InstructionData, Ghcb, Regs); + CcInitInstructionData (&InstructionData, Ghcb, Regs); Status = NaeExit (Ghcb, Regs, &InstructionData); if (Status == 0) { - Regs->Rip += InstructionLength (&InstructionData); + Regs->Rip += CcInstructionLength (&InstructionData); } else { GHCB_EVENT_INJECTION Event; diff --git a/OvmfPkg/Library/CcExitLib/CcInstruction.c b/OvmfPkg/Library/CcExitLib/CcInstruction.c new file mode 100644 index 000000000000..0fb54b3ed553 --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/CcInstruction.c @@ -0,0 +1,454 @@ +/** @file + X64 Instruction function. + + Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include "CcInstruction.h" + +#define MAX_INSTRUCTION_LENGTH 15 + +/** + Return a pointer to the contents of the specified register. + + Based upon the input register, return a pointer to the registers contents + in the x86 processor context. + + @param[in] Regs x64 processor context + @param[in] Register Register to obtain pointer for + + @return Pointer to the contents of the requested register + +**/ +UINT64 * +CcGetRegisterPointer ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN UINT8 Register + ) +{ + UINT64 *Reg; + + switch (Register) { + case 0: + Reg = &Regs->Rax; + break; + case 1: + Reg = &Regs->Rcx; + break; + case 2: + Reg = &Regs->Rdx; + break; + case 3: + Reg = &Regs->Rbx; + break; + case 4: + Reg = &Regs->Rsp; + break; + case 5: + Reg = &Regs->Rbp; + break; + case 6: + Reg = &Regs->Rsi; + break; + case 7: + Reg = &Regs->Rdi; + break; + case 8: + Reg = &Regs->R8; + break; + case 9: + Reg = &Regs->R9; + break; + case 10: + Reg = &Regs->R10; + break; + case 11: + Reg = &Regs->R11; + break; + case 12: + Reg = &Regs->R12; + break; + case 13: + Reg = &Regs->R13; + break; + case 14: + Reg = &Regs->R14; + break; + case 15: + Reg = &Regs->R15; + break; + default: + Reg = NULL; + } + + ASSERT (Reg != NULL); + + return Reg; +} + +/** + Update the instruction parsing context for displacement bytes. + + @param[in, out] InstructionData Instruction parsing context + @param[in] Size The instruction displacement size + +**/ +STATIC +VOID +UpdateForDisplacement ( + IN OUT CC_INSTRUCTION_DATA *InstructionData, + IN UINTN Size + ) +{ + InstructionData->DisplacementSize = Size; + InstructionData->Immediate += Size; + InstructionData->End += Size; +} + +/** + Determine if an instruction address if RIP relative. + + Examine the instruction parsing context to determine if the address offset + is relative to the instruction pointer. + + @param[in] InstructionData Instruction parsing context + + @retval TRUE Instruction addressing is RIP relative + @retval FALSE Instruction addressing is not RIP relative + +**/ +STATIC +BOOLEAN +IsRipRelative ( + IN CC_INSTRUCTION_DATA *InstructionData + ) +{ + CC_INSTRUCTION_OPCODE_EXT *Ext; + + Ext = &InstructionData->Ext; + + return ((InstructionData->Mode == LongMode64Bit) && + (Ext->ModRm.Mod == 0) && + (Ext->ModRm.Rm == 5) && + (InstructionData->SibPresent == FALSE)); +} + +/** + Return the effective address of a memory operand. + + Examine the instruction parsing context to obtain the effective memory + address of a memory operand. + + @param[in] Regs x64 processor context + @param[in] InstructionData Instruction parsing context + + @return The memory operand effective address + +**/ +STATIC +UINT64 +GetEffectiveMemoryAddress ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN CC_INSTRUCTION_DATA *InstructionData + ) +{ + CC_INSTRUCTION_OPCODE_EXT *Ext; + UINT64 EffectiveAddress; + + Ext = &InstructionData->Ext; + EffectiveAddress = 0; + + if (IsRipRelative (InstructionData)) { + // + // RIP-relative displacement is a 32-bit signed value + // + INT32 RipRelative; + + RipRelative = *(INT32 *)InstructionData->Displacement; + + UpdateForDisplacement (InstructionData, 4); + + // + // Negative displacement is handled by standard UINT64 wrap-around. + // + return Regs->Rip + (UINT64)RipRelative; + } + + switch (Ext->ModRm.Mod) { + case 1: + UpdateForDisplacement (InstructionData, 1); + EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement)); + break; + case 2: + switch (InstructionData->AddrSize) { + case Size16Bits: + UpdateForDisplacement (InstructionData, 2); + EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement)); + break; + default: + UpdateForDisplacement (InstructionData, 4); + EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement)); + break; + } + + break; + } + + if (InstructionData->SibPresent) { + INT64 Displacement; + + if (Ext->Sib.Index != 4) { + CopyMem ( + &Displacement, + CcGetRegisterPointer (Regs, Ext->Sib.Index), + sizeof (Displacement) + ); + Displacement *= (INT64)(1 << Ext->Sib.Scale); + + // + // Negative displacement is handled by standard UINT64 wrap-around. + // + EffectiveAddress += (UINT64)Displacement; + } + + if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) { + EffectiveAddress += *CcGetRegisterPointer (Regs, Ext->Sib.Base); + } else { + UpdateForDisplacement (InstructionData, 4); + EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement)); + } + } else { + EffectiveAddress += *CcGetRegisterPointer (Regs, Ext->ModRm.Rm); + } + + return EffectiveAddress; +} + +/** + Decode a ModRM byte. + + Examine the instruction parsing context to decode a ModRM byte and the SIB + byte, if present. + + @param[in] Regs x64 processor context + @param[in, out] InstructionData Instruction parsing context + +**/ +VOID +CcDecodeModRm ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT CC_INSTRUCTION_DATA *InstructionData + ) +{ + CC_INSTRUCTION_OPCODE_EXT *Ext; + INSTRUCTION_REX_PREFIX *RexPrefix; + INSTRUCTION_MODRM *ModRm; + INSTRUCTION_SIB *Sib; + + RexPrefix = &InstructionData->RexPrefix; + Ext = &InstructionData->Ext; + ModRm = &InstructionData->ModRm; + Sib = &InstructionData->Sib; + + InstructionData->ModRmPresent = TRUE; + ModRm->Uint8 = *(InstructionData->End); + + InstructionData->Displacement++; + InstructionData->Immediate++; + InstructionData->End++; + + Ext->ModRm.Mod = ModRm->Bits.Mod; + Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg; + Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm; + + Ext->RegData = *CcGetRegisterPointer (Regs, Ext->ModRm.Reg); + + if (Ext->ModRm.Mod == 3) { + Ext->RmData = *CcGetRegisterPointer (Regs, Ext->ModRm.Rm); + } else { + if (ModRm->Bits.Rm == 4) { + InstructionData->SibPresent = TRUE; + Sib->Uint8 = *(InstructionData->End); + + InstructionData->Displacement++; + InstructionData->Immediate++; + InstructionData->End++; + + Ext->Sib.Scale = Sib->Bits.Scale; + Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index; + Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base; + } + + Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData); + } +} + +/** + Decode instruction prefixes. + + Parse the instruction data to track the instruction prefixes that have + been used. + + @param[in] Regs x64 processor context + @param[in, out] InstructionData Instruction parsing context + + @retval EFI_SUCCESS Successfully decode Prefixes + @retval Others Other error as indicated +**/ +STATIC +EFI_STATUS +DecodePrefixes ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT CC_INSTRUCTION_DATA *InstructionData + ) +{ + CC_INSTRUCTION_MODE Mode; + CC_INSTRUCTION_SIZE ModeDataSize; + CC_INSTRUCTION_SIZE ModeAddrSize; + UINT8 *Byte; + UINT8 ParsedLength; + + ParsedLength = 0; + + // + // Always in 64-bit mode + // + Mode = LongMode64Bit; + ModeDataSize = Size32Bits; + ModeAddrSize = Size64Bits; + + InstructionData->Mode = Mode; + InstructionData->DataSize = ModeDataSize; + InstructionData->AddrSize = ModeAddrSize; + + InstructionData->Prefixes = InstructionData->Begin; + + Byte = InstructionData->Prefixes; + for ( ; ParsedLength <= MAX_INSTRUCTION_LENGTH; Byte++, InstructionData->PrefixSize++, ParsedLength++) { + // + // Check the 0x40 to 0x4F range using an if statement here since some + // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids + // 16 case statements below. + // + if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) { + InstructionData->RexPrefix.Uint8 = *Byte; + if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) { + InstructionData->DataSize = Size64Bits; + } + + continue; + } + + switch (*Byte) { + case OVERRIDE_SEGMENT_CS: + case OVERRIDE_SEGMENT_DS: + case OVERRIDE_SEGMENT_ES: + case OVERRIDE_SEGMENT_SS: + if (Mode != LongMode64Bit) { + InstructionData->SegmentSpecified = TRUE; + InstructionData->Segment = (*Byte >> 3) & 3; + } + + break; + + case OVERRIDE_SEGMENT_FS: + case OVERRIDE_SEGMENT_GS: + InstructionData->SegmentSpecified = TRUE; + InstructionData->Segment = *Byte & 7; + break; + + case OVERRIDE_OPERAND_SIZE: + if (InstructionData->RexPrefix.Uint8 == 0) { + InstructionData->DataSize = + (Mode == LongMode64Bit) ? Size16Bits : + (Mode == LongModeCompat32Bit) ? Size16Bits : + (Mode == LongModeCompat16Bit) ? Size32Bits : 0; + } + + break; + + case OVERRIDE_ADDRESS_SIZE: + InstructionData->AddrSize = + (Mode == LongMode64Bit) ? Size32Bits : + (Mode == LongModeCompat32Bit) ? Size16Bits : + (Mode == LongModeCompat16Bit) ? Size32Bits : 0; + break; + + case LOCK_PREFIX: + break; + + case REPZ_PREFIX: + InstructionData->RepMode = RepZ; + break; + + case REPNZ_PREFIX: + InstructionData->RepMode = RepNZ; + break; + + default: + InstructionData->OpCodes = Byte; + InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1; + + InstructionData->End = Byte + InstructionData->OpCodeSize; + InstructionData->Displacement = InstructionData->End; + InstructionData->Immediate = InstructionData->End; + return EFI_SUCCESS; + } + } + + return EFI_ABORTED; +} + +/** + Determine instruction length + + Return the total length of the parsed instruction. + + @param[in] InstructionData Instruction parsing context + + @return Length of parsed instruction + +**/ +UINT64 +CcInstructionLength ( + IN CC_INSTRUCTION_DATA *InstructionData + ) +{ + return (UINT64)(InstructionData->End - InstructionData->Begin); +} + +/** + Initialize the instruction parsing context. + + Initialize the instruction parsing context, which includes decoding the + instruction prefixes. + + @param[in, out] InstructionData Instruction parsing context + @param[in] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in] Regs x64 processor context + + @retval EFI_SUCCESS Successfully initialize InstructionData + @retval Others Other error as indicated +**/ +EFI_STATUS +CcInitInstructionData ( + IN OUT CC_INSTRUCTION_DATA *InstructionData, + IN GHCB *Ghcb, + IN EFI_SYSTEM_CONTEXT_X64 *Regs + ) +{ + SetMem (InstructionData, sizeof (*InstructionData), 0); + InstructionData->Ghcb = Ghcb; + InstructionData->Begin = (UINT8 *)Regs->Rip; + InstructionData->End = (UINT8 *)Regs->Rip; + + return DecodePrefixes (Regs, InstructionData); +} diff --git a/OvmfPkg/Library/CcExitLib/CcInstruction.h b/OvmfPkg/Library/CcExitLib/CcInstruction.h new file mode 100644 index 000000000000..a8223a6a7d6d --- /dev/null +++ b/OvmfPkg/Library/CcExitLib/CcInstruction.h @@ -0,0 +1,197 @@ +/** @file + Confidential Computing X64 Instruction + + Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.
+ Copyright (c) 2022, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef CC_INSTRUCTION_H_ +#define CC_INSTRUCTION_H_ + +#include +#include +#include +#include +#include + +// +// Instruction execution mode definition +// +typedef enum { + LongMode64Bit = 0, + LongModeCompat32Bit, + LongModeCompat16Bit, +} CC_INSTRUCTION_MODE; + +// +// Instruction size definition (for operand and address) +// +typedef enum { + Size8Bits = 0, + Size16Bits, + Size32Bits, + Size64Bits, +} CC_INSTRUCTION_SIZE; + +// +// Intruction segment definition +// +typedef enum { + SegmentEs = 0, + SegmentCs, + SegmentSs, + SegmentDs, + SegmentFs, + SegmentGs, +} CC_INSTRUCTION_SEGMENT; + +// +// Instruction rep function definition +// +typedef enum { + RepNone = 0, + RepZ, + RepNZ, +} CC_INSTRUCTION_REP; + +typedef struct { + UINT8 Rm; + UINT8 Reg; + UINT8 Mod; +} CC_INSTRUCTION_MODRM_EXT; + +typedef struct { + UINT8 Base; + UINT8 Index; + UINT8 Scale; +} CC_INSTRUCTION_SIB_EXT; + +// +// Instruction opcode definition +// +typedef struct { + CC_INSTRUCTION_MODRM_EXT ModRm; + + CC_INSTRUCTION_SIB_EXT Sib; + + UINTN RegData; + UINTN RmData; +} CC_INSTRUCTION_OPCODE_EXT; + +// +// Instruction parsing context definition +// +typedef struct { + GHCB *Ghcb; + + CC_INSTRUCTION_MODE Mode; + CC_INSTRUCTION_SIZE DataSize; + CC_INSTRUCTION_SIZE AddrSize; + BOOLEAN SegmentSpecified; + CC_INSTRUCTION_SEGMENT Segment; + CC_INSTRUCTION_REP RepMode; + + UINT8 *Begin; + UINT8 *End; + + UINT8 *Prefixes; + UINT8 *OpCodes; + UINT8 *Displacement; + UINT8 *Immediate; + + INSTRUCTION_REX_PREFIX RexPrefix; + + BOOLEAN ModRmPresent; + INSTRUCTION_MODRM ModRm; + + BOOLEAN SibPresent; + INSTRUCTION_SIB Sib; + + UINTN PrefixSize; + UINTN OpCodeSize; + UINTN DisplacementSize; + UINTN ImmediateSize; + + CC_INSTRUCTION_OPCODE_EXT Ext; +} CC_INSTRUCTION_DATA; + +EFI_STATUS +CcInitInstructionData ( + IN OUT CC_INSTRUCTION_DATA *InstructionData, + IN GHCB *Ghcb, + IN EFI_SYSTEM_CONTEXT_X64 *Regs + ); + +/** + Return a pointer to the contents of the specified register. + + Based upon the input register, return a pointer to the registers contents + in the x86 processor context. + + @param[in] Regs x64 processor context + @param[in] Register Register to obtain pointer for + + @return Pointer to the contents of the requested register + +**/ +UINT64 * +CcGetRegisterPointer ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN UINT8 Register + ); + +/** + Decode a ModRM byte. + + Examine the instruction parsing context to decode a ModRM byte and the SIB + byte, if present. + + @param[in] Regs x64 processor context + @param[in, out] InstructionData Instruction parsing context + +**/ +VOID +CcDecodeModRm ( + IN EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT CC_INSTRUCTION_DATA *InstructionData + ); + +/** + Determine instruction length + + Return the total length of the parsed instruction. + + @param[in] InstructionData Instruction parsing context + + @return Length of parsed instruction + +**/ +UINT64 +CcInstructionLength ( + IN CC_INSTRUCTION_DATA *InstructionData + ); + +/** + Initialize the instruction parsing context. + + Initialize the instruction parsing context, which includes decoding the + instruction prefixes. + + @param[in, out] InstructionData Instruction parsing context + @param[in] Ghcb Pointer to the Guest-Hypervisor Communication + Block + @param[in] Regs x64 processor context + + @retval EFI_SUCCESS Successfully initialize InstructionData + @retval Others Other error as indicated +**/ +EFI_STATUS +CcInitInstructionData ( + IN OUT CC_INSTRUCTION_DATA *InstructionData, + IN GHCB *Ghcb, + IN EFI_SYSTEM_CONTEXT_X64 *Regs + ); + +#endif diff --git a/OvmfPkg/Library/CcExitLib/SecCcExitLib.inf b/OvmfPkg/Library/CcExitLib/SecCcExitLib.inf index 1ee22ce0aea1..811269dd2c06 100644 --- a/OvmfPkg/Library/CcExitLib/SecCcExitLib.inf +++ b/OvmfPkg/Library/CcExitLib/SecCcExitLib.inf @@ -24,6 +24,7 @@ CcExitLib.c CcExitVcHandler.c CcExitVcHandler.h + CcInstruction.c SecCcExitVcHandler.c CcExitVeHandler.c X64/TdVmcallCpuid.nasm -- 2.29.2.windows.2