From nobody Tue May 14 12:29:29 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+98650+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+98650+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1673941428; cv=none; d=zohomail.com; s=zohoarc; b=iQFqYqREIyPBrnFNspkhDBnrgz7PwPS+0ps/qDZlSz5XxFpdnp+5AgaBTiFS0AgN1nDRCurypHES5TRoMEV7ZwGV+P4Gq7iraw4NmA+cxbfiZz0wgRQ6GzjxW0yN8B9NYo/aGjtzMrBPL6JYEuQCwwCXOEeiMxTLXfRaeeL0cIw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1673941428; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=8QTtIcRKl2RK5eMRCakS1Jo8f0LcOlzo5nx7gy9NvWM=; b=T5DJmajriNI+lQEVJWr32tcYHn6pzV4exzLrFaG4H3Waywz8eY/n5X1XCUaV1KOYREaGnZfHfOSDsETjvN+P3T3lYZzoOpvgaVU+uEXkYtGXFGWTKmAArVP3CzVVH/Jitdmo+31JRmMufsr4DAC20kaQCSeGK3tfuzD/sZjzoUQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+98650+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1673941428187592.3507547370112; Mon, 16 Jan 2023 23:43:48 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id SrZ5YY1788612xtTtTFFGS0U; Mon, 16 Jan 2023 23:43:47 -0800 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web11.191473.1673941423940464461 for ; Mon, 16 Jan 2023 23:43:47 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10592"; a="304320674" X-IronPort-AV: E=Sophos;i="5.97,222,1669104000"; d="scan'208";a="304320674" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jan 2023 23:43:45 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10592"; a="636772719" X-IronPort-AV: E=Sophos;i="5.97,222,1669104000"; d="scan'208";a="636772719" X-Received: from mxu9-mobl1.ccr.corp.intel.com ([10.254.211.139]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jan 2023 23:43:42 -0800 From: "Min Xu" To: devel@edk2.groups.io Cc: Min M Xu , Gerd Hoffmann , Erdem Aktas , James Bottomley , Jiewen Yao , Tom Lendacky Subject: [edk2-devel] [PATCH V3 1/2] OvmfPkg/CcExitLib: Move common X86 instruction code to separate file Date: Tue, 17 Jan 2023 15:43:29 +0800 Message-Id: <20230117074330.1058-2-min.m.xu@intel.com> In-Reply-To: <20230117074330.1058-1-min.m.xu@intel.com> References: <20230117074330.1058-1-min.m.xu@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,min.m.xu@intel.com X-Gm-Message-State: ke4GZ0LPecD0uRSzADmPt4OWx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1673941427; bh=5aY5UwURDkgsvGwV9mdjGrnv3DTNCIaeGXM9t2hCJqY=; h=Cc:Date:From:Reply-To:Subject:To; b=JFlII37EubHNo4yV14zK3+1REOp10iKAiP6WLsABYOiaUhZqeo30yIsKlaBdnsQYd1n mhD/2ACdojffrcWrN7cTlouEyGGro8b0wljjIk5/fbQRg1pIov7UKk97i4eMh2R1Q3eMA XsITMNU5M7VUil+mD084pz91WGRcAPNUpGw= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1673941429278100001 Content-Type: text/plain; charset="utf-8" From: Min M Xu https://bugzilla.tianocore.org/show_bug.cgi?id=3D4169 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 Acked-by: Gerd Hoffmann Reported-by: Ryan Afranji Reviewed-by: Jiewen Yao --- 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/CcEx= itLib/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 =20 #include "CcExitVcHandler.h" - -// -// Instruction execution mode definition -// -typedef enum { - LongMode64Bit =3D 0, - LongModeCompat32Bit, - LongModeCompat16Bit, -} SEV_ES_INSTRUCTION_MODE; - -// -// Instruction size definition (for operand and address) -// -typedef enum { - Size8Bits =3D 0, - Size16Bits, - Size32Bits, - Size64Bits, -} SEV_ES_INSTRUCTION_SIZE; - -// -// Intruction segment definition -// -typedef enum { - SegmentEs =3D 0, - SegmentCs, - SegmentSs, - SegmentDs, - SegmentFs, - SegmentGs, -} SEV_ES_INSTRUCTION_SEGMENT; - -// -// Instruction rep function definition -// -typedef enum { - RepNone =3D 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" =20 // // 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 ); =20 // @@ -155,439 +55,6 @@ typedef PACKED struct { SEV_SNP_CPUID_FUNCTION function[0]; } SEV_SNP_CPUID_INFO; =20 -/** - 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 =3D &Regs->Rax; - break; - case 1: - Reg =3D &Regs->Rcx; - break; - case 2: - Reg =3D &Regs->Rdx; - break; - case 3: - Reg =3D &Regs->Rbx; - break; - case 4: - Reg =3D &Regs->Rsp; - break; - case 5: - Reg =3D &Regs->Rbp; - break; - case 6: - Reg =3D &Regs->Rsi; - break; - case 7: - Reg =3D &Regs->Rdi; - break; - case 8: - Reg =3D &Regs->R8; - break; - case 9: - Reg =3D &Regs->R9; - break; - case 10: - Reg =3D &Regs->R10; - break; - case 11: - Reg =3D &Regs->R11; - break; - case 12: - Reg =3D &Regs->R12; - break; - case 13: - Reg =3D &Regs->R13; - break; - case 14: - Reg =3D &Regs->R14; - break; - case 15: - Reg =3D &Regs->R15; - break; - default: - Reg =3D NULL; - } - - ASSERT (Reg !=3D 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 =3D Size; - InstructionData->Immediate +=3D Size; - InstructionData->End +=3D Size; -} - -/** - Determine if an instruction address if RIP relative. - - Examine the instruction parsing context to determine if the address offs= et - 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 =3D &InstructionData->Ext; - - return ((InstructionData->Mode =3D=3D LongMode64Bit) && - (Ext->ModRm.Mod =3D=3D 0) && - (Ext->ModRm.Rm =3D=3D 5) && - (InstructionData->SibPresent =3D=3D 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 =3D &InstructionData->Ext; - EffectiveAddress =3D 0; - - if (IsRipRelative (InstructionData)) { - // - // RIP-relative displacement is a 32-bit signed value - // - INT32 RipRelative; - - RipRelative =3D *(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 +=3D (UINT64)(*(INT8 *)(InstructionData->Displaceme= nt)); - break; - case 2: - switch (InstructionData->AddrSize) { - case Size16Bits: - UpdateForDisplacement (InstructionData, 2); - EffectiveAddress +=3D (UINT64)(*(INT16 *)(InstructionData->Displ= acement)); - break; - default: - UpdateForDisplacement (InstructionData, 4); - EffectiveAddress +=3D (UINT64)(*(INT32 *)(InstructionData->Displ= acement)); - break; - } - - break; - } - - if (InstructionData->SibPresent) { - INT64 Displacement; - - if (Ext->Sib.Index !=3D 4) { - CopyMem ( - &Displacement, - GetRegisterPointer (Regs, Ext->Sib.Index), - sizeof (Displacement) - ); - Displacement *=3D (INT64)(1 << Ext->Sib.Scale); - - // - // Negative displacement is handled by standard UINT64 wrap-around. - // - EffectiveAddress +=3D (UINT64)Displacement; - } - - if ((Ext->Sib.Base !=3D 5) || Ext->ModRm.Mod) { - EffectiveAddress +=3D *GetRegisterPointer (Regs, Ext->Sib.Base); - } else { - UpdateForDisplacement (InstructionData, 4); - EffectiveAddress +=3D (UINT64)(*(INT32 *)(InstructionData->Displacem= ent)); - } - } else { - EffectiveAddress +=3D *GetRegisterPointer (Regs, Ext->ModRm.Rm); - } - - return EffectiveAddress; -} - -/** - Decode a ModRM byte. - - Examine the instruction parsing context to decode a ModRM byte and the S= IB - 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 =3D &InstructionData->RexPrefix; - Ext =3D &InstructionData->Ext; - ModRm =3D &InstructionData->ModRm; - Sib =3D &InstructionData->Sib; - - InstructionData->ModRmPresent =3D TRUE; - ModRm->Uint8 =3D *(InstructionData->End); - - InstructionData->Displacement++; - InstructionData->Immediate++; - InstructionData->End++; - - Ext->ModRm.Mod =3D ModRm->Bits.Mod; - Ext->ModRm.Reg =3D (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg; - Ext->ModRm.Rm =3D (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm; - - Ext->RegData =3D *GetRegisterPointer (Regs, Ext->ModRm.Reg); - - if (Ext->ModRm.Mod =3D=3D 3) { - Ext->RmData =3D *GetRegisterPointer (Regs, Ext->ModRm.Rm); - } else { - if (ModRm->Bits.Rm =3D=3D 4) { - InstructionData->SibPresent =3D TRUE; - Sib->Uint8 =3D *(InstructionData->End); - - InstructionData->Displacement++; - InstructionData->Immediate++; - InstructionData->End++; - - Ext->Sib.Scale =3D Sib->Bits.Scale; - Ext->Sib.Index =3D (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index; - Ext->Sib.Base =3D (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base; - } - - Ext->RmData =3D 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 =3D LongMode64Bit; - ModeDataSize =3D Size32Bits; - ModeAddrSize =3D Size64Bits; - - InstructionData->Mode =3D Mode; - InstructionData->DataSize =3D ModeDataSize; - InstructionData->AddrSize =3D ModeAddrSize; - - InstructionData->Prefixes =3D InstructionData->Begin; - - Byte =3D 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 >=3D REX_PREFIX_START) && (*Byte <=3D REX_PREFIX_STOP)) { - InstructionData->RexPrefix.Uint8 =3D *Byte; - if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) !=3D 0) { - InstructionData->DataSize =3D Size64Bits; - } - - continue; - } - - switch (*Byte) { - case OVERRIDE_SEGMENT_CS: - case OVERRIDE_SEGMENT_DS: - case OVERRIDE_SEGMENT_ES: - case OVERRIDE_SEGMENT_SS: - if (Mode !=3D LongMode64Bit) { - InstructionData->SegmentSpecified =3D TRUE; - InstructionData->Segment =3D (*Byte >> 3) & 3; - } - - break; - - case OVERRIDE_SEGMENT_FS: - case OVERRIDE_SEGMENT_GS: - InstructionData->SegmentSpecified =3D TRUE; - InstructionData->Segment =3D *Byte & 7; - break; - - case OVERRIDE_OPERAND_SIZE: - if (InstructionData->RexPrefix.Uint8 =3D=3D 0) { - InstructionData->DataSize =3D - (Mode =3D=3D LongMode64Bit) ? Size16Bits : - (Mode =3D=3D LongModeCompat32Bit) ? Size16Bits : - (Mode =3D=3D LongModeCompat16Bit) ? Size32Bits : 0; - } - - break; - - case OVERRIDE_ADDRESS_SIZE: - InstructionData->AddrSize =3D - (Mode =3D=3D LongMode64Bit) ? Size32Bits : - (Mode =3D=3D LongModeCompat32Bit) ? Size16Bits : - (Mode =3D=3D LongModeCompat16Bit) ? Size32Bits : 0; - break; - - case LOCK_PREFIX: - break; - - case REPZ_PREFIX: - InstructionData->RepMode =3D RepZ; - break; - - case REPNZ_PREFIX: - InstructionData->RepMode =3D RepNZ; - break; - - default: - InstructionData->OpCodes =3D Byte; - InstructionData->OpCodeSize =3D (*Byte =3D=3D TWO_BYTE_OPCODE_ESCA= PE) ? 2 : 1; - - InstructionData->End =3D Byte + InstructionData->OpCodeSi= ze; - InstructionData->Displacement =3D InstructionData->End; - InstructionData->Immediate =3D 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 Communi= cation - 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 =3D Ghcb; - InstructionData->Begin =3D (UINT8 *)Regs->Rip; - InstructionData->End =3D (UINT8 *)Regs->Rip; - - DecodePrefixes (Regs, InstructionData); -} - /** Report an unsupported event to the hypervisor =20 @@ -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 =3D ((Bytes !=3D 0) ? Bytes : (InstructionData->DataSize =3D=3D Size16Bits) ? 2 : (InstructionData->DataSize =3D=3D Size32Bits) ? 4 : @@ -824,7 +291,7 @@ MmioExit ( // fall through // case 0xC7: - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Bytes =3D ((Bytes !=3D 0) ? Bytes : (InstructionData->DataSize =3D=3D Size16Bits) ? 2 : (InstructionData->DataSize =3D=3D Size32Bits) ? 4 : @@ -860,7 +327,7 @@ MmioExit ( // fall through // case 0x8B: - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Bytes =3D ((Bytes !=3D 0) ? Bytes : (InstructionData->DataSize =3D=3D Size16Bits) ? 2 : (InstructionData->DataSize =3D=3D Size32Bits) ? 4 : @@ -888,7 +355,7 @@ MmioExit ( return Status; } =20 - Register =3D GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Re= g); + Register =3D CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.= Reg); if (Bytes =3D=3D 4) { // // Zero-extend for 32-bit operation @@ -967,7 +434,7 @@ MmioExit ( // fall through // case 0xB7: - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); Bytes =3D (Bytes !=3D 0) ? Bytes : 2; =20 Status =3D ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, By= tes); @@ -985,7 +452,7 @@ MmioExit ( return Status; } =20 - Register =3D GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Re= g); + Register =3D 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 =3D (Bytes !=3D 0) ? Bytes : 2; =20 Status =3D ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, By= tes); @@ -1029,7 +496,7 @@ MmioExit ( SignByte =3D ((*Data & BIT15) !=3D 0) ? 0xFF : 0x00; } =20 - Register =3D GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Re= g); + Register =3D 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); =20 Ghcb->SaveArea.Rax =3D 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); =20 Ghcb->SaveArea.Rax =3D Regs->Rax; // Identity mapped, so VA =3D 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; =20 - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); =20 Status =3D CcExitVmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0); if (Status !=3D 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; =20 - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); =20 Ghcb->SaveArea.Rax =3D 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; =20 Ext =3D &InstructionData->Ext; SevEsData =3D (SEV_ES_PER_CPU_DATA *)(Ghcb + 1); =20 - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); =20 // // MOV DRn always treats MOD =3D=3D 3 no matter how encoded // - Register =3D GetRegisterPointer (Regs, Ext->ModRm.Rm); + Register =3D CcGetRegisterPointer (Regs, Ext->ModRm.Rm); =20 // // 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; =20 Ext =3D &InstructionData->Ext; SevEsData =3D (SEV_ES_PER_CPU_DATA *)(Ghcb + 1); =20 - DecodeModRm (Regs, InstructionData); + CcDecodeModRm (Regs, InstructionData); =20 // // MOV DRn always treats MOD =3D=3D 3 no matter how encoded // - Register =3D GetRegisterPointer (Regs, Ext->ModRm.Rm); + Register =3D CcGetRegisterPointer (Regs, Ext->ModRm.Rm); =20 // // 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; =20 VcRet =3D EFI_SUCCESS; =20 @@ -2307,11 +1774,11 @@ InternalVmgExitHandleVc ( NaeExit =3D UnsupportedExit; } =20 - InitInstructionData (&InstructionData, Ghcb, Regs); + CcInitInstructionData (&InstructionData, Ghcb, Regs); =20 Status =3D NaeExit (Ghcb, Regs, &InstructionData); if (Status =3D=3D 0) { - Regs->Rip +=3D InstructionLength (&InstructionData); + Regs->Rip +=3D CcInstructionLength (&InstructionData); } else { GHCB_EVENT_INJECTION Event; =20 diff --git a/OvmfPkg/Library/CcExitLib/CcInstruction.c b/OvmfPkg/Library/Cc= ExitLib/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 =3D &Regs->Rax; + break; + case 1: + Reg =3D &Regs->Rcx; + break; + case 2: + Reg =3D &Regs->Rdx; + break; + case 3: + Reg =3D &Regs->Rbx; + break; + case 4: + Reg =3D &Regs->Rsp; + break; + case 5: + Reg =3D &Regs->Rbp; + break; + case 6: + Reg =3D &Regs->Rsi; + break; + case 7: + Reg =3D &Regs->Rdi; + break; + case 8: + Reg =3D &Regs->R8; + break; + case 9: + Reg =3D &Regs->R9; + break; + case 10: + Reg =3D &Regs->R10; + break; + case 11: + Reg =3D &Regs->R11; + break; + case 12: + Reg =3D &Regs->R12; + break; + case 13: + Reg =3D &Regs->R13; + break; + case 14: + Reg =3D &Regs->R14; + break; + case 15: + Reg =3D &Regs->R15; + break; + default: + Reg =3D NULL; + } + + ASSERT (Reg !=3D 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 =3D Size; + InstructionData->Immediate +=3D Size; + InstructionData->End +=3D Size; +} + +/** + Determine if an instruction address if RIP relative. + + Examine the instruction parsing context to determine if the address offs= et + 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 =3D &InstructionData->Ext; + + return ((InstructionData->Mode =3D=3D LongMode64Bit) && + (Ext->ModRm.Mod =3D=3D 0) && + (Ext->ModRm.Rm =3D=3D 5) && + (InstructionData->SibPresent =3D=3D 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 =3D &InstructionData->Ext; + EffectiveAddress =3D 0; + + if (IsRipRelative (InstructionData)) { + // + // RIP-relative displacement is a 32-bit signed value + // + INT32 RipRelative; + + RipRelative =3D *(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 +=3D (UINT64)(*(INT8 *)(InstructionData->Displaceme= nt)); + break; + case 2: + switch (InstructionData->AddrSize) { + case Size16Bits: + UpdateForDisplacement (InstructionData, 2); + EffectiveAddress +=3D (UINT64)(*(INT16 *)(InstructionData->Displ= acement)); + break; + default: + UpdateForDisplacement (InstructionData, 4); + EffectiveAddress +=3D (UINT64)(*(INT32 *)(InstructionData->Displ= acement)); + break; + } + + break; + } + + if (InstructionData->SibPresent) { + INT64 Displacement; + + if (Ext->Sib.Index !=3D 4) { + CopyMem ( + &Displacement, + CcGetRegisterPointer (Regs, Ext->Sib.Index), + sizeof (Displacement) + ); + Displacement *=3D (INT64)(1 << Ext->Sib.Scale); + + // + // Negative displacement is handled by standard UINT64 wrap-around. + // + EffectiveAddress +=3D (UINT64)Displacement; + } + + if ((Ext->Sib.Base !=3D 5) || Ext->ModRm.Mod) { + EffectiveAddress +=3D *CcGetRegisterPointer (Regs, Ext->Sib.Base); + } else { + UpdateForDisplacement (InstructionData, 4); + EffectiveAddress +=3D (UINT64)(*(INT32 *)(InstructionData->Displacem= ent)); + } + } else { + EffectiveAddress +=3D *CcGetRegisterPointer (Regs, Ext->ModRm.Rm); + } + + return EffectiveAddress; +} + +/** + Decode a ModRM byte. + + Examine the instruction parsing context to decode a ModRM byte and the S= IB + 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 =3D &InstructionData->RexPrefix; + Ext =3D &InstructionData->Ext; + ModRm =3D &InstructionData->ModRm; + Sib =3D &InstructionData->Sib; + + InstructionData->ModRmPresent =3D TRUE; + ModRm->Uint8 =3D *(InstructionData->End); + + InstructionData->Displacement++; + InstructionData->Immediate++; + InstructionData->End++; + + Ext->ModRm.Mod =3D ModRm->Bits.Mod; + Ext->ModRm.Reg =3D (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg; + Ext->ModRm.Rm =3D (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm; + + Ext->RegData =3D *CcGetRegisterPointer (Regs, Ext->ModRm.Reg); + + if (Ext->ModRm.Mod =3D=3D 3) { + Ext->RmData =3D *CcGetRegisterPointer (Regs, Ext->ModRm.Rm); + } else { + if (ModRm->Bits.Rm =3D=3D 4) { + InstructionData->SibPresent =3D TRUE; + Sib->Uint8 =3D *(InstructionData->End); + + InstructionData->Displacement++; + InstructionData->Immediate++; + InstructionData->End++; + + Ext->Sib.Scale =3D Sib->Bits.Scale; + Ext->Sib.Index =3D (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index; + Ext->Sib.Base =3D (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base; + } + + Ext->RmData =3D 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 =3D 0; + + // + // Always in 64-bit mode + // + Mode =3D LongMode64Bit; + ModeDataSize =3D Size32Bits; + ModeAddrSize =3D Size64Bits; + + InstructionData->Mode =3D Mode; + InstructionData->DataSize =3D ModeDataSize; + InstructionData->AddrSize =3D ModeAddrSize; + + InstructionData->Prefixes =3D InstructionData->Begin; + + Byte =3D InstructionData->Prefixes; + for ( ; ParsedLength <=3D MAX_INSTRUCTION_LENGTH; Byte++, InstructionDat= a->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 >=3D REX_PREFIX_START) && (*Byte <=3D REX_PREFIX_STOP)) { + InstructionData->RexPrefix.Uint8 =3D *Byte; + if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) !=3D 0) { + InstructionData->DataSize =3D Size64Bits; + } + + continue; + } + + switch (*Byte) { + case OVERRIDE_SEGMENT_CS: + case OVERRIDE_SEGMENT_DS: + case OVERRIDE_SEGMENT_ES: + case OVERRIDE_SEGMENT_SS: + if (Mode !=3D LongMode64Bit) { + InstructionData->SegmentSpecified =3D TRUE; + InstructionData->Segment =3D (*Byte >> 3) & 3; + } + + break; + + case OVERRIDE_SEGMENT_FS: + case OVERRIDE_SEGMENT_GS: + InstructionData->SegmentSpecified =3D TRUE; + InstructionData->Segment =3D *Byte & 7; + break; + + case OVERRIDE_OPERAND_SIZE: + if (InstructionData->RexPrefix.Uint8 =3D=3D 0) { + InstructionData->DataSize =3D + (Mode =3D=3D LongMode64Bit) ? Size16Bits : + (Mode =3D=3D LongModeCompat32Bit) ? Size16Bits : + (Mode =3D=3D LongModeCompat16Bit) ? Size32Bits : 0; + } + + break; + + case OVERRIDE_ADDRESS_SIZE: + InstructionData->AddrSize =3D + (Mode =3D=3D LongMode64Bit) ? Size32Bits : + (Mode =3D=3D LongModeCompat32Bit) ? Size16Bits : + (Mode =3D=3D LongModeCompat16Bit) ? Size32Bits : 0; + break; + + case LOCK_PREFIX: + break; + + case REPZ_PREFIX: + InstructionData->RepMode =3D RepZ; + break; + + case REPNZ_PREFIX: + InstructionData->RepMode =3D RepNZ; + break; + + default: + InstructionData->OpCodes =3D Byte; + InstructionData->OpCodeSize =3D (*Byte =3D=3D TWO_BYTE_OPCODE_ESCA= PE) ? 2 : 1; + + InstructionData->End =3D Byte + InstructionData->OpCodeSi= ze; + InstructionData->Displacement =3D InstructionData->End; + InstructionData->Immediate =3D 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 Communi= cation + 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 =3D Ghcb; + InstructionData->Begin =3D (UINT8 *)Regs->Rip; + InstructionData->End =3D (UINT8 *)Regs->Rip; + + return DecodePrefixes (Regs, InstructionData); +} diff --git a/OvmfPkg/Library/CcExitLib/CcInstruction.h b/OvmfPkg/Library/Cc= ExitLib/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 =3D 0, + LongModeCompat32Bit, + LongModeCompat16Bit, +} CC_INSTRUCTION_MODE; + +// +// Instruction size definition (for operand and address) +// +typedef enum { + Size8Bits =3D 0, + Size16Bits, + Size32Bits, + Size64Bits, +} CC_INSTRUCTION_SIZE; + +// +// Intruction segment definition +// +typedef enum { + SegmentEs =3D 0, + SegmentCs, + SegmentSs, + SegmentDs, + SegmentFs, + SegmentGs, +} CC_INSTRUCTION_SEGMENT; + +// +// Instruction rep function definition +// +typedef enum { + RepNone =3D 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 S= IB + 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 Communi= cation + 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/C= cExitLib/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 --=20 2.29.2.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#98650): https://edk2.groups.io/g/devel/message/98650 Mute This Topic: https://groups.io/mt/96325924/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Tue May 14 12:29:29 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+98651+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+98651+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1673941429; cv=none; d=zohomail.com; s=zohoarc; b=URkLiyZxxMzgKdMdhCWcKkCrF48Z4lhgaMieu7bh8K4KwGMMEzkr8rzyOtnpnedDljE+i22GzcfSR7pyDCFPIun4ihPORQuY1wCgjDSU4L7FJ0vYssaHmALrsCynJiQRuWtJYB683OTzmzeQu0drPyJZVVxqNrb39nm6C7gFeX0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1673941429; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=jbe4lhoJBvRPtjrNnCQtB/VH2CfLpMFjnrJ09LqyrCI=; b=N0yl2blAuFJ7XSnTrzFbxZuDWwSgnoI9ryBCTagQkCfyvwwB/aT0pqila4PjkNWgNY7yPctzHTx3EgSFeN6Qh3fUGoGd/8rXwW4nW/rz3N7zm9FkQPKv0s9pkCc+gAI+uJUvDHQXHTUwTRlbeA9hPnAG0livtbdxR61XKvD13O8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+98651+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 167394142985730.999521280735053; Mon, 16 Jan 2023 23:43:49 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id OI6CYY1788612xFSCyPNbeAB; Mon, 16 Jan 2023 23:43:49 -0800 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web11.191473.1673941423940464461 for ; Mon, 16 Jan 2023 23:43:49 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10592"; a="304320696" X-IronPort-AV: E=Sophos;i="5.97,222,1669104000"; d="scan'208";a="304320696" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jan 2023 23:43:48 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10592"; a="636772743" X-IronPort-AV: E=Sophos;i="5.97,222,1669104000"; d="scan'208";a="636772743" X-Received: from mxu9-mobl1.ccr.corp.intel.com ([10.254.211.139]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jan 2023 23:43:45 -0800 From: "Min Xu" To: devel@edk2.groups.io Cc: Min M Xu , Erdem Aktas , James Bottomley , Jiewen Yao , Gerd Hoffmann , Tom Lendacky , Ryan Afranji Subject: [edk2-devel] [PATCH V3 2/2] OvmfPkg/CcExitLib: Refactor TDX MmioExit Date: Tue, 17 Jan 2023 15:43:30 +0800 Message-Id: <20230117074330.1058-3-min.m.xu@intel.com> In-Reply-To: <20230117074330.1058-1-min.m.xu@intel.com> References: <20230117074330.1058-1-min.m.xu@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,min.m.xu@intel.com X-Gm-Message-State: DceajVJPffrRsYAk9EsdBA8rx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1673941429; bh=1p7FfeFXWRUDJ4DDT5HplcytVD7m7qhbSupetxNZVOE=; h=Cc:Date:From:Reply-To:Subject:To; b=W+iza3tHLW2j13Wlj62+6+MphwbDo0RlJhiKN+CDbsrmW0JUv+HSHeA47VRNE2zgtm0 QzDDZ8VrjrkJWOcEKzE5EaS0WkA3Lcb34nSqE12OMVb3FtW4oxP6h76wQqNCMcofsRXvw /jUsiKNYAZeEvO2/DCnYvv/PDgwJllt0LL4= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1673941431283100006 Content-Type: text/plain; charset="utf-8" From: Min M Xu BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4169 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 Cc: James Bottomley Cc: Jiewen Yao Cc: Gerd Hoffmann Cc: Tom Lendacky Cc: Ryan Afranji Reported-by: Ryan Afranji Signed-off-by: Min Xu Acked-by: Gerd Hoffmann Reviewed-by: Jiewen Yao --- OvmfPkg/Library/CcExitLib/CcExitVeHandler.c | 546 ++++++++++++++------ 1 file changed, 382 insertions(+), 164 deletions(-) diff --git a/OvmfPkg/Library/CcExitLib/CcExitVeHandler.c b/OvmfPkg/Library/= CcExitLib/CcExitVeHandler.c index 30d547d5fe55..b8979ec2c0c0 100644 --- a/OvmfPkg/Library/CcExitLib/CcExitVeHandler.c +++ b/OvmfPkg/Library/CcExitLib/CcExitVeHandler.c @@ -13,6 +13,10 @@ #include #include #include +#include "CcInstruction.h" + +#define TDX_MMIO_READ 0 +#define TDX_MMIO_WRITE 1 =20 typedef union { struct { @@ -216,14 +220,15 @@ STATIC VOID EFIAPI TdxDecodeInstruction ( - IN UINT8 *Rip + IN UINT8 *Rip, + IN UINT32 Length ) { UINTN i; =20 DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip)); - for (i =3D 0; i < 15; i++) { - DEBUG ((DEBUG_INFO, "%02x:", Rip[i])); + for (i =3D 0; i < MIN (15, Length); i++) { + DEBUG ((DEBUG_INFO, "%02x ", Rip[i])); } =20 DEBUG ((DEBUG_INFO, "\n")); @@ -233,52 +238,339 @@ TdxDecodeInstruction ( if ((x)) { \ TdxDecodeInstruction(Rip); \ TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \ + CpuDeadLoop (); \ } =20 +/** + * Tdx MMIO access via TdVmcall. + * + * @param MmioSize Size of the MMIO access + * @param ReadOrWrite Read or write operation + * @param GuestPA Guest physical address + * @param Val Pointer to the value which is read or written + + * @retval EFI_SUCCESS Successfully access the mmio + * @retval Others Other errors as indicated + */ STATIC -UINT64 * -EFIAPI -GetRegFromContext ( - IN EFI_SYSTEM_CONTEXT_X64 *Regs, - IN UINTN RegIndex +EFI_STATUS +TdxMmioReadWrite ( + IN UINT32 MmioSize, + IN UINT32 ReadOrWrite, + IN UINT64 GuestPA, + IN UINT64 *Val ) { - switch (RegIndex) { - case 0: return &Regs->Rax; - break; - case 1: return &Regs->Rcx; - break; - case 2: return &Regs->Rdx; - break; - case 3: return &Regs->Rbx; - break; - case 4: return &Regs->Rsp; - break; - case 5: return &Regs->Rbp; - break; - case 6: return &Regs->Rsi; - break; - case 7: return &Regs->Rdi; - break; - case 8: return &Regs->R8; - break; - case 9: return &Regs->R9; + UINT64 TdStatus; + + if ((MmioSize !=3D 1) && (MmioSize !=3D 2) && (MmioSize !=3D 4) && (Mmio= Size !=3D 8)) { + DEBUG ((DEBUG_ERROR, "%a: Invalid MmioSize - %d\n", __FUNCTION__, Mmio= Size)); + return EFI_INVALID_PARAMETER; + } + + if (Val =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + TdStatus =3D 0; + if (ReadOrWrite =3D=3D TDX_MMIO_READ) { + TdStatus =3D TdVmCall (TDVMCALL_MMIO, MmioSize, TDX_MMIO_READ, GuestPA= , 0, Val); + } else if (ReadOrWrite =3D=3D TDX_MMIO_WRITE) { + TdStatus =3D TdVmCall (TDVMCALL_MMIO, MmioSize, TDX_MMIO_WRITE, GuestP= A, *Val, 0); + } else { + return EFI_INVALID_PARAMETER; + } + + if (TdStatus !=3D 0) { + DEBUG ((DEBUG_ERROR, "%a: TdVmcall failed with %llx\n", __FUNCTION__, = TdStatus)); + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +typedef struct { + UINT8 OpCode; + UINT32 Bytes; + EFI_PHYSICAL_ADDRESS Address; + UINT64 Val; + UINT64 *Register; + UINT32 ReadOrWrite; +} MMIO_EXIT_PARSED_INSTRUCTION; + +/** + * Parse the MMIO instructions. + * + * @param Regs Pointer to the EFI_SYSTEM_CONTEXT_X64 which in= cludes the instructions + * @param InstructionData Pointer to the CC_INSTRUCTION_DATA + * @param ParsedInstruction Pointer to the parsed instruction data + * + * @retval EFI_SUCCESS Successfully parsed the instructions + * @retval Others Other error as indicated + */ +STATIC +EFI_STATUS +ParseMmioExitInstructions ( + IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, + IN OUT CC_INSTRUCTION_DATA *InstructionData, + OUT MMIO_EXIT_PARSED_INSTRUCTION *ParsedInstruction + ) +{ + EFI_STATUS Status; + UINT8 OpCode; + UINT8 SignByte; + UINT32 Bytes; + EFI_PHYSICAL_ADDRESS Address; + UINT64 Val; + UINT64 *Register; + UINT32 ReadOrWrite; + + Address =3D 0; + Bytes =3D 0; + Register =3D NULL; + Status =3D EFI_SUCCESS; + Val =3D 0; + + Status =3D CcInitInstructionData (InstructionData, NULL, Regs); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Initialize InstructionData failed! (%r)\n", = __FUNCTION__, Status)); + return Status; + } + + OpCode =3D *(InstructionData->OpCodes); + if (OpCode =3D=3D TWO_BYTE_OPCODE_ESCAPE) { + OpCode =3D *(InstructionData->OpCodes + 1); + } + + switch (OpCode) { + // + // MMIO write (MOV reg/memX, regX) + // + case 0x88: + Bytes =3D 1; + // + // fall through + // + case 0x89: + CcDecodeModRm (Regs, InstructionData); + Bytes =3D ((Bytes !=3D 0) ? Bytes : + (InstructionData->DataSize =3D=3D Size16Bits) ? 2 : + (InstructionData->DataSize =3D=3D Size32Bits) ? 4 : + (InstructionData->DataSize =3D=3D Size64Bits) ? 8 : + 0); + + if (InstructionData->Ext.ModRm.Mod =3D=3D 3) { + DEBUG ((DEBUG_ERROR, "%a: Parse Ext.ModRm.Mod error! (OpCode: 0x%x= )\n", __FUNCTION__, OpCode)); + return EFI_UNSUPPORTED; + } + + Address =3D InstructionData->Ext.RmData; + Val =3D InstructionData->Ext.RegData; + ReadOrWrite =3D TDX_MMIO_WRITE; + break; - case 10: return &Regs->R10; + + // + // MMIO write (MOV moffsetX, aX) + // + case 0xA2: + Bytes =3D 1; + // + // fall through + // + case 0xA3: + Bytes =3D ((Bytes !=3D 0) ? Bytes : + (InstructionData->DataSize =3D=3D Size16Bits) ? 2 : + (InstructionData->DataSize =3D=3D Size32Bits) ? 4 : + (InstructionData->DataSize =3D=3D Size64Bits) ? 8 : + 0); + + InstructionData->ImmediateSize =3D (UINTN)(1 << InstructionData->Add= rSize); + InstructionData->End +=3D InstructionData->ImmediateSize; + CopyMem (&Address, InstructionData->Immediate, InstructionData->Imme= diateSize); + + Val =3D Regs->Rax; + ReadOrWrite =3D TDX_MMIO_WRITE; break; - case 11: return &Regs->R11; + + // + // MMIO write (MOV reg/memX, immX) + // + case 0xC6: + Bytes =3D 1; + // + // fall through + // + case 0xC7: + CcDecodeModRm (Regs, InstructionData); + Bytes =3D ((Bytes !=3D 0) ? Bytes : + (InstructionData->DataSize =3D=3D Size16Bits) ? 2 : + (InstructionData->DataSize =3D=3D Size32Bits) ? 4 : + (InstructionData->DataSize =3D=3D Size64Bits) ? 8 : + 0); + + InstructionData->ImmediateSize =3D Bytes; + InstructionData->End +=3D Bytes; + + Val =3D 0; + CopyMem (&Val, InstructionData->Immediate, InstructionData->Immediat= eSize); + + Address =3D InstructionData->Ext.RmData; + ReadOrWrite =3D TDX_MMIO_WRITE; + break; - case 12: return &Regs->R12; + + // + // MMIO read (MOV regX, reg/memX) + // + case 0x8A: + Bytes =3D 1; + // + // fall through + // + case 0x8B: + CcDecodeModRm (Regs, InstructionData); + Bytes =3D ((Bytes !=3D 0) ? Bytes : + (InstructionData->DataSize =3D=3D Size16Bits) ? 2 : + (InstructionData->DataSize =3D=3D Size32Bits) ? 4 : + (InstructionData->DataSize =3D=3D Size64Bits) ? 8 : + 0); + if (InstructionData->Ext.ModRm.Mod =3D=3D 3) { + // + // NPF on two register operands??? + // + DEBUG ((DEBUG_ERROR, "%a: Parse Ext.ModRm.Mod error! (OpCode: 0x%x= )\n", __FUNCTION__, OpCode)); + return EFI_UNSUPPORTED; + } + + Address =3D InstructionData->Ext.RmData; + ReadOrWrite =3D TDX_MMIO_READ; + + Register =3D CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.= Reg); + if (Register =3D=3D NULL) { + return EFI_ABORTED; + } + + if (Bytes =3D=3D 4) { + // + // Zero-extend for 32-bit operation + // + *Register =3D 0; + } + break; - case 13: return &Regs->R13; + + // + // MMIO read (MOV aX, moffsetX) + // + case 0xA0: + Bytes =3D 1; + // + // fall through + // + case 0xA1: + Bytes =3D ((Bytes !=3D 0) ? Bytes : + (InstructionData->DataSize =3D=3D Size16Bits) ? 2 : + (InstructionData->DataSize =3D=3D Size32Bits) ? 4 : + (InstructionData->DataSize =3D=3D Size64Bits) ? 8 : + 0); + + InstructionData->ImmediateSize =3D (UINTN)(1 << InstructionData->Add= rSize); + InstructionData->End +=3D InstructionData->ImmediateSize; + + Address =3D 0; + CopyMem ( + &Address, + InstructionData->Immediate, + InstructionData->ImmediateSize + ); + + if (Bytes =3D=3D 4) { + // + // Zero-extend for 32-bit operation + // + Regs->Rax =3D 0; + } + + Register =3D &Regs->Rax; + ReadOrWrite =3D TDX_MMIO_READ; + break; - case 14: return &Regs->R14; + + // + // MMIO read w/ zero-extension ((MOVZX regX, reg/memX) + // + case 0xB6: + Bytes =3D 1; + // + // fall through + // + case 0xB7: + CcDecodeModRm (Regs, InstructionData); + Bytes =3D (Bytes !=3D 0) ? Bytes : 2; + Address =3D InstructionData->Ext.RmData; + + Register =3D CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.= Reg); + if (Register =3D=3D NULL) { + return EFI_ABORTED; + } + + SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0); + + ReadOrWrite =3D TDX_MMIO_READ; + break; - case 15: return &Regs->R15; + + // + // MMIO read w/ sign-extension (MOVSX regX, reg/memX) + // + case 0xBE: + Bytes =3D 1; + // + // fall through + // + case 0xBF: + CcDecodeModRm (Regs, InstructionData); + Bytes =3D (Bytes !=3D 0) ? Bytes : 2; + + Address =3D InstructionData->Ext.RmData; + + if (Bytes =3D=3D 1) { + UINT8 *Data; + Data =3D (UINT8 *)&Val; + SignByte =3D ((*Data & BIT7) !=3D 0) ? 0xFF : 0x00; + } else { + UINT16 *Data; + Data =3D (UINT16 *)&Val; + SignByte =3D ((*Data & BIT15) !=3D 0) ? 0xFF : 0x00; + } + + Register =3D CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.= Reg); + if (Register =3D=3D NULL) { + return EFI_ABORTED; + } + + SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte); + + ReadOrWrite =3D TDX_MMIO_READ; + break; + + default: + DEBUG ((DEBUG_ERROR, "%a: Invalid MMIO opcode (%x)\n", __FUNCTION__,= OpCode)); + Status =3D EFI_UNSUPPORTED; + } + + if (!EFI_ERROR (Status)) { + ParsedInstruction->OpCode =3D OpCode; + ParsedInstruction->Address =3D Address; + ParsedInstruction->Bytes =3D Bytes; + ParsedInstruction->Register =3D Register; + ParsedInstruction->Val =3D Val; + ParsedInstruction->ReadOrWrite =3D ReadOrWrite; } =20 - return NULL; + return Status; } =20 /** @@ -290,160 +582,84 @@ GetRegFromContext ( @param[in] Veinfo VE Info =20 @retval 0 Event handled successfully - @return New exception value to propagate **/ STATIC -INTN +UINT64 EFIAPI MmioExit ( IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN TDCALL_VEINFO_RETURN_DATA *Veinfo ) { - UINT64 Status; - UINT32 MmioSize; - UINT32 RegSize; - UINT8 OpCode; - BOOLEAN SeenRex; - UINT64 *Reg; - UINT8 *Rip; - UINT64 Val; - UINT32 OpSize; - MODRM ModRm; - REX Rex; - TD_RETURN_DATA TdReturnData; - UINT8 Gpaw; - UINT64 TdSharedPageMask; + UINT64 TdStatus; + EFI_STATUS Status; + TD_RETURN_DATA TdReturnData; + UINT8 Gpaw; + UINT64 Val; + UINT64 TdSharedPageMask; + CC_INSTRUCTION_DATA InstructionData; + MMIO_EXIT_PARSED_INSTRUCTION ParsedInstruction; =20 - Rip =3D (UINT8 *)Regs->Rip; - Val =3D 0; - Rex.Val =3D 0; - SeenRex =3D FALSE; - - Status =3D TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData); - if (Status =3D=3D TDX_EXIT_REASON_SUCCESS) { + TdStatus =3D TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData); + if (TdStatus =3D=3D TDX_EXIT_REASON_SUCCESS) { Gpaw =3D (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f); TdSharedPageMask =3D 1ULL << (Gpaw - 1); } else { - DEBUG ((DEBUG_ERROR, "TDCALL failed with status=3D%llx\n", Status)); - return Status; + DEBUG ((DEBUG_ERROR, "%a: TDCALL failed with status=3D%llx\n", __FUNCT= ION__, TdStatus)); + goto FatalError; } =20 if ((Veinfo->GuestPA & TdSharedPageMask) =3D=3D 0) { - DEBUG ((DEBUG_ERROR, "EPT-violation #VE on private memory is not allow= ed!")); - TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); - CpuDeadLoop (); + DEBUG ((DEBUG_ERROR, "%a: EPT-violation #VE on private memory is not a= llowed!", __FUNCTION__)); + goto FatalError; } =20 - // - // Default to 32bit transfer - // - OpSize =3D 4; + Status =3D ParseMmioExitInstructions (Regs, &InstructionData, &ParsedIns= truction); + if (EFI_ERROR (Status)) { + goto FatalError; + } + + if (Veinfo->GuestPA !=3D (ParsedInstruction.Address | TdSharedPageMask))= { + DEBUG (( + DEBUG_ERROR, + "%a: Address is not correct! (%d: 0x%llx !=3D 0x%llx)\n", + __FUNCTION__, + ParsedInstruction.OpCode, + Veinfo->GuestPA, + ParsedInstruction.Address + )); + goto FatalError; + } =20 - do { - OpCode =3D *Rip++; - if (OpCode =3D=3D 0x66) { - OpSize =3D 2; - } else if ((OpCode =3D=3D 0x64) || (OpCode =3D=3D 0x65) || (OpCode =3D= =3D 0x67)) { - continue; - } else if ((OpCode >=3D 0x40) && (OpCode <=3D 0x4f)) { - SeenRex =3D TRUE; - Rex.Val =3D OpCode; - } else { - break; + if (ParsedInstruction.ReadOrWrite =3D=3D TDX_MMIO_WRITE ) { + Status =3D TdxMmioReadWrite (ParsedInstruction.Bytes, TDX_MMIO_WRITE, = Veinfo->GuestPA, &ParsedInstruction.Val); + } else if (ParsedInstruction.ReadOrWrite =3D=3D TDX_MMIO_READ) { + Val =3D 0; + Status =3D TdxMmioReadWrite (ParsedInstruction.Bytes, TDX_MMIO_READ, V= einfo->GuestPA, &Val); + if (!EFI_ERROR (Status)) { + CopyMem (ParsedInstruction.Register, &Val, ParsedInstruction.Bytes); } - } while (TRUE); - - // - // We need to have at least 2 more bytes for this instruction - // - TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 13); - - OpCode =3D *Rip++; - // - // Two-byte opecode, get next byte - // - if (OpCode =3D=3D 0x0F) { - OpCode =3D *Rip++; - } - - switch (OpCode) { - case 0x88: - case 0x8A: - case 0xB6: - MmioSize =3D 1; - break; - case 0xB7: - MmioSize =3D 2; - break; - default: - MmioSize =3D Rex.Bits.W ? 8 : OpSize; - break; + } else { + goto FatalError; } =20 - /* Punt on AH/BH/CH/DH unless it shows up. */ - ModRm.Val =3D *Rip++; - TDX_DECODER_BUG_ON (MmioSize =3D=3D 1 && ModRm.Bits.Reg > 4 && !SeenRex = && OpCode !=3D 0xB6); - Reg =3D GetRegFromContext (Regs, ModRm.Bits.Reg | ((int)Rex.Bits.R << 3)= ); - TDX_DECODER_BUG_ON (!Reg); - - if (ModRm.Bits.Rm =3D=3D 4) { - ++Rip; /* SIB byte */ + if (EFI_ERROR (Status)) { + goto FatalError; } =20 - if ((ModRm.Bits.Mod =3D=3D 2) || ((ModRm.Bits.Mod =3D=3D 0) && (ModRm.Bi= ts.Rm =3D=3D 5))) { - Rip +=3D 4; /* DISP32 */ - } else if (ModRm.Bits.Mod =3D=3D 1) { - ++Rip; /* DISP8 */ - } - - switch (OpCode) { - case 0x88: - case 0x89: - CopyMem ((void *)&Val, Reg, MmioSize); - Status =3D TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Va= l, 0); - break; - case 0xC7: - CopyMem ((void *)&Val, Rip, OpSize); - Status =3D TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Va= l, 0); - Rip +=3D OpSize; - default: - // - // 32-bit write registers are zero extended to the full register - // Hence 'MOVZX r[32/64], r/m16' is - // hardcoded to reg size 8, and the straight MOV case has a reg - // size of 8 in the 32-bit read case. - // - switch (OpCode) { - case 0xB6: - RegSize =3D Rex.Bits.W ? 8 : OpSize; - break; - case 0xB7: - RegSize =3D 8; - break; - default: - RegSize =3D MmioSize =3D=3D 4 ? 8 : MmioSize; - break; - } - - Status =3D TdVmCall (TDVMCALL_MMIO, MmioSize, 0, Veinfo->GuestPA, 0,= &Val); - if (Status =3D=3D 0) { - ZeroMem (Reg, RegSize); - CopyMem (Reg, (void *)&Val, MmioSize); - } - } - - if (Status =3D=3D 0) { - TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15); + // + // We change instruction length to reflect true size so handler can + // bump rip + // + Veinfo->ExitInstructionLength =3D (UINT32)(CcInstructionLength (&Instru= ctionData)); + TdxDecodeInstruction ((UINT8 *)Regs->Rip, Veinfo->ExitInstructionLength); =20 - // - // We change instruction length to reflect true size so handler can - // bump rip - // - Veinfo->ExitInstructionLength =3D (UINT32)((UINT64)Rip - Regs->Rip); - } + return 0; =20 - return Status; +FatalError: + TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); + CpuDeadLoop (); + return 0; } =20 /** @@ -479,6 +695,7 @@ CcExitHandleVe ( if (Status !=3D 0) { DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status =3D= 0x%llx\n", Status)); TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); + CpuDeadLoop (); } =20 switch (ReturnData.VeInfo.ExitReason) { @@ -571,6 +788,7 @@ CcExitHandleVe ( )); =20 TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0); + CpuDeadLoop (); } =20 SystemContext.SystemContextX64->Rip +=3D ReturnData.VeInfo.ExitInstructi= onLength; --=20 2.29.2.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#98651): https://edk2.groups.io/g/devel/message/98651 Mute This Topic: https://groups.io/mt/96325925/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-