From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../bootsectors/bs3-cpu-generated-1-template.c | 6152 ++++++++++++++++++++ 1 file changed, 6152 insertions(+) create mode 100644 src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c (limited to 'src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c') diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c new file mode 100644 index 00000000..30bbafa6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c @@ -0,0 +1,6152 @@ +/* $Id: bs3-cpu-generated-1-template.c $ */ +/** @file + * BS3Kit - bs3-cpu-generated-1, C code template. + */ + +/* + * Copyright (C) 2007-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef BS3_INSTANTIATING_CMN +# error "BS3_INSTANTIATING_CMN not defined" +#endif + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include + +#include "bs3-cpu-generated-1.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define BS3CG1_WITH_VEX + +#define P_CS X86_OP_PRF_CS +#define P_SS X86_OP_PRF_SS +#define P_DS X86_OP_PRF_DS +#define P_ES X86_OP_PRF_ES +#define P_FS X86_OP_PRF_FS +#define P_GS X86_OP_PRF_GS +#define P_OZ X86_OP_PRF_SIZE_OP +#define P_AZ X86_OP_PRF_SIZE_ADDR +#define P_LK X86_OP_PRF_LOCK +#define P_RN X86_OP_PRF_REPNZ +#define P_RZ X86_OP_PRF_REPZ + +#define REX_WRBX (X86_OP_REX_W | X86_OP_REX_R | X86_OP_REX_B | X86_OP_REX_X) +#define REX_W___ (X86_OP_REX_W) +#define REX_WR__ (X86_OP_REX_W | X86_OP_REX_R) +#define REX_W_B_ (X86_OP_REX_W | X86_OP_REX_B) +#define REX_W__X (X86_OP_REX_W | X86_OP_REX_X) +#define REX_WRB_ (X86_OP_REX_W | X86_OP_REX_R | X86_OP_REX_B) +#define REX_WR_X (X86_OP_REX_W | X86_OP_REX_R | X86_OP_REX_X) +#define REX_W_BX (X86_OP_REX_W | X86_OP_REX_B | X86_OP_REX_X) +#define REX__R__ (X86_OP_REX_R) +#define REX__RB_ (X86_OP_REX_R | X86_OP_REX_B) +#define REX__R_X (X86_OP_REX_R | X86_OP_REX_X) +#define REX__RBX (X86_OP_REX_R | X86_OP_REX_B | X86_OP_REX_X) +#define REX___B_ (X86_OP_REX_B) +#define REX___BX (X86_OP_REX_B | X86_OP_REX_X) +#define REX____X (X86_OP_REX_X) +#define REX_____ (0x40) + + +/** @def BS3CG1_DPRINTF + * Debug print macro. + */ +#if 0 +# define BS3CG1_DPRINTF(a_ArgList) Bs3TestPrintf a_ArgList +# define BS3CG1_DEBUG_CTX_MOD +#else +# define BS3CG1_DPRINTF(a_ArgList) do { } while (0) +#endif + +/** + * Checks if this is a 64-bit test target or not. + * Helps avoid ifdefs or code bloat. + */ +#if ARCH_BITS == 64 +# define BS3CG1_IS_64BIT_TARGET(a_pThis) BS3_MODE_IS_64BIT_CODE((a_pThis)->bMode) +#else +# define BS3CG1_IS_64BIT_TARGET(a_pThis) (false) +#endif + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** Operand value location. */ +typedef enum BS3CG1OPLOC +{ + BS3CG1OPLOC_INVALID = 0, + BS3CG1OPLOC_CTX, + BS3CG1OPLOC_CTX_ZX_VLMAX, + BS3CG1OPLOC_IMM, + BS3CG1OPLOC_MEM, + BS3CG1OPLOC_MEM_RW, + BS3CG1OPLOC_MEM_WO, + BS3CG1OPLOC_END +} BS3CG1OPLOC; +AssertCompile(BS3CG1OPLOC_END <= 16); + + +/** Pointer to the generated test state. */ +typedef struct BS3CG1STATE *PBS3CG1STATE; + +/** + * Encoder callback. + * @returns Next encoding. If equal or less to @a iEncoding, no + * further encodings are available for testing. + * @param pThis The state. + * @param iEncoding The encoding. + */ +typedef unsigned BS3_NEAR_CODE FNBS3CG1ENCODER(PBS3CG1STATE pThis, unsigned iEncoding); +/** Pointer to a encoder callback. */ +typedef FNBS3CG1ENCODER *PFNBS3CG1ENCODER; + + +/** + * The state. + */ +typedef struct BS3CG1STATE +{ + /** @name Instruction details (expanded from BS3CG1INSTR). + * @{ */ + /** Pointer to the mnemonic string (not terminated) (g_achBs3Cg1Mnemonics). */ + const char BS3_FAR *pchMnemonic; + /** Pointer to the test header. */ + PCBS3CG1TESTHDR pTestHdr; + /** Pointer to the per operand flags (g_abBs3Cg1Operands). */ + const uint8_t BS3_FAR *pabOperands; + /** Opcode bytes (g_abBs3Cg1Opcodes). */ + const uint8_t BS3_FAR *pabOpcodes; + /** The current instruction number in the input array (for error reporting). */ + uint32_t iInstr; + + /** The instruction flags. */ + uint32_t fFlags; + /** The encoding. */ + BS3CG1ENC enmEncoding; + /** The non-invalid encoding. This may differ from enmEncoding when + * Bs3Cg1CalcNoneIntelInvalidEncoding has been called. */ + BS3CG1ENC enmEncodingNonInvalid; + /** The CPU test / CPU ID. */ + BS3CG1CPU enmCpuTest; + /** Prefix sensitivity and requirements. */ + BS3CG1PFXKIND enmPrefixKind; + /** Exception type (SSE, AVX). */ + BS3CG1XCPTTYPE enmXcptType; + /** Per operand flags. */ + BS3CG1OP aenmOperands[4]; + /** Opcode bytes. */ + uint8_t abOpcodes[4]; + /** The instruction encoder. */ + PFNBS3CG1ENCODER pfnEncoder; + + /** The length of the mnemonic. */ + uint8_t cchMnemonic; + /** Whether to advance the mnemonic pointer or not. */ + uint8_t fAdvanceMnemonic; + /** The opcode map number. */ + uint8_t uOpcodeMap; + /** The number of opcode bytes. */ + uint8_t cbOpcodes; + /** Number of operands. */ + uint8_t cOperands; + /** @} */ + + /** Default operand size. */ + uint8_t cbOpDefault; + /** Operand size when overridden by 066h. */ + uint8_t cbOpOvrd66; + /** Operand size when overridden by REX.W. */ + uint8_t cbOpOvrdRexW; + + /** Operand size in bytes (0 if not applicable). */ + uint8_t cbOperand; + /** Current VEX.L value (UINT8_MAX if not applicable). */ + uint8_t uVexL; + /** Current target ring (0..3). */ + uint8_t uCpl; + + /** The current test number. */ + uint8_t iTest; + + /** Target mode (g_bBs3CurrentMode). */ + uint8_t bMode; + /** The CPU vendor (BS3CPUVENDOR). */ + uint8_t bCpuVendor; + /** First ring being tested. */ + uint8_t iFirstRing; + /** End of rings being tested. */ + uint8_t iEndRing; + + /** @name Current encoded instruction. + * @{ */ + /** The size of the current instruction that we're testing. */ + uint8_t cbCurInstr; + /** The size the prefixes. */ + uint8_t cbCurPrefix; + /** The offset into abCurInstr of the immediate. */ + uint8_t offCurImm; + /** Buffer for assembling the current instruction. */ + uint8_t abCurInstr[23]; + + /** Set if the encoding can't be tested in the same ring as this test code. + * This is used to deal with encodings modifying SP/ESP/RSP. */ + bool fSameRingNotOkay; + /** Whether to work the extended context too. */ + bool fWorkExtCtx; + /** The aOperands index of the modrm.reg operand (if applicable). */ + uint8_t iRegOp; + /** The aOperands index of the modrm.rm operand (if applicable). */ + uint8_t iRmOp; + + /** Operands details. */ + struct + { + uint8_t cbOp; + /** BS3CG1OPLOC_XXX. */ + uint8_t enmLocation; + /** BS3CG1OPLOC_XXX for memory encodings (MODRM.rm field). */ + uint8_t enmLocationMem : 4; + /** BS3CG1OPLOC_XXX for register encodings (MODRM.rm field). */ + uint8_t enmLocationReg : 4; + /** The BS3CG1DST value for this field. + * Set to BS3CG1DST_INVALID if memory or immediate. */ + uint8_t idxField; + /** The base BS3CG1DST value for this field. + * Used only by some generalized encoders when dealing with registers. */ + uint8_t idxFieldBase; + /** Depends on enmLocation. + * - BS3CG1OPLOC_IMM: offset relative to start of the instruction. + * - BS3CG1OPLOC_MEM: offset should be subtracted from &pbDataPg[_4K]. + * - BS3CG1OPLOC_MEM_RW: offset should be subtracted from &pbDataPg[_4K]. + * - BS3CG1OPLOC_MEM_RO: offset should be subtracted from &pbDataPg[_4K]. + * - BS3CG1OPLOC_CTX: not used (use idxField instead). + */ + uint8_t off; + } aOperands[4]; + /** @} */ + + /** Page to put code in. When paging is enabled, the page before and after + * are marked not-present. */ + uint8_t BS3_FAR *pbCodePg; + /** The flat address corresponding to pbCodePg. */ + uintptr_t uCodePgFlat; + /** The 16-bit address corresponding to pbCodePg if relevant for bMode. */ + RTFAR16 CodePgFar; + /** The IP/EIP/RIP value for pbCodePg[0] relative to CS (bMode). */ + uintptr_t CodePgRip; + + /** Page for placing data operands in. When paging is enabled, the page before + * and after are marked not-present. */ + uint8_t BS3_FAR *pbDataPg; + /** The flat address corresponding to pbDataPg. */ + uintptr_t uDataPgFlat; + /** The 16-bit address corresponding to pbDataPg. */ + RTFAR16 DataPgFar; + + /** The name corresponding to bMode. */ + const char BS3_FAR *pszMode; + /** The short name corresponding to bMode. */ + const char BS3_FAR *pszModeShort; + + /** @name Expected result (modifiable by output program). + * @{ */ + /** The expected exception based on operand values or result. + * UINT8_MAX if no special exception expected. */ + uint8_t bValueXcpt; + /** @} */ + /** Alignment exception expected by the encoder. + * UINT8_MAX if no special exception expected. */ + uint8_t bAlignmentXcpt; + /** Set by the encoding method to indicating invalid encoding. */ + bool fInvalidEncoding; + /** The result of Bs3Cg1CpuSetupFirst(). */ + bool fCpuSetupFirstResult; + + /** The context we're working on. */ + BS3REGCTX Ctx; + /** The trap context and frame. */ + BS3TRAPFRAME TrapFrame; + /** Initial contexts, one for each ring. */ + BS3REGCTX aInitialCtxs[4]; + + /** The extended context we're working on (input, expected output). */ + PBS3EXTCTX pExtCtx; + /** The extended result context (analoguous to TrapFrame). */ + PBS3EXTCTX pResultExtCtx; + /** The initial extended context. */ + PBS3EXTCTX pInitialExtCtx; + + /** Memory operand scratch space. */ + union + { + uint8_t ab[128]; + uint16_t au16[128 / sizeof(uint16_t)]; + uint32_t au32[128 / sizeof(uint32_t)]; + uint64_t au64[128 / sizeof(uint64_t)]; + } MemOp; + + /** Array parallel to aInitialCtxs for saving segment registers. */ + struct + { + RTSEL ds; + } aSavedSegRegs[4]; + +} BS3CG1STATE; + + +#define BS3CG1_PF_OZ UINT16_C(0x0001) +#define BS3CG1_PF_AZ UINT16_C(0x0002) +#define BS3CG1_PF_CS UINT16_C(0x0004) +#define BS3CG1_PF_DS UINT16_C(0x0008) +#define BS3CG1_PF_ES UINT16_C(0x0010) +#define BS3CG1_PF_FS UINT16_C(0x0020) +#define BS3CG1_PF_GS UINT16_C(0x0040) +#define BS3CG1_PF_SS UINT16_C(0x0080) +#define BS3CG1_PF_SEGS (BS3CG1_PF_CS | BS3CG1_PF_DS | BS3CG1_PF_ES | BS3CG1_PF_FS | BS3CG1_PF_GS | BS3CG1_PF_SS) +#define BS3CG1_PF_MEM (BS3CG1_PF_SEGS | BS3CG1_PF_AZ) +#define BS3CG1_PF_LK UINT16_C(0x0100) +#define BS3CG1_PF_RN UINT16_C(0x0200) +#define BS3CG1_PF_RZ UINT16_C(0x0400) +#define BS3CG1_PF_W UINT16_C(0x0800) /**< REX.W */ +#define BS3CG1_PF_R UINT16_C(0x1000) /**< REX.R */ +#define BS3CG1_PF_B UINT16_C(0x2000) /**< REX.B */ +#define BS3CG1_PF_X UINT16_C(0x4000) /**< REX.X */ + + +/** Used in g_cbBs3Cg1DstFields to indicate that it's one of the 4 operands. */ +#define BS3CG1DSTSIZE_OPERAND UINT8_C(255) +/** Used in g_cbBs3Cg1DstFields to indicate that the operand size determins + * the field size (2, 4, or 8). */ +#define BS3CG1DSTSIZE_OPERAND_SIZE_GRP UINT8_C(254) + + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Destination field sizes indexed by bBS3CG1DST. + * Zero means operand size sized. */ +static const uint8_t g_acbBs3Cg1DstFields[] = +{ + /* [BS3CG1DST_INVALID] = */ BS3CG1DSTSIZE_OPERAND, + + /* [BS3CG1DST_OP1] = */ BS3CG1DSTSIZE_OPERAND, + /* [BS3CG1DST_OP2] = */ BS3CG1DSTSIZE_OPERAND, + /* [BS3CG1DST_OP3] = */ BS3CG1DSTSIZE_OPERAND, + /* [BS3CG1DST_OP4] = */ BS3CG1DSTSIZE_OPERAND, + /* [BS3CG1DST_EFL] = */ 4, + /* [BS3CG1DST_EFL_UNDEF]=*/ 4, + + /* [BS3CG1DST_AL] = */ 1, + /* [BS3CG1DST_CL] = */ 1, + /* [BS3CG1DST_DL] = */ 1, + /* [BS3CG1DST_BL] = */ 1, + /* [BS3CG1DST_AH] = */ 1, + /* [BS3CG1DST_CH] = */ 1, + /* [BS3CG1DST_DH] = */ 1, + /* [BS3CG1DST_BH] = */ 1, + /* [BS3CG1DST_SPL] = */ 1, + /* [BS3CG1DST_BPL] = */ 1, + /* [BS3CG1DST_SIL] = */ 1, + /* [BS3CG1DST_DIL] = */ 1, + /* [BS3CG1DST_R8L] = */ 1, + /* [BS3CG1DST_R9L] = */ 1, + /* [BS3CG1DST_R10L] = */ 1, + /* [BS3CG1DST_R11L] = */ 1, + /* [BS3CG1DST_R12L] = */ 1, + /* [BS3CG1DST_R13L] = */ 1, + /* [BS3CG1DST_R14L] = */ 1, + /* [BS3CG1DST_R15L] = */ 1, + + /* [BS3CG1DST_AX] = */ 2, + /* [BS3CG1DST_CX] = */ 2, + /* [BS3CG1DST_DX] = */ 2, + /* [BS3CG1DST_BX] = */ 2, + /* [BS3CG1DST_SP] = */ 2, + /* [BS3CG1DST_BP] = */ 2, + /* [BS3CG1DST_SI] = */ 2, + /* [BS3CG1DST_DI] = */ 2, + /* [BS3CG1DST_R8W] = */ 2, + /* [BS3CG1DST_R9W] = */ 2, + /* [BS3CG1DST_R10W] = */ 2, + /* [BS3CG1DST_R11W] = */ 2, + /* [BS3CG1DST_R12W] = */ 2, + /* [BS3CG1DST_R13W] = */ 2, + /* [BS3CG1DST_R14W] = */ 2, + /* [BS3CG1DST_R15W] = */ 2, + + /* [BS3CG1DST_EAX] = */ 4, + /* [BS3CG1DST_ECX] = */ 4, + /* [BS3CG1DST_EDX] = */ 4, + /* [BS3CG1DST_EBX] = */ 4, + /* [BS3CG1DST_ESP] = */ 4, + /* [BS3CG1DST_EBP] = */ 4, + /* [BS3CG1DST_ESI] = */ 4, + /* [BS3CG1DST_EDI] = */ 4, + /* [BS3CG1DST_R8D] = */ 4, + /* [BS3CG1DST_R9D] = */ 4, + /* [BS3CG1DST_R10D] = */ 4, + /* [BS3CG1DST_R11D] = */ 4, + /* [BS3CG1DST_R12D] = */ 4, + /* [BS3CG1DST_R13D] = */ 4, + /* [BS3CG1DST_R14D] = */ 4, + /* [BS3CG1DST_R15D] = */ 4, + + /* [BS3CG1DST_RAX] = */ 8, + /* [BS3CG1DST_RCX] = */ 8, + /* [BS3CG1DST_RDX] = */ 8, + /* [BS3CG1DST_RBX] = */ 8, + /* [BS3CG1DST_RSP] = */ 8, + /* [BS3CG1DST_RBP] = */ 8, + /* [BS3CG1DST_RSI] = */ 8, + /* [BS3CG1DST_RDI] = */ 8, + /* [BS3CG1DST_R8] = */ 8, + /* [BS3CG1DST_R9] = */ 8, + /* [BS3CG1DST_R10] = */ 8, + /* [BS3CG1DST_R11] = */ 8, + /* [BS3CG1DST_R12] = */ 8, + /* [BS3CG1DST_R13] = */ 8, + /* [BS3CG1DST_R14] = */ 8, + /* [BS3CG1DST_R15] = */ 8, + + /* [BS3CG1DST_OZ_RAX] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RCX] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RDX] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RBX] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RSP] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RBP] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RSI] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RDI] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R8] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R9] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R10] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R11] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R12] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R13] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R14] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R15] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + + /* [BS3CG1DST_CR0] = */ 4, + /* [BS3CG1DST_CR4] = */ 4, + /* [BS3CG1DST_XCR0] = */ 8, + + /* [BS3CG1DST_FCW] = */ 2, + /* [BS3CG1DST_FSW] = */ 2, + /* [BS3CG1DST_FTW] = */ 2, + /* [BS3CG1DST_FOP] = */ 2, + /* [BS3CG1DST_FPUIP] = */ 2, + /* [BS3CG1DST_FPUCS] = */ 2, + /* [BS3CG1DST_FPUDP] = */ 2, + /* [BS3CG1DST_FPUDS] = */ 2, + /* [BS3CG1DST_MXCSR] = */ 4, + /* [BS3CG1DST_ST0] = */ 12, + /* [BS3CG1DST_ST1] = */ 12, + /* [BS3CG1DST_ST2] = */ 12, + /* [BS3CG1DST_ST3] = */ 12, + /* [BS3CG1DST_ST4] = */ 12, + /* [BS3CG1DST_ST5] = */ 12, + /* [BS3CG1DST_ST6] = */ 12, + /* [BS3CG1DST_ST7] = */ 12, + /* [BS3CG1DST_MM0] = */ 8, + /* [BS3CG1DST_MM1] = */ 8, + /* [BS3CG1DST_MM2] = */ 8, + /* [BS3CG1DST_MM3] = */ 8, + /* [BS3CG1DST_MM4] = */ 8, + /* [BS3CG1DST_MM5] = */ 8, + /* [BS3CG1DST_MM6] = */ 8, + /* [BS3CG1DST_MM7] = */ 8, + /* [BS3CG1DST_MM0_LO_ZX] = */ 4, + /* [BS3CG1DST_MM1_LO_ZX] = */ 4, + /* [BS3CG1DST_MM2_LO_ZX] = */ 4, + /* [BS3CG1DST_MM3_LO_ZX] = */ 4, + /* [BS3CG1DST_MM4_LO_ZX] = */ 4, + /* [BS3CG1DST_MM5_LO_ZX] = */ 4, + /* [BS3CG1DST_MM6_LO_ZX] = */ 4, + /* [BS3CG1DST_MM7_LO_ZX] = */ 4, + /* [BS3CG1DST_XMM0] = */ 16, + /* [BS3CG1DST_XMM1] = */ 16, + /* [BS3CG1DST_XMM2] = */ 16, + /* [BS3CG1DST_XMM3] = */ 16, + /* [BS3CG1DST_XMM4] = */ 16, + /* [BS3CG1DST_XMM5] = */ 16, + /* [BS3CG1DST_XMM6] = */ 16, + /* [BS3CG1DST_XMM7] = */ 16, + /* [BS3CG1DST_XMM8] = */ 16, + /* [BS3CG1DST_XMM9] = */ 16, + /* [BS3CG1DST_XMM10] = */ 16, + /* [BS3CG1DST_XMM11] = */ 16, + /* [BS3CG1DST_XMM12] = */ 16, + /* [BS3CG1DST_XMM13] = */ 16, + /* [BS3CG1DST_XMM14] = */ 16, + /* [BS3CG1DST_XMM15] = */ 16, + /* [BS3CG1DST_XMM0_LO] = */ 8, + /* [BS3CG1DST_XMM1_LO] = */ 8, + /* [BS3CG1DST_XMM2_LO] = */ 8, + /* [BS3CG1DST_XMM3_LO] = */ 8, + /* [BS3CG1DST_XMM4_LO] = */ 8, + /* [BS3CG1DST_XMM5_LO] = */ 8, + /* [BS3CG1DST_XMM6_LO] = */ 8, + /* [BS3CG1DST_XMM7_LO] = */ 8, + /* [BS3CG1DST_XMM8_LO] = */ 8, + /* [BS3CG1DST_XMM9_LO] = */ 8, + /* [BS3CG1DST_XMM10_LO] = */ 8, + /* [BS3CG1DST_XMM11_LO] = */ 8, + /* [BS3CG1DST_XMM12_LO] = */ 8, + /* [BS3CG1DST_XMM13_LO] = */ 8, + /* [BS3CG1DST_XMM14_LO] = */ 8, + /* [BS3CG1DST_XMM15_LO] = */ 8, + /* [BS3CG1DST_XMM0_HI] = */ 8, + /* [BS3CG1DST_XMM1_HI] = */ 8, + /* [BS3CG1DST_XMM2_HI] = */ 8, + /* [BS3CG1DST_XMM3_HI] = */ 8, + /* [BS3CG1DST_XMM4_HI] = */ 8, + /* [BS3CG1DST_XMM5_HI] = */ 8, + /* [BS3CG1DST_XMM6_HI] = */ 8, + /* [BS3CG1DST_XMM7_HI] = */ 8, + /* [BS3CG1DST_XMM8_HI] = */ 8, + /* [BS3CG1DST_XMM9_HI] = */ 8, + /* [BS3CG1DST_XMM10_HI] = */ 8, + /* [BS3CG1DST_XMM11_HI] = */ 8, + /* [BS3CG1DST_XMM12_HI] = */ 8, + /* [BS3CG1DST_XMM13_HI] = */ 8, + /* [BS3CG1DST_XMM14_HI] = */ 8, + /* [BS3CG1DST_XMM15_HI] = */ 8, + /* [BS3CG1DST_XMM0_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM1_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM2_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM3_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM4_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM5_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM6_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM7_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM8_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM9_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM10_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM11_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM12_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM13_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM14_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM15_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM0_DW0] = */ 4, + /* [BS3CG1DST_XMM1_DW0] = */ 4, + /* [BS3CG1DST_XMM2_DW0] = */ 4, + /* [BS3CG1DST_XMM3_DW0] = */ 4, + /* [BS3CG1DST_XMM4_DW0] = */ 4, + /* [BS3CG1DST_XMM5_DW0] = */ 4, + /* [BS3CG1DST_XMM6_DW0] = */ 4, + /* [BS3CG1DST_XMM7_DW0] = */ 4, + /* [BS3CG1DST_XMM8_DW0] = */ 4, + /* [BS3CG1DST_XMM9_DW0] = */ 4, + /* [BS3CG1DST_XMM10_DW0] = */ 4, + /* [BS3CG1DST_XMM11_DW0] = */ 4, + /* [BS3CG1DST_XMM12_DW0] = */ 4, + /* [BS3CG1DST_XMM13_DW0] = */ 4, + /* [BS3CG1DST_XMM14_DW0] = */ 4, + /* [BS3CG1DST_XMM15_DW0] = */ 4, + /* [BS3CG1DST_XMM0_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM1_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM2_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM3_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM4_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM5_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM6_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM7_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM8_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM9_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM10_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM11_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM12_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM13_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM14_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM15_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM0_HI96] = */ 12, + /* [BS3CG1DST_XMM1_HI96] = */ 12, + /* [BS3CG1DST_XMM2_HI96] = */ 12, + /* [BS3CG1DST_XMM3_HI96] = */ 12, + /* [BS3CG1DST_XMM4_HI96] = */ 12, + /* [BS3CG1DST_XMM5_HI96] = */ 12, + /* [BS3CG1DST_XMM6_HI96] = */ 12, + /* [BS3CG1DST_XMM7_HI96] = */ 12, + /* [BS3CG1DST_XMM8_HI96] = */ 12, + /* [BS3CG1DST_XMM9_HI96] = */ 12, + /* [BS3CG1DST_XMM10_HI96] =*/ 12, + /* [BS3CG1DST_XMM11_HI96] =*/ 12, + /* [BS3CG1DST_XMM12_HI96] =*/ 12, + /* [BS3CG1DST_XMM13_HI96] =*/ 12, + /* [BS3CG1DST_XMM14_HI96] =*/ 12, + /* [BS3CG1DST_XMM15_HI96] =*/ 12, + /* [BS3CG1DST_YMM0] = */ 32, + /* [BS3CG1DST_YMM1] = */ 32, + /* [BS3CG1DST_YMM2] = */ 32, + /* [BS3CG1DST_YMM3] = */ 32, + /* [BS3CG1DST_YMM4] = */ 32, + /* [BS3CG1DST_YMM5] = */ 32, + /* [BS3CG1DST_YMM6] = */ 32, + /* [BS3CG1DST_YMM7] = */ 32, + /* [BS3CG1DST_YMM8] = */ 32, + /* [BS3CG1DST_YMM9] = */ 32, + /* [BS3CG1DST_YMM10] = */ 32, + /* [BS3CG1DST_YMM11] = */ 32, + /* [BS3CG1DST_YMM12] = */ 32, + /* [BS3CG1DST_YMM13] = */ 32, + /* [BS3CG1DST_YMM14] = */ 32, + /* [BS3CG1DST_YMM15] = */ 32, + + /* [BS3CG1DST_VALUE_XCPT] = */ 1, +}; +AssertCompile(RT_ELEMENTS(g_acbBs3Cg1DstFields) == BS3CG1DST_END); + +/** Destination field offset indexed by bBS3CG1DST. + * Zero means operand size sized. */ +static const unsigned g_aoffBs3Cg1DstFields[] = +{ + /* [BS3CG1DST_INVALID] = */ ~0U, + /* [BS3CG1DST_OP1] = */ ~0U, + /* [BS3CG1DST_OP2] = */ ~0U, + /* [BS3CG1DST_OP3] = */ ~0U, + /* [BS3CG1DST_OP4] = */ ~0U, + /* [BS3CG1DST_EFL] = */ RT_OFFSETOF(BS3REGCTX, rflags), + /* [BS3CG1DST_EFL_UNDEF]=*/ ~0, /* special field */ + + /* [BS3CG1DST_AL] = */ RT_OFFSETOF(BS3REGCTX, rax.u8), + /* [BS3CG1DST_CL] = */ RT_OFFSETOF(BS3REGCTX, rcx.u8), + /* [BS3CG1DST_DL] = */ RT_OFFSETOF(BS3REGCTX, rdx.u8), + /* [BS3CG1DST_BL] = */ RT_OFFSETOF(BS3REGCTX, rbx.u8), + /* [BS3CG1DST_AH] = */ RT_OFFSETOF(BS3REGCTX, rax.b.bHi), + /* [BS3CG1DST_CH] = */ RT_OFFSETOF(BS3REGCTX, rcx.b.bHi), + /* [BS3CG1DST_DH] = */ RT_OFFSETOF(BS3REGCTX, rdx.b.bHi), + /* [BS3CG1DST_BH] = */ RT_OFFSETOF(BS3REGCTX, rbx.b.bHi), + /* [BS3CG1DST_SPL] = */ RT_OFFSETOF(BS3REGCTX, rsp.u8), + /* [BS3CG1DST_BPL] = */ RT_OFFSETOF(BS3REGCTX, rbp.u8), + /* [BS3CG1DST_SIL] = */ RT_OFFSETOF(BS3REGCTX, rsi.u8), + /* [BS3CG1DST_DIL] = */ RT_OFFSETOF(BS3REGCTX, rdi.u8), + /* [BS3CG1DST_R8L] = */ RT_OFFSETOF(BS3REGCTX, r8.u8), + /* [BS3CG1DST_R9L] = */ RT_OFFSETOF(BS3REGCTX, r9.u8), + /* [BS3CG1DST_R10L] = */ RT_OFFSETOF(BS3REGCTX, r10.u8), + /* [BS3CG1DST_R11L] = */ RT_OFFSETOF(BS3REGCTX, r11.u8), + /* [BS3CG1DST_R12L] = */ RT_OFFSETOF(BS3REGCTX, r12.u8), + /* [BS3CG1DST_R13L] = */ RT_OFFSETOF(BS3REGCTX, r13.u8), + /* [BS3CG1DST_R14L] = */ RT_OFFSETOF(BS3REGCTX, r14.u8), + /* [BS3CG1DST_R15L] = */ RT_OFFSETOF(BS3REGCTX, r15.u8), + + /* [BS3CG1DST_AX] = */ RT_OFFSETOF(BS3REGCTX, rax.u16), + /* [BS3CG1DST_CX] = */ RT_OFFSETOF(BS3REGCTX, rcx.u16), + /* [BS3CG1DST_DX] = */ RT_OFFSETOF(BS3REGCTX, rdx.u16), + /* [BS3CG1DST_BX] = */ RT_OFFSETOF(BS3REGCTX, rbx.u16), + /* [BS3CG1DST_SP] = */ RT_OFFSETOF(BS3REGCTX, rsp.u16), + /* [BS3CG1DST_BP] = */ RT_OFFSETOF(BS3REGCTX, rbp.u16), + /* [BS3CG1DST_SI] = */ RT_OFFSETOF(BS3REGCTX, rsi.u16), + /* [BS3CG1DST_DI] = */ RT_OFFSETOF(BS3REGCTX, rdi.u16), + /* [BS3CG1DST_R8W] = */ RT_OFFSETOF(BS3REGCTX, r8.u16), + /* [BS3CG1DST_R9W] = */ RT_OFFSETOF(BS3REGCTX, r9.u16), + /* [BS3CG1DST_R10W] = */ RT_OFFSETOF(BS3REGCTX, r10.u16), + /* [BS3CG1DST_R11W] = */ RT_OFFSETOF(BS3REGCTX, r11.u16), + /* [BS3CG1DST_R12W] = */ RT_OFFSETOF(BS3REGCTX, r12.u16), + /* [BS3CG1DST_R13W] = */ RT_OFFSETOF(BS3REGCTX, r13.u16), + /* [BS3CG1DST_R14W] = */ RT_OFFSETOF(BS3REGCTX, r14.u16), + /* [BS3CG1DST_R15W] = */ RT_OFFSETOF(BS3REGCTX, r15.u16), + + /* [BS3CG1DST_EAX] = */ RT_OFFSETOF(BS3REGCTX, rax.u32), + /* [BS3CG1DST_ECX] = */ RT_OFFSETOF(BS3REGCTX, rcx.u32), + /* [BS3CG1DST_EDX] = */ RT_OFFSETOF(BS3REGCTX, rdx.u32), + /* [BS3CG1DST_EBX] = */ RT_OFFSETOF(BS3REGCTX, rbx.u32), + /* [BS3CG1DST_ESP] = */ RT_OFFSETOF(BS3REGCTX, rsp.u32), + /* [BS3CG1DST_EBP] = */ RT_OFFSETOF(BS3REGCTX, rbp.u32), + /* [BS3CG1DST_ESI] = */ RT_OFFSETOF(BS3REGCTX, rsi.u32), + /* [BS3CG1DST_EDI] = */ RT_OFFSETOF(BS3REGCTX, rdi.u32), + /* [BS3CG1DST_R8D] = */ RT_OFFSETOF(BS3REGCTX, r8.u32), + /* [BS3CG1DST_R9D] = */ RT_OFFSETOF(BS3REGCTX, r9.u32), + /* [BS3CG1DST_R10D] = */ RT_OFFSETOF(BS3REGCTX, r10.u32), + /* [BS3CG1DST_R11D] = */ RT_OFFSETOF(BS3REGCTX, r11.u32), + /* [BS3CG1DST_R12D] = */ RT_OFFSETOF(BS3REGCTX, r12.u32), + /* [BS3CG1DST_R13D] = */ RT_OFFSETOF(BS3REGCTX, r13.u32), + /* [BS3CG1DST_R14D] = */ RT_OFFSETOF(BS3REGCTX, r14.u32), + /* [BS3CG1DST_R15D] = */ RT_OFFSETOF(BS3REGCTX, r15.u32), + + /* [BS3CG1DST_RAX] = */ RT_OFFSETOF(BS3REGCTX, rax.u64), + /* [BS3CG1DST_RCX] = */ RT_OFFSETOF(BS3REGCTX, rcx.u64), + /* [BS3CG1DST_RDX] = */ RT_OFFSETOF(BS3REGCTX, rdx.u64), + /* [BS3CG1DST_RBX] = */ RT_OFFSETOF(BS3REGCTX, rbx.u64), + /* [BS3CG1DST_RSP] = */ RT_OFFSETOF(BS3REGCTX, rsp.u64), + /* [BS3CG1DST_RBP] = */ RT_OFFSETOF(BS3REGCTX, rbp.u64), + /* [BS3CG1DST_RSI] = */ RT_OFFSETOF(BS3REGCTX, rsi.u64), + /* [BS3CG1DST_RDI] = */ RT_OFFSETOF(BS3REGCTX, rdi.u64), + /* [BS3CG1DST_R8] = */ RT_OFFSETOF(BS3REGCTX, r8.u64), + /* [BS3CG1DST_R9] = */ RT_OFFSETOF(BS3REGCTX, r9.u64), + /* [BS3CG1DST_R10] = */ RT_OFFSETOF(BS3REGCTX, r10.u64), + /* [BS3CG1DST_R11] = */ RT_OFFSETOF(BS3REGCTX, r11.u64), + /* [BS3CG1DST_R12] = */ RT_OFFSETOF(BS3REGCTX, r12.u64), + /* [BS3CG1DST_R13] = */ RT_OFFSETOF(BS3REGCTX, r13.u64), + /* [BS3CG1DST_R14] = */ RT_OFFSETOF(BS3REGCTX, r14.u64), + /* [BS3CG1DST_R15] = */ RT_OFFSETOF(BS3REGCTX, r15.u64), + + /* [BS3CG1DST_OZ_RAX] = */ RT_OFFSETOF(BS3REGCTX, rax), + /* [BS3CG1DST_OZ_RCX] = */ RT_OFFSETOF(BS3REGCTX, rcx), + /* [BS3CG1DST_OZ_RDX] = */ RT_OFFSETOF(BS3REGCTX, rdx), + /* [BS3CG1DST_OZ_RBX] = */ RT_OFFSETOF(BS3REGCTX, rbx), + /* [BS3CG1DST_OZ_RSP] = */ RT_OFFSETOF(BS3REGCTX, rsp), + /* [BS3CG1DST_OZ_RBP] = */ RT_OFFSETOF(BS3REGCTX, rbp), + /* [BS3CG1DST_OZ_RSI] = */ RT_OFFSETOF(BS3REGCTX, rsi), + /* [BS3CG1DST_OZ_RDI] = */ RT_OFFSETOF(BS3REGCTX, rdi), + /* [BS3CG1DST_OZ_R8] = */ RT_OFFSETOF(BS3REGCTX, r8), + /* [BS3CG1DST_OZ_R9] = */ RT_OFFSETOF(BS3REGCTX, r9), + /* [BS3CG1DST_OZ_R10] = */ RT_OFFSETOF(BS3REGCTX, r10), + /* [BS3CG1DST_OZ_R11] = */ RT_OFFSETOF(BS3REGCTX, r11), + /* [BS3CG1DST_OZ_R12] = */ RT_OFFSETOF(BS3REGCTX, r12), + /* [BS3CG1DST_OZ_R13] = */ RT_OFFSETOF(BS3REGCTX, r13), + /* [BS3CG1DST_OZ_R14] = */ RT_OFFSETOF(BS3REGCTX, r14), + /* [BS3CG1DST_OZ_R15] = */ RT_OFFSETOF(BS3REGCTX, r15), + + /* [BS3CG1DST_CR0] = */ RT_OFFSETOF(BS3REGCTX, cr0), + /* [BS3CG1DST_CR4] = */ RT_OFFSETOF(BS3REGCTX, cr4), + /* [BS3CG1DST_XCR0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, fXcr0Saved), + + /* [BS3CG1DST_FCW] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FCW), + /* [BS3CG1DST_FSW] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FSW), + /* [BS3CG1DST_FTW] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FTW), + /* [BS3CG1DST_FOP] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FOP), + /* [BS3CG1DST_FPUIP] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FPUIP), + /* [BS3CG1DST_FPUCS] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.CS), + /* [BS3CG1DST_FPUDP] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FPUDP), + /* [BS3CG1DST_FPUDS] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.DS), + /* [BS3CG1DST_MXCSR] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.MXCSR), + /* [BS3CG1DST_ST0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[0]), + /* [BS3CG1DST_ST1] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[1]), + /* [BS3CG1DST_ST2] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[2]), + /* [BS3CG1DST_ST3] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[3]), + /* [BS3CG1DST_ST4] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[4]), + /* [BS3CG1DST_ST5] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[5]), + /* [BS3CG1DST_ST6] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[6]), + /* [BS3CG1DST_ST7] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[7]), + /* [BS3CG1DST_MM0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[0]), + /* [BS3CG1DST_MM1] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[1]), + /* [BS3CG1DST_MM2] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[2]), + /* [BS3CG1DST_MM3] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[3]), + /* [BS3CG1DST_MM4] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[4]), + /* [BS3CG1DST_MM5] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[5]), + /* [BS3CG1DST_MM6] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[6]), + /* [BS3CG1DST_MM7] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[7]), + /* [BS3CG1DST_MM0_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[0]), + /* [BS3CG1DST_MM1_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[1]), + /* [BS3CG1DST_MM2_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[2]), + /* [BS3CG1DST_MM3_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[3]), + /* [BS3CG1DST_MM4_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[4]), + /* [BS3CG1DST_MM5_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[5]), + /* [BS3CG1DST_MM6_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[6]), + /* [BS3CG1DST_MM7_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[7]), + + /* [BS3CG1DST_XMM0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM1_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM2_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM3_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM4_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM5_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM6_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM7_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM8_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM9_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM10_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM11_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM12_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM13_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM14_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM15_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM0_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0].au32[1]), + /* [BS3CG1DST_XMM1_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1].au32[1]), + /* [BS3CG1DST_XMM2_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2].au32[1]), + /* [BS3CG1DST_XMM3_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3].au32[1]), + /* [BS3CG1DST_XMM4_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4].au32[1]), + /* [BS3CG1DST_XMM5_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5].au32[1]), + /* [BS3CG1DST_XMM6_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6].au32[1]), + /* [BS3CG1DST_XMM7_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7].au32[1]), + /* [BS3CG1DST_XMM8_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8].au32[1]), + /* [BS3CG1DST_XMM9_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9].au32[1]), + /* [BS3CG1DST_XMM10_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10].au32[1]), + /* [BS3CG1DST_XMM11_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11].au32[1]), + /* [BS3CG1DST_XMM12_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12].au32[1]), + /* [BS3CG1DST_XMM13_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13].au32[1]), + /* [BS3CG1DST_XMM14_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14].au32[1]), + /* [BS3CG1DST_XMM15_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15].au32[1]), + + /* [BS3CG1DST_YMM0] = */ ~0U, + /* [BS3CG1DST_YMM1] = */ ~0U, + /* [BS3CG1DST_YMM2] = */ ~0U, + /* [BS3CG1DST_YMM3] = */ ~0U, + /* [BS3CG1DST_YMM4] = */ ~0U, + /* [BS3CG1DST_YMM5] = */ ~0U, + /* [BS3CG1DST_YMM6] = */ ~0U, + /* [BS3CG1DST_YMM7] = */ ~0U, + /* [BS3CG1DST_YMM8] = */ ~0U, + /* [BS3CG1DST_YMM9] = */ ~0U, + /* [BS3CG1DST_YMM10] = */ ~0U, + /* [BS3CG1DST_YMM11] = */ ~0U, + /* [BS3CG1DST_YMM12] = */ ~0U, + /* [BS3CG1DST_YMM13] = */ ~0U, + /* [BS3CG1DST_YMM14] = */ ~0U, + /* [BS3CG1DST_YMM15] = */ ~0U, + + /* [BS3CG1DST_VALUE_XCPT] = */ ~0U, +}; +AssertCompile(RT_ELEMENTS(g_aoffBs3Cg1DstFields) == BS3CG1DST_END); + +/** Destination field names. */ +static const struct { char sz[12]; } g_aszBs3Cg1DstFields[] = +{ + { "INVALID" }, + { "OP1" }, + { "OP2" }, + { "OP3" }, + { "OP4" }, + { "EFL" }, + { "EFL_UND" }, + + { "AL" }, + { "CL" }, + { "DL" }, + { "BL" }, + { "AH" }, + { "CH" }, + { "DH" }, + { "BH" }, + { "SPL" }, + { "BPL" }, + { "SIL" }, + { "DIL" }, + { "R8L" }, + { "R9L" }, + { "R10L" }, + { "R11L" }, + { "R12L" }, + { "R13L" }, + { "R14L" }, + { "R15L" }, + + { "AX" }, + { "CX" }, + { "DX" }, + { "BX" }, + { "SP" }, + { "BP" }, + { "SI" }, + { "DI" }, + { "R8W" }, + { "R9W" }, + { "R10W" }, + { "R11W" }, + { "R12W" }, + { "R13W" }, + { "R14W" }, + { "R15W" }, + + { "EAX" }, + { "ECX" }, + { "EDX" }, + { "EBX" }, + { "ESP" }, + { "EBP" }, + { "ESI" }, + { "EDI" }, + { "R8D" }, + { "R9D" }, + { "R10D" }, + { "R11D" }, + { "R12D" }, + { "R13D" }, + { "R14D" }, + { "R15D" }, + + { "RAX" }, + { "RCX" }, + { "RDX" }, + { "RBX" }, + { "RSP" }, + { "RBP" }, + { "RSI" }, + { "RDI" }, + { "R8" }, + { "R9" }, + { "R10" }, + { "R11" }, + { "R12" }, + { "R13" }, + { "R14" }, + { "R15" }, + + { "OZ_RAX" }, + { "OZ_RCX" }, + { "OZ_RDX" }, + { "OZ_RBX" }, + { "OZ_RSP" }, + { "OZ_RBP" }, + { "OZ_RSI" }, + { "OZ_RDI" }, + { "OZ_R8" }, + { "OZ_R9" }, + { "OZ_R10" }, + { "OZ_R11" }, + { "OZ_R12" }, + { "OZ_R13" }, + { "OZ_R14" }, + { "OZ_R15" }, + + { "CR0" }, + { "CR4" }, + { "XCR0" }, + + { "FCW" }, + { "FSW" }, + { "FTW" }, + { "FOP" }, + { "FPUIP" }, + { "FPUCS" }, + { "FPUDP" }, + { "FPUDS" }, + { "MXCSR" }, + { "ST0" }, + { "ST1" }, + { "ST2" }, + { "ST3" }, + { "ST4" }, + { "ST5" }, + { "ST6" }, + { "ST7" }, + { "MM0" }, + { "MM1" }, + { "MM2" }, + { "MM3" }, + { "MM4" }, + { "MM5" }, + { "MM6" }, + { "MM7" }, + { "MM0_LO_ZX" }, + { "MM1_LO_ZX" }, + { "MM2_LO_ZX" }, + { "MM3_LO_ZX" }, + { "MM4_LO_ZX" }, + { "MM5_LO_ZX" }, + { "MM6_LO_ZX" }, + { "MM7_LO_ZX" }, + { "XMM0" }, + { "XMM1" }, + { "XMM2" }, + { "XMM3" }, + { "XMM4" }, + { "XMM5" }, + { "XMM6" }, + { "XMM7" }, + { "XMM8" }, + { "XMM9" }, + { "XMM10" }, + { "XMM11" }, + { "XMM12" }, + { "XMM13" }, + { "XMM14" }, + { "XMM15" }, + { "XMM0_LO" }, + { "XMM1_LO" }, + { "XMM2_LO" }, + { "XMM3_LO" }, + { "XMM4_LO" }, + { "XMM5_LO" }, + { "XMM6_LO" }, + { "XMM7_LO" }, + { "XMM8_LO" }, + { "XMM9_LO" }, + { "XMM10_LO" }, + { "XMM11_LO" }, + { "XMM12_LO" }, + { "XMM13_LO" }, + { "XMM14_LO" }, + { "XMM15_LO" }, + { "XMM0_HI" }, + { "XMM1_HI" }, + { "XMM2_HI" }, + { "XMM3_HI" }, + { "XMM4_HI" }, + { "XMM5_HI" }, + { "XMM6_HI" }, + { "XMM7_HI" }, + { "XMM8_HI" }, + { "XMM9_HI" }, + { "XMM10_HI" }, + { "XMM11_HI" }, + { "XMM12_HI" }, + { "XMM13_HI" }, + { "XMM14_HI" }, + { "XMM15_HI" }, + { "XMM0_LO_ZX" }, + { "XMM1_LO_ZX" }, + { "XMM2_LO_ZX" }, + { "XMM3_LO_ZX" }, + { "XMM4_LO_ZX" }, + { "XMM5_LO_ZX" }, + { "XMM6_LO_ZX" }, + { "XMM7_LO_ZX" }, + { "XMM8_LO_ZX" }, + { "XMM9_LO_ZX" }, + { "XMM10_LO_ZX" }, + { "XMM11_LO_ZX" }, + { "XMM12_LO_ZX" }, + { "XMM13_LO_ZX" }, + { "XMM14_LO_ZX" }, + { "XMM15_LO_ZX" }, + { "XMM0_DW0" }, + { "XMM1_DW0" }, + { "XMM2_DW0" }, + { "XMM3_DW0" }, + { "XMM4_DW0" }, + { "XMM5_DW0" }, + { "XMM6_DW0" }, + { "XMM7_DW0" }, + { "XMM8_DW0" }, + { "XMM9_DW0" }, + { "XMM10_DW0" }, + { "XMM11_DW0" }, + { "XMM12_DW0" }, + { "XMM13_DW0" }, + { "XMM14_DW0" }, + { "XMM15_DW0" }, + { "XMM0_DW0_ZX" }, + { "XMM1_DW0_ZX" }, + { "XMM2_DW0_ZX" }, + { "XMM3_DW0_ZX" }, + { "XMM4_DW0_ZX" }, + { "XMM5_DW0_ZX" }, + { "XMM6_DW0_ZX" }, + { "XMM7_DW0_ZX" }, + { "XMM8_DW0_ZX" }, + { "XMM9_DW0_ZX" }, + { "XMM10_DW0_ZX" }, + { "XMM11_DW0_ZX" }, + { "XMM12_DW0_ZX" }, + { "XMM13_DW0_ZX" }, + { "XMM14_DW0_ZX" }, + { "XMM15_DW0_ZX" }, + { "XMM0_HI96" }, + { "XMM1_HI96" }, + { "XMM2_HI96" }, + { "XMM3_HI96" }, + { "XMM4_HI96" }, + { "XMM5_HI96" }, + { "XMM6_HI96" }, + { "XMM7_HI96" }, + { "XMM8_HI96" }, + { "XMM9_HI96" }, + { "XMM10_HI96" }, + { "XMM11_HI96" }, + { "XMM12_HI96" }, + { "XMM13_HI96" }, + { "XMM14_HI96" }, + { "XMM15_HI96" }, + { "YMM0" }, + { "YMM1" }, + { "YMM2" }, + { "YMM3" }, + { "YMM4" }, + { "YMM5" }, + { "YMM6" }, + { "YMM7" }, + { "YMM8" }, + { "YMM9" }, + { "YMM10" }, + { "YMM11" }, + { "YMM12" }, + { "YMM13" }, + { "YMM14" }, + { "YMM15" }, + + { "VALXCPT" }, +}; +AssertCompile(RT_ELEMENTS(g_aszBs3Cg1DstFields) >= BS3CG1DST_END); +AssertCompile(RT_ELEMENTS(g_aszBs3Cg1DstFields) == BS3CG1DST_END); + + +#if 0 +static const struct +{ + uint8_t cbPrefixes; + uint8_t abPrefixes[14]; + uint16_t fEffective; +} g_aPrefixVariations[] = +{ + { 0, { 0x00 }, BS3CG1_PF_NONE }, + + { 1, { P_OZ }, BS3CG1_PF_OZ }, + { 1, { P_CS }, BS3CG1_PF_CS }, + { 1, { P_DS }, BS3CG1_PF_DS }, + { 1, { P_ES }, BS3CG1_PF_ES }, + { 1, { P_FS }, BS3CG1_PF_FS }, + { 1, { P_GS }, BS3CG1_PF_GS }, + { 1, { P_SS }, BS3CG1_PF_SS }, + { 1, { P_LK }, BS3CG1_PF_LK }, + + { 2, { P_CS, P_OZ, }, BS3CG1_PF_CS | BS3CFG1_PF_OZ }, + { 2, { P_DS, P_OZ, }, BS3CG1_PF_DS | BS3CFG1_PF_OZ }, + { 2, { P_ES, P_OZ, }, BS3CG1_PF_ES | BS3CFG1_PF_OZ }, + { 2, { P_FS, P_OZ, }, BS3CG1_PF_FS | BS3CFG1_PF_OZ }, + { 2, { P_GS, P_OZ, }, BS3CG1_PF_GS | BS3CFG1_PF_OZ }, + { 2, { P_GS, P_OZ, }, BS3CG1_PF_SS | BS3CFG1_PF_OZ }, + { 2, { P_SS, P_OZ, }, BS3CG1_PF_SS | BS3CFG1_PF_OZ }, + + { 2, { P_OZ, P_CS, }, BS3CG1_PF_CS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_DS, }, BS3CG1_PF_DS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_ES, }, BS3CG1_PF_ES | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_FS, }, BS3CG1_PF_FS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_GS, }, BS3CG1_PF_GS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_GS, }, BS3CG1_PF_SS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_SS, }, BS3CG1_PF_SS | BS3CFG1_PF_OZ }, +}; + +static const uint16_t g_afPfxKindToIgnoredFlags[BS3CG1PFXKIND_END] = +{ + /* [BS3CG1PFXKIND_INVALID] = */ UINT16_MAX, + /* [BS3CG1PFXKIND_MODRM] = */ 0, + /* [BS3CG1PFXKIND_MODRM_NO_OP_SIZES] = */ BS3CG1_PF_OZ | BS3CG1_PF_W, +}; + +#endif + + +/** + * Checks if >= 16 byte SSE alignment are exempted for the exception type. + * + * @returns true / false. + * @param enmXcptType The type to check. + */ +static bool BS3_NEAR_CODE Bs3Cg1XcptTypeIsUnaligned(BS3CG1XCPTTYPE enmXcptType) +{ + switch (enmXcptType) + { + case BS3CG1XCPTTYPE_1: + case BS3CG1XCPTTYPE_2: + case BS3CG1XCPTTYPE_4: + return false; + case BS3CG1XCPTTYPE_NONE: + case BS3CG1XCPTTYPE_3: + case BS3CG1XCPTTYPE_4UA: + case BS3CG1XCPTTYPE_5: + return true; + default: + return false; + } +} + + +/** + * Checks if >= 16 byte AVX alignment are exempted for the exception type. + * + * @returns true / false. + * @param enmXcptType The type to check. + */ +static bool BS3_NEAR_CODE Bs3Cg1XcptTypeIsVexUnaligned(BS3CG1XCPTTYPE enmXcptType) +{ + switch (enmXcptType) + { + case BS3CG1XCPTTYPE_1: + return false; + + case BS3CG1XCPTTYPE_NONE: + case BS3CG1XCPTTYPE_2: + case BS3CG1XCPTTYPE_3: + case BS3CG1XCPTTYPE_4: + case BS3CG1XCPTTYPE_4UA: + case BS3CG1XCPTTYPE_5: + case BS3CG1XCPTTYPE_6: + case BS3CG1XCPTTYPE_11: + case BS3CG1XCPTTYPE_12: + return true; + + default: + return false; + } +} + + +DECLINLINE(unsigned) BS3_NEAR_CODE Bs3Cg1InsertReqPrefix(PBS3CG1STATE pThis, unsigned offDst) +{ + switch (pThis->enmPrefixKind) + { + case BS3CG1PFXKIND_REQ_66: + pThis->abCurInstr[offDst] = 0x66; + break; + case BS3CG1PFXKIND_REQ_F2: + pThis->abCurInstr[offDst] = 0xf2; + break; + case BS3CG1PFXKIND_REQ_F3: + pThis->abCurInstr[offDst] = 0xf3; + break; + default: + return offDst; + } + return offDst + 1; +} + + +DECLINLINE(unsigned) BS3_NEAR_CODE Bs3Cg1InsertOpcodes(PBS3CG1STATE pThis, unsigned offDst) +{ + switch (pThis->cbOpcodes) + { + case 4: pThis->abCurInstr[offDst + 3] = pThis->abOpcodes[3]; + case 3: pThis->abCurInstr[offDst + 2] = pThis->abOpcodes[2]; + case 2: pThis->abCurInstr[offDst + 1] = pThis->abOpcodes[1]; + case 1: pThis->abCurInstr[offDst] = pThis->abOpcodes[0]; + return offDst + pThis->cbOpcodes; + + default: + BS3_ASSERT(0); + return 0; + } +} + + +/** + * Inserts a ModR/M byte with mod=3 and set the two idxFields members. + * + * @returns off + 1. + * @param pThis The state. + * @param off Current instruction offset. + * @param uReg Register index for ModR/M.reg. + * @param uRegMem Register index for ModR/M.rm. + */ +static unsigned Bs3Cg1InsertModRmWithRegFields(PBS3CG1STATE pThis, unsigned off, uint8_t uReg, uint8_t uRegMem) +{ + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, uReg & 7, uRegMem & 7); + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + uReg; + pThis->aOperands[pThis->iRmOp ].idxField = pThis->aOperands[pThis->iRmOp ].idxFieldBase + uRegMem; + return off; +} + + + +/** + * Cleans up state and context changes made by the encoder. + * + * @param pThis The state. + */ +static void BS3_NEAR_CODE Bs3Cg1EncodeCleanup(PBS3CG1STATE pThis) +{ + /* Restore the DS registers in the contexts. */ + unsigned iRing = 4; + while (iRing-- > 0) + pThis->aInitialCtxs[iRing].ds = pThis->aSavedSegRegs[iRing].ds; + + switch (pThis->enmEncoding) + { + /* Most encodings currently doesn't need any special cleaning up. */ + default: + return; + } +} + + +static unsigned BS3_NEAR_CODE Bs3Cfg1EncodeMemMod0Disp(PBS3CG1STATE pThis, bool fAddrOverride, unsigned off, uint8_t iReg, + uint8_t cbOp, uint8_t cbMisalign, BS3CG1OPLOC enmLocation) +{ + pThis->aOperands[pThis->iRmOp].idxField = BS3CG1DST_INVALID; + pThis->aOperands[pThis->iRmOp].enmLocation = enmLocation; + pThis->aOperands[pThis->iRmOp].cbOp = cbOp; + pThis->aOperands[pThis->iRmOp].off = cbOp + cbMisalign; + + if ( BS3_MODE_IS_16BIT_CODE(pThis->bMode) + || (fAddrOverride && BS3_MODE_IS_32BIT_CODE(pThis->bMode)) ) + { + /* + * 16-bit code doing 16-bit or 32-bit addressing, + * or 32-bit code doing 16-bit addressing. + */ + unsigned iRing = 4; + if (BS3_MODE_IS_RM_OR_V86(pThis->bMode)) + while (iRing-- > 0) + pThis->aInitialCtxs[iRing].ds = pThis->DataPgFar.sel; + else + while (iRing-- > 0) + pThis->aInitialCtxs[iRing].ds = pThis->DataPgFar.sel | iRing; + if (!fAddrOverride || BS3_MODE_IS_32BIT_CODE(pThis->bMode)) + { + pThis->abCurInstr[off++] = X86_MODRM_MAKE(0, iReg, 6 /*disp16*/); + *(uint16_t *)&pThis->abCurInstr[off] = pThis->DataPgFar.off + X86_PAGE_SIZE - cbOp - cbMisalign; + off += 2; + } + else + { + pThis->abCurInstr[off++] = X86_MODRM_MAKE(0, iReg, 5 /*disp32*/); + *(uint32_t *)&pThis->abCurInstr[off] = pThis->DataPgFar.off + X86_PAGE_SIZE - cbOp - cbMisalign; + off += 4; + } + } + else + { + /* + * 32-bit code doing 32-bit addressing, + * or 64-bit code doing either 64-bit or 32-bit addressing. + */ + pThis->abCurInstr[off++] = X86_MODRM_MAKE(0, iReg, 5 /*disp32*/); + *(uint32_t *)&pThis->abCurInstr[off] = BS3_FP_OFF(pThis->pbDataPg) + X86_PAGE_SIZE - cbOp - cbMisalign; + +#if ARCH_BITS == 64 + /* In 64-bit mode we always have a rip relative encoding regardless of fAddrOverride. */ + if (BS3CG1_IS_64BIT_TARGET(pThis)) + *(uint32_t *)&pThis->abCurInstr[off] -= BS3_FP_OFF(&pThis->pbCodePg[X86_PAGE_SIZE]); +#endif + off += 4; + } + + /* + * Fill the memory with 0xcc. + */ + switch (cbOp + cbMisalign) + { + case 8: pThis->pbDataPg[X86_PAGE_SIZE - 8] = 0xcc; RT_FALL_THRU(); + case 7: pThis->pbDataPg[X86_PAGE_SIZE - 7] = 0xcc; RT_FALL_THRU(); + case 6: pThis->pbDataPg[X86_PAGE_SIZE - 6] = 0xcc; RT_FALL_THRU(); + case 5: pThis->pbDataPg[X86_PAGE_SIZE - 5] = 0xcc; RT_FALL_THRU(); + case 4: pThis->pbDataPg[X86_PAGE_SIZE - 4] = 0xcc; RT_FALL_THRU(); + case 3: pThis->pbDataPg[X86_PAGE_SIZE - 3] = 0xcc; RT_FALL_THRU(); + case 2: pThis->pbDataPg[X86_PAGE_SIZE - 2] = 0xcc; RT_FALL_THRU(); + case 1: pThis->pbDataPg[X86_PAGE_SIZE - 1] = 0xcc; RT_FALL_THRU(); + case 0: break; + default: + { + BS3CG1_DPRINTF(("Bs3MemSet(%p,%#x,%#x)\n", &pThis->pbDataPg[X86_PAGE_SIZE - cbOp - cbMisalign], 0xcc, cbOp - cbMisalign)); + Bs3MemSet(&pThis->pbDataPg[X86_PAGE_SIZE - cbOp - cbMisalign], 0xcc, cbOp - cbMisalign); + break; + } + } + + return off; +} + + +#if 0 /* unused */ +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegField(PBS3CG1STATE pThis, bool fAddrOverride, unsigned off, uint8_t iReg, + uint8_t cbOp, uint8_t cbMisalign, BS3CG1OPLOC enmLocation) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, fAddrOverride, off, iReg & 7, cbOp, cbMisalign, enmLocation); +} +#endif + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(PBS3CG1STATE pThis, unsigned off, uint8_t iReg) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, false /*fAddrOverride*/, off, iReg & 7, + pThis->aOperands[pThis->iRmOp].cbOp, + 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsAddrOverride(PBS3CG1STATE pThis, unsigned off, uint8_t iReg) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, true /*fAddrOverride*/, off, iReg & 7, + pThis->aOperands[pThis->iRmOp].cbOp, + 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(PBS3CG1STATE pThis, unsigned off, uint8_t iReg, uint8_t cbMisalign) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, false /*fAddrOverride*/, off, iReg & 7, + pThis->aOperands[pThis->iRmOp].cbOp, + cbMisalign, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(PBS3CG1STATE pThis, unsigned off, uint8_t iReg, uint8_t cbOp) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, false /*fAddrOverride*/, off, iReg & 7, cbOp, 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(PBS3CG1STATE pThis, unsigned off, uint8_t iReg, uint8_t cbOp) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, true /*fAddrOverride*/, off, iReg & 7, cbOp, 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + + +/** The modrm.reg value is taken from the instruction byte at @a off. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(PBS3CG1STATE pThis, unsigned off) +{ + return Bs3Cfg1EncodeMemMod0Disp(pThis, false /*fAddrOverride*/, off, + (pThis->abCurInstr[off] & X86_MODRM_REG_MASK) >> X86_MODRM_REG_SHIFT, + pThis->aOperands[pThis->iRmOp].cbOp, + 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Eb_Gb_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + /* Start by reg,reg encoding. */ + case 0: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_xAX, X86_GREG_xCX); + break; + case 1: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5 /*CH*/); + break; + case 2: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80386) + return 0; + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 6 /*DH*/); + break; + /* Tests with address overrides go last! */ + case 3: + pThis->abCurInstr[0] = P_AZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsAddrOverride(pThis, off, 7 /*BH*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Gv_Ev__OR__MODRM_Ev_Gv(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + unsigned cbOp; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_xBX, X86_GREG_xDX); + cbOp = pThis->cbOpDefault; + break; + case 1: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + cbOp = pThis->cbOpDefault; + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(pThis, off, X86_GREG_xBP, cbOp); + break; + case 2: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80386) + return 0; + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_xAX, X86_GREG_xCX); + cbOp = pThis->cbOpOvrd66; + break; + case 3: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + cbOp = pThis->cbOpOvrd66; + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(pThis, off, X86_GREG_xSI, cbOp); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 : 0; + break; + case 4: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_xBX, X86_GREG_xDX); + cbOp = pThis->cbOpOvrdRexW; + break; + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RB_; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_x14, X86_GREG_x12); + cbOp = pThis->cbOpDefault; + break; + /* Tests with address overrides go last!*/ + case 6: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + pThis->abCurInstr[0] = P_AZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + cbOp = pThis->cbOpDefault; + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(pThis, off, X86_GREG_xDI, cbOp); + break; + case 7: + pThis->abCurInstr[0] = P_OZ; + pThis->abCurInstr[1] = P_AZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 2)); + cbOp = pThis->cbOpOvrd66; + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(pThis, off, X86_GREG_xDI, cbOp); + break; + default: + return 0; + } + pThis->aOperands[0].cbOp = cbOp; + pThis->aOperands[1].cbOp = cbOp; + pThis->cbOperand = cbOp; + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Pq_WO_Qq(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 7); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 /*no +8*/, 2 /*no +8*/); + break; +#endif + case 3: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 /*iReg - no +8*/); + break; +#endif + + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Pq_WO_Uq(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 /*no+8*/, 2 + 8); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_PdZx_WO_Ed_WZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 /*no +8*/, 2+8); + break; +#endif + case 3: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 /*iReg*/); + break; +#endif + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ +#if ARCH_BITS == 64 + if (BS3CG1_IS_64BIT_TARGET(pThis)) + { + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 /*no +8*/, 2+8); + break; + case 3: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + break; + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 /*iReg*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; + } +#endif + return 0; +} + + +/* Differs from Bs3Cg1EncodeNext_MODRM_PdZx_WO_Ed_WZ in that REX.R isn't ignored. */ +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vd_WO_Ed_WZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6+8, 2+8); + break; +#endif + case 3: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7+8 /*iReg*/); + break; +#endif + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/* Differs from Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ in that REX.R isn't ignored. */ +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vq_WO_Eq_WNZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ +#if ARCH_BITS == 64 + if (BS3CG1_IS_64BIT_TARGET(pThis)) + { + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6+8, 2+8); + break; + case 4: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + break; + case 6: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7+8 /*iReg*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; + } +#endif + return 0; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vsomething_Usomething_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 2, 2); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 3+8, 7+8); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertModRmWithRegFields(pThis, Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)), 1, 0); + break; + case 1: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2 /*iReg*/); + break; + case 2: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vsomething_Nsomething(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 7); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 + 8, 7 /*no +8*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Gv_RO_Ma(PBS3CG1STATE pThis, unsigned iEncoding) /* bound instr */ +{ + unsigned off; + unsigned cbOp = BS3_MODE_IS_16BIT_CODE(pThis->bMode) ? 2 : 4; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(pThis, off, X86_GREG_xBP, cbOp * 2); + break; + case 1: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80386) + return 0; + cbOp = cbOp == 2 ? 4 : 2; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(pThis, off, X86_GREG_xBP, cbOp * 2); + break; + case 2: + pThis->abCurInstr[0] = P_AZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(pThis, off, X86_GREG_xBP, cbOp * 2); + break; + case 3: + cbOp = cbOp == 2 ? 4 : 2; + pThis->abCurInstr[0] = P_AZ; + pThis->abCurInstr[1] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 2)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(pThis, off, X86_GREG_xBP, cbOp * 2); + break; + default: + return 0; + } + pThis->aOperands[pThis->iRegOp].cbOp = cbOp; + pThis->cbOperand = cbOp; + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Msomething(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Msomething_Psomething(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 /*iReg - no +8*/); + break; +#endif + + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2 /*iReg*/); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 2 /*iReg*/, 1 /*cbMisalign*/ ); + if (!Bs3Cg1XcptTypeIsUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__R__; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2+8 /*iReg*/); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_FIXED(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + pThis->cbCurInstr = off; + break; + default: + return 0; + } + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_FIXED_AL_Ib(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + pThis->aOperands[1].off = (uint8_t)off; + pThis->abCurInstr[off++] = 0xff; + pThis->cbCurInstr = off; + break; + default: + return 0; + } + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_FIXED_rAX_Iz(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + unsigned cbOp; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + pThis->aOperands[1].off = (uint8_t)off; + cbOp = pThis->cbOpDefault; + if (cbOp == 2) + *(uint16_t *)&pThis->abCurInstr[off] = UINT16_MAX; + else + *(uint32_t *)&pThis->abCurInstr[off] = UINT32_MAX; + off += cbOp; + pThis->aOperands[0].cbOp = cbOp; + pThis->aOperands[1].cbOp = cbOp; + pThis->cbOperand = cbOp; + break; + case 1: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80386) + return 0; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + pThis->aOperands[1].off = (uint8_t)off; + cbOp = pThis->cbOpOvrd66; + if (cbOp == 2) + *(uint16_t *)&pThis->abCurInstr[off] = UINT16_MAX; + else + *(uint32_t *)&pThis->abCurInstr[off] = UINT32_MAX; + off += cbOp; + pThis->aOperands[0].cbOp = cbOp; + pThis->aOperands[1].cbOp = cbOp; + pThis->cbOperand = cbOp; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->aOperands[1].off = (uint8_t)off; + *(uint32_t *)&pThis->abCurInstr[off] = UINT32_MAX; + off += 4; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 4; + pThis->cbOperand = 8; + break; + default: + return 0; + + /* IMAGE PADDING - workaround for "rd err" - remove later! */ + case 4: + ASMHalt(); + ASMHalt(); + ASMHalt(); + return 0; + + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_MOD_EQ_3(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + if (iEncoding < 8) + { + off = Bs3Cg1InsertReqPrefix(pThis, 0); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, iEncoding, 1); + } + else if (iEncoding < 16) + { + off = Bs3Cg1InsertReqPrefix(pThis, 0); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, 0, iEncoding & 7); + } + else + return 0; + pThis->cbCurInstr = off; + + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_MOD_NE_3(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + if (iEncoding < 3) + { + off = Bs3Cg1InsertReqPrefix(pThis, 0); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(iEncoding, 0, 1); + if (iEncoding >= 1) + pThis->abCurInstr[off++] = 0x7f; + if (iEncoding == 2) + { + pThis->abCurInstr[off++] = 0x5f; + if (!BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + { + pThis->abCurInstr[off++] = 0x3f; + pThis->abCurInstr[off++] = 0x1f; + } + } + } + else + return 0; + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/* + * + * VEX + * VEX + * VEX + * + */ +#ifdef BS3CG1_WITH_VEX + +/** + * Inserts a 3-byte VEX prefix. + * + * @returns New offDst value. + * @param pThis The state. + * @param offDst The current instruction offset. + * @param uVexL The VEX.L value. + * @param uVexV The VEX.V value (caller inverted it already). + * @param uVexR The VEX.R value (caller inverted it already). + * @param uVexX The VEX.X value (caller inverted it already). + * @param uVexB The VEX.B value (caller inverted it already). + * @param uVexW The VEX.W value (straight). + */ +DECLINLINE(unsigned) BS3_NEAR_CODE Bs3Cg1InsertVex3bPrefix(PBS3CG1STATE pThis, unsigned offDst, uint8_t uVexV, uint8_t uVexL, + uint8_t uVexR, uint8_t uVexX, uint8_t uVexB, uint8_t uVexW) +{ + uint8_t b1; + uint8_t b2; + b1 = uVexR << 7; + b1 |= uVexX << 6; + b1 |= uVexB << 5; + b1 |= pThis->uOpcodeMap; + b2 = uVexV << 3; + b2 |= uVexW << 7; + b2 |= uVexL << 2; + switch (pThis->enmPrefixKind) + { + case BS3CG1PFXKIND_NO_F2_F3_66: b2 |= 0; break; + case BS3CG1PFXKIND_REQ_66: b2 |= 1; break; + case BS3CG1PFXKIND_REQ_F3: b2 |= 2; break; + case BS3CG1PFXKIND_REQ_F2: b2 |= 3; break; + default: + Bs3TestFailedF("enmPrefixKind=%d not supported for VEX!\n", pThis->enmPrefixKind); + break; + } + + pThis->abCurInstr[offDst] = 0xc4; /* vex3 */ + pThis->abCurInstr[offDst + 1] = b1; + pThis->abCurInstr[offDst + 2] = b2; + pThis->uVexL = uVexL; + return offDst + 3; +} + + +/** + * Inserts a 2-byte VEX prefix. + * + * @note Will switch to 3-byte VEX prefix if uOpcodeMap isn't one. + * + * @returns New offDst value. + * @param pThis The state. + * @param offDst The current instruction offset. + * @param uVexL The VEX.L value. + * @param uVexV The VEX.V value (caller inverted it already). + * @param uVexR The VEX.R value (caller inverted it already). + */ +DECLINLINE(unsigned) BS3_NEAR_CODE Bs3Cg1InsertVex2bPrefix(PBS3CG1STATE pThis, unsigned offDst, + uint8_t uVexV, uint8_t uVexL, uint8_t uVexR) +{ + if (pThis->uOpcodeMap == 1) + { + uint8_t b = uVexR << 7; + b |= uVexV << 3; + b |= uVexL << 2; + switch (pThis->enmPrefixKind) + { + case BS3CG1PFXKIND_NO_F2_F3_66: b |= 0; break; + case BS3CG1PFXKIND_REQ_66: b |= 1; break; + case BS3CG1PFXKIND_REQ_F3: b |= 2; break; + case BS3CG1PFXKIND_REQ_F2: b |= 3; break; + default: + Bs3TestFailedF("enmPrefixKind=%d not supported for VEX!\n"); + break; + } + + pThis->abCurInstr[offDst] = 0xc5; /* vex2 */ + pThis->abCurInstr[offDst + 1] = b; + pThis->uVexL = uVexL; + return offDst + 2; + } + return Bs3Cg1InsertVex3bPrefix(pThis, offDst, uVexV, uVexL, uVexR, 1 /*uVexX*/, 1 /*uVexB*/, 0/*uVexW*/); +} + + +/** + * Inserts a ModR/M byte with mod=3 and set the two idxFields members. + * + * @returns off + 1. + * @param pThis The state. + * @param off Current instruction offset. + * @param uReg Register index for ModR/M.reg. + * @param uRegMem Register index for ModR/M.rm. + * @param uVexVvvv The VEX.vvvv register. + */ +static unsigned Bs3Cg1InsertModRmWithRegFieldsAndVvvv(PBS3CG1STATE pThis, unsigned off, + uint8_t uReg, uint8_t uRegMem, uint8_t uVexVvvv) +{ + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, uReg & 7, uRegMem & 7); + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + uReg; + pThis->aOperands[1 ].idxField = pThis->aOperands[1 ].idxFieldBase + uVexVvvv; + pThis->aOperands[pThis->iRmOp ].idxField = pThis->aOperands[pThis->iRmOp ].idxFieldBase + uRegMem; + return off; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_Vd_WO_Ed_WZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + break; + case 2: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L-invalid*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + pThis->fInvalidEncoding = true; + break; + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xe /*~V-invalid*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 0 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6+8, 2+8); + break; +#endif + case 5: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 4 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 : 0; + break; +#if ARCH_BITS == 64 + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4+8 /*iReg*/); + break; + case 9: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8 /*iReg*/); + iEncoding += 2; + break; +#endif + case 10: /* VEX.W is ignored in 32-bit mode. flag? */ + BS3_ASSERT(!BS3CG1_IS_64BIT_TARGET(pThis)); + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/* Differs from Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ in that REX.R isn't ignored. */ +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_Vq_WO_Eq_WNZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ +#if ARCH_BITS == 64 + if (BS3CG1_IS_64BIT_TARGET(pThis)) + { + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + break; + case 1: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L-invalid*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + pThis->fInvalidEncoding = true; + break; + case 2: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xe /*~V-invalid*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + pThis->fInvalidEncoding = true; + break; + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 0 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6+8, 2+8); + break; + case 4: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 4 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 : 0; + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4+8 /*iReg*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; + } +#endif + return 0; +} + + +/** + * Wip - VEX.W ignored. + * Lig - VEX.L ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0x8 /*~V*/, 1 /*L-ignored*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 3, 1, 7); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: +#if ARCH_BITS == 64 + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 3+8, 2, 15); + break; +#endif + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - ignored*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xc /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 3); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_HdqCsomething_Usomething_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0x8 /*~V*/, 1 /*L-ignored*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 3, 1, 7); + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: +#if ARCH_BITS == 64 + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 3+8, 2, 15); + break; +#endif + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - ignored*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + pThis->fInvalidEncoding = true; + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xc /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 3); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 20: /* Switch to 256-bit operands. */ + pThis->aOperands[pThis->iRegOp].idxFieldBase = BS3CG1DST_YMM0; + pThis->aOperands[pThis->iRegOp].cbOp = 32; + pThis->aOperands[pThis->iRmOp ].cbOp = 32; + RT_FALL_THRU(); + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 1: + case 21: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + break; +#endif + case 2: + case 22: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->fInvalidEncoding = true; + break; + case 3: + case 23: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 4: + case 24: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 5: + case 25: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + break; + case 6: + case 26: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 7: + case 27: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + break; +#endif + case 8: + case 28: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->fInvalidEncoding = true; + break; + case 9: + case 29: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 7 /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->fInvalidEncoding = true; + iEncoding += 10; + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + + +/** + * Wip - VEX.W ignored. + * Lig - VEX.L ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - ignored*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - ignored*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + break; +#endif + case 3: + iEncoding = 3; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->fInvalidEncoding = true; + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L-ignored*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + break; + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + break; +#endif + case 10: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->fInvalidEncoding = true; + break; + case 11: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 7 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->fInvalidEncoding = true; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + * L0 - VEX.L must be zero. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lmbz_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - invalid*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7); + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + break; + case 3: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - invalid*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5 + 8); + pThis->fInvalidEncoding = true; + break; +#endif + case 4: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->fInvalidEncoding = true; + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - invalid*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + pThis->fInvalidEncoding = true; + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 10: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + break; +#endif + case 11: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->fInvalidEncoding = true; + break; + case 12: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 7 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->fInvalidEncoding = true; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lxx_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding, uint8_t uVexL) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + break; +#endif + case 2: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, uVexL, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->fInvalidEncoding = true; + break; + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + break; +#endif + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->fInvalidEncoding = true; + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 7 /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->fInvalidEncoding = true; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + * L0 - VEX.L is zero (encoding may exist where it isn't). + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_L0_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + return Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lxx_OR_ViceVersa(pThis, iEncoding, 0 /*uVexL*/); +} + + +/** + * Wip - VEX.W ignored. + * L1 - VEX.L is one (encoding may exist where it isn't). + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_L1_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + return Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lxx_OR_ViceVersa(pThis, iEncoding, 1 /*uVexL*/); +} + + + +/** + * Wip - VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Msomething_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xc /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 3; + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0x1 /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 14; + break; +#endif + case 3: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 1; + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L-ignored*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + pThis->fInvalidEncoding = true; + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + break; + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + break; +#endif + case 10: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 1 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + (BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + pThis->fInvalidEncoding = true; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_Md_WO(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + break; + case 1: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + break; + case 2: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0x7 /*~V-invalid*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 4: + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 5: + pThis->abCurInstr[0] = P_RZ; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 6: + pThis->abCurInstr[0] = P_RN; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 8: + pThis->abCurInstr[0] = REX_____; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; +#endif + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip = VEX.W ignored. + * Lmbz = VEX.L must be zero. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_Lmbz_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + /* 128-bit wide stuff goes first, then we'll update the operand widths afterwards. */ + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + + case 1: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + break; + case 2: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W - ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 5, 4); + break; + case 3: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 3 /*iReg*/); + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W - ignored */); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 3 /*iReg*/); + break; + case 6: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsVexUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsVexUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + /* 128-bit invalid encodings: */ + case 8: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, 0 /*L*/, 1 /*~R*/); /* Bad V value */ + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + pThis->fInvalidEncoding = true; + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + iEncoding = 20-1; + break; + + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip = VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + + switch (iEncoding) + { + case 20: /* switch to 256-bit */ + pThis->aOperands[pThis->iRmOp ].cbOp = 32; + pThis->aOperands[pThis->iRmOp ].idxFieldBase = BS3CG1DST_YMM0; + pThis->aOperands[pThis->iRegOp].cbOp = 32; + pThis->aOperands[pThis->iRegOp].idxFieldBase = BS3CG1DST_YMM0; + RT_FALL_THRU(); + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + + case 1: + case 21: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + break; + case 2: + case 22: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W - ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 5, 4); + break; + case 3: + case 23: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2 /*iReg*/); + break; + case 4: + case 24: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 3 /*iReg*/); + break; + case 5: + case 25: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W - ignored */); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 3 /*iReg*/); + break; + case 6: + case 26: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsVexUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + case 7: + case 27: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsVexUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + /* invalid encodings: */ + case 8: + case 28: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); /* Bad V value */ + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + pThis->fInvalidEncoding = true; + break; + case 9: + case 29: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + break; + + case 10: + case 30: + pThis->abCurInstr[0] = P_RN; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + break; + case 11: + case 31: + pThis->abCurInstr[0] = P_RZ; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + break; + case 12: + case 32: + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + break; + case 13: + case 33: + pThis->abCurInstr[0] = P_LK; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 + 4 : 0; + break; + +#if ARCH_BITS == 64 + /* 64-bit mode registers */ + case 14: + case 34: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 3+8, 4); + break; + case 15: + case 35: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 0 /*~R*/, 1 /*~X*/, 0 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1+8, 4+8); + iEncoding += 4; + break; +#endif + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +//static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_FIXED(PBS3CG1STATE pThis, unsigned iEncoding) +//{ +// unsigned off; +// if (iEncoding == 0) +// off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); +// else if (iEncoding == 0) +// off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); +// else +// return 0; +// pThis->cbCurInstr = off; +// return iEncoding + 1; +//} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_MOD_EQ_3(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + if (iEncoding < 8) + { + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, iEncoding, 1); + } + else if (iEncoding < 16) + { + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, iEncoding & 7, 1); + } + else if (iEncoding < 24) + { + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, 0, iEncoding & 7); + } + else if (iEncoding < 32) + { + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, (iEncoding & 3) != 0 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, (iEncoding & 2) != 0 /*L*/, 1 /*~R*/, 1 /*~X*/, + 1 /*~B*/, (iEncoding & 4) != 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, 0, iEncoding & 7); + } + else + return 0; + pThis->cbCurInstr = off; + + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_MOD_NE_3(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + if (iEncoding < 8) + { + unsigned iMod = iEncoding % 3; + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, (iEncoding & 2) != 0 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, (iEncoding & 2) != 0 /*L*/, 1 /*~R*/, + 1 /*~X*/, 1 /*~B*/, (iEncoding & 4) != 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(iMod, 0, 1); + if (iMod >= 1) + pThis->abCurInstr[off++] = 0x7f; + if (iMod == 2) + { + pThis->abCurInstr[off++] = 0x5f; + if (!BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + { + pThis->abCurInstr[off++] = 0x3f; + pThis->abCurInstr[off++] = 0x1f; + } + } + } + else + return 0; + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM(PBS3CG1STATE pThis, unsigned iEncoding) +{ + const unsigned cFirstEncodings = 32; + if (iEncoding < cFirstEncodings) + { + unsigned iRet = Bs3Cg1EncodeNext_VEX_MODRM_MOD_EQ_3(pThis, iEncoding); + BS3_ASSERT(iRet > iEncoding); + return iRet; + } + return Bs3Cg1EncodeNext_VEX_MODRM_MOD_NE_3(pThis, iEncoding - cFirstEncodings) + cFirstEncodings; +} + +#endif /* BS3CG1_WITH_VEX */ + + +/** + * Encodes the next instruction. + * + * @returns Next iEncoding value. Returns @a iEncoding unchanged to indicate + * that there are no more encodings to test. + * @param pThis The state. + * @param iEncoding The encoding to produce. Meaning is specific to + * each BS3CG1ENC_XXX value and should be considered + * internal. + */ +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext(PBS3CG1STATE pThis, unsigned iEncoding) +{ + pThis->bAlignmentXcpt = UINT8_MAX; + pThis->uVexL = UINT8_MAX; + if (pThis->pfnEncoder) + return pThis->pfnEncoder(pThis, iEncoding); + + Bs3TestFailedF("Internal error! BS3CG1ENC_XXX = %u not implemented", pThis->enmEncoding); + return iEncoding; +} + + +/** + * Prepares doing instruction encodings. + * + * This is in part specific to how the instruction is encoded, but generally it + * sets up basic operand values that doesn't change (much) when Bs3Cg1EncodeNext + * is called from within the loop. + * + * @returns Success indicator (true/false). + * @param pThis The state. + */ +#define Bs3Cg1EncodePrep BS3_CMN_NM(Bs3Cg1EncodePrep) +bool BS3_NEAR_CODE Bs3Cg1EncodePrep(PBS3CG1STATE pThis) +{ + unsigned i = 4; + while (i-- > 0) + pThis->aSavedSegRegs[i].ds = pThis->aInitialCtxs[i].ds; + + i = RT_ELEMENTS(pThis->aOperands); + while (i-- > 0) + { + pThis->aOperands[i].enmLocationReg = BS3CG1OPLOC_INVALID; + pThis->aOperands[i].enmLocationMem = BS3CG1OPLOC_INVALID; + pThis->aOperands[i].idxFieldBase = BS3CG1DST_INVALID; + } + + pThis->iRmOp = RT_ELEMENTS(pThis->aOperands) - 1; + pThis->iRegOp = RT_ELEMENTS(pThis->aOperands) - 1; + pThis->fSameRingNotOkay = false; + pThis->cbOperand = 0; + pThis->pfnEncoder = NULL; + + switch (pThis->enmEncoding) + { + case BS3CG1ENC_MODRM_Eb_Gb: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Eb_Gb_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 1; + pThis->aOperands[1].cbOp = 1; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_AL; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_AL; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_RW; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Ev_Gv: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Gv_Ev__OR__MODRM_Ev_Gv; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->cbOperand = 2; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_OZ_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_OZ_RAX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_RW; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Ed_WO_Pd_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_PdZx_WO_Ed_WZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Eq_WO_Pq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Ed_WO_Vd_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vd_WO_Ed_WZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Eq_WO_Vq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vq_WO_Eq_WNZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Gb_Eb: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Eb_Gb_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 1; + pThis->aOperands[1].cbOp = 1; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_AL; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_AL; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Gv_Ev: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Gv_Ev__OR__MODRM_Ev_Gv; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->cbOperand = 2; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_OZ_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_OZ_RAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Gv_RO_Ma: /* bound instr */ + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Gv_RO_Ma; + pThis->iRmOp = 1; + pThis->iRegOp = 0; + pThis->cbOperand = 2; + pThis->aOperands[0].cbOp = 2; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_OZ_RAX; + break; + + case BS3CG1ENC_MODRM_Wss_WO_Vss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_DW0; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Wsd_WO_Vsd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_WqZxReg_WO_Vq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Wps_WO_Vps: + case BS3CG1ENC_MODRM_Wpd_WO_Vpd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Vdq_WO_Mdq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_MODRM_Vdq_WO_Wdq: + case BS3CG1ENC_MODRM_Vpd_WO_Wpd: + case BS3CG1ENC_MODRM_Vps_WO_Wps: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Pq_WO_Qq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Pq_WO_Qq; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Pq_WO_Uq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Pq_WO_Uq; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; /* reg only */ + break; + + case BS3CG1ENC_MODRM_PdZx_WO_Ed_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_PdZx_WO_Ed_WZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_MM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Pq_WO_Eq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_VdZx_WO_Ed_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vd_WO_Ed_WZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_VqZx_WO_Eq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vq_WO_Eq_WNZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Vq_WO_UqHi: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Usomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_VqHi_WO_Uq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Usomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_VqHi_WO_Mq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Vq_WO_Mq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_VssZx_WO_Wss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_MODRM_VqZx_WO_Nq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Nsomething; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + break; + + case BS3CG1ENC_MODRM_VsdZx_WO_Wsd: + case BS3CG1ENC_MODRM_VqZx_WO_Wq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_MODRM_Mb_RO: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 1; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Md_RO: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Md_WO: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + break; + + case BS3CG1ENC_MODRM_Mdq_WO_Vdq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_MODRM_Mq_WO_Pq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Psomething; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Mq_WO_Vq: + case BS3CG1ENC_MODRM_Mq_WO_VqHi: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = pThis->enmEncoding == BS3CG1ENC_MODRM_Mq_WO_Vq + ? BS3CG1DST_XMM0_LO : BS3CG1DST_XMM0_HI; + break; + + case BS3CG1ENC_MODRM_Mps_WO_Vps: + case BS3CG1ENC_MODRM_Mpd_WO_Vpd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_FIXED: + pThis->pfnEncoder = Bs3Cg1EncodeNext_FIXED; + break; + + case BS3CG1ENC_FIXED_AL_Ib: + pThis->pfnEncoder = Bs3Cg1EncodeNext_FIXED_AL_Ib; + pThis->aOperands[0].cbOp = 1; + pThis->aOperands[1].cbOp = 1; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_IMM; + pThis->aOperands[0].idxField = BS3CG1DST_AL; + pThis->aOperands[1].idxField = BS3CG1DST_INVALID; + break; + + case BS3CG1ENC_FIXED_rAX_Iz: + pThis->pfnEncoder = Bs3Cg1EncodeNext_FIXED_rAX_Iz; + pThis->aOperands[0].cbOp = 2; + pThis->aOperands[1].cbOp = 2; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_IMM; + pThis->aOperands[0].idxField = BS3CG1DST_OZ_RAX; + pThis->aOperands[1].idxField = BS3CG1DST_INVALID; + break; + + /* Unused or invalid instructions mostly. */ + case BS3CG1ENC_MODRM_MOD_EQ_3: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_MOD_EQ_3; + break; + case BS3CG1ENC_MODRM_MOD_NE_3: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_MOD_NE_3; + break; + +#ifdef BS3CG1_WITH_VEX + + case BS3CG1ENC_VEX_MODRM_Vd_WO_Ed_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Vd_WO_Ed_WZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_VEX_MODRM_Vq_WO_Eq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Vq_WO_Eq_WNZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_VEX_MODRM_Vps_WO_Wps: + case BS3CG1ENC_VEX_MODRM_Vpd_WO_Wpd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_VssZx_WO_Md: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 1; + pThis->iRegOp = 0; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_INVALID; + break; + + case BS3CG1ENC_VEX_MODRM_Vss_WO_HssHi_Uss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 2; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 12; + pThis->aOperands[2].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI96; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_DW0; + break; + + case BS3CG1ENC_VEX_MODRM_VsdZx_WO_Mq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 1; + pThis->iRegOp = 0; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_INVALID; + break; + + case BS3CG1ENC_VEX_MODRM_Vx_WO_Mx_L0: + BS3_ASSERT(!(pThis->fFlags & BS3CG1INSTR_F_VEX_L_ZERO)); + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_L0_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Vx_WO_Mx_L1: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_L1_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 32; + pThis->aOperands[1].cbOp = 32; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_YMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Vsd_WO_HsdHi_Usd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 2; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[2].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Vq_WO_HqHi_UqHi: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_HdqCsomething_Usomething_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 2; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[2].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_HI; + break; + + case BS3CG1ENC_VEX_MODRM_Vq_WO_HqHi_Mq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Msomething_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 2; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[2].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_INVALID; + break; + + case BS3CG1ENC_VEX_MODRM_Vq_WO_Wq: + BS3_ASSERT(pThis->fFlags & BS3CG1INSTR_F_VEX_L_ZERO); + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_Lmbz_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Vx_WO_Wx: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Ed_WO_Vd_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Vd_WO_Ed_WZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_DW0_ZX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_VEX_MODRM_Eq_WO_Vq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Vq_WO_Eq_WNZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_VEX_MODRM_Md_WO: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Md_WO; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + break; + + case BS3CG1ENC_VEX_MODRM_Md_WO_Vss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_INVALID; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_DW0; + break; + + case BS3CG1ENC_VEX_MODRM_Mq_WO_Vq: + BS3_ASSERT(pThis->fFlags & (BS3CG1INSTR_F_VEX_L_ZERO | BS3CG1INSTR_F_VEX_L_IGNORED)); + pThis->pfnEncoder = pThis->fFlags & BS3CG1INSTR_F_VEX_L_ZERO + ? Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lmbz_OR_ViceVersa + : Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Mq_WO_Vsd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_INVALID; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Mps_WO_Vps: + case BS3CG1ENC_VEX_MODRM_Mpd_WO_Vpd: + case BS3CG1ENC_VEX_MODRM_Mx_WO_Vx: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Uss_WO_HssHi_Vss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa; + pThis->iRegOp = 2; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 96; + pThis->aOperands[2].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI96; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_DW0; + break; + + case BS3CG1ENC_VEX_MODRM_Usd_WO_HsdHi_Vsd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa; + pThis->iRegOp = 2; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[2].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Wps_WO_Vps: + case BS3CG1ENC_VEX_MODRM_Wpd_WO_Vpd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Wq_WO_Vq: + BS3_ASSERT(pThis->fFlags & BS3CG1INSTR_F_VEX_L_ZERO); + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_Lmbz_OR_ViceVersa; + pThis->iRegOp = 1; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Wx_WO_Vx: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + + /* Unused or invalid instructions mostly. */ + //case BS3CG1ENC_VEX_FIXED: + // pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_FIXED; + // break; + case BS3CG1ENC_VEX_MODRM_MOD_EQ_3: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_MOD_EQ_3; + break; + case BS3CG1ENC_VEX_MODRM_MOD_NE_3: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_MOD_NE_3; + break; + case BS3CG1ENC_VEX_MODRM: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM; + break; + +#endif /* BS3CG1_WITH_VEX */ + + default: + Bs3TestFailedF("Invalid/unimplemented enmEncoding for instruction #%RU32 (%.*s): %d", + pThis->iInstr, pThis->cchMnemonic, pThis->pchMnemonic, pThis->enmEncoding); + return false; + } + return true; +} + + +/** + * Calculates the appropriate non-intel invalid instruction encoding. + * + * @returns the encoding to use instead. + * @param enmEncoding The intel invalid instruction encoding. + */ +static BS3CG1ENC Bs3Cg1CalcNoneIntelInvalidEncoding(BS3CG1ENC enmEncoding) +{ + switch (enmEncoding) + { + case BS3CG1ENC_MODRM_Gb_Eb: + case BS3CG1ENC_MODRM_Gv_RO_Ma: + case BS3CG1ENC_FIXED: + return BS3CG1ENC_FIXED; + default: + Bs3TestFailedF("Bs3Cg1CalcNoneIntelInvalidEncoding: Unsupported encoding: %d\n", enmEncoding); + return BS3CG1ENC_FIXED; + } +} + + +/** + * Sets cbOpDefault, cbOpOvrd66 and cbOpOvrdRexW. + * + * @param pThis The state. + * @param bMode The mode (only code part is used). + */ +static void Bs3Cg1SetOpSizes(PBS3CG1STATE pThis, uint8_t bMode) +{ + if (BS3_MODE_IS_16BIT_CODE(bMode)) + { + pThis->cbOpDefault = 2; + pThis->cbOpOvrd66 = 4; + pThis->cbOpOvrdRexW = 0; + } + else if (BS3_MODE_IS_32BIT_CODE(bMode)) + { + pThis->cbOpDefault = 4; + pThis->cbOpOvrd66 = 2; + pThis->cbOpOvrdRexW = 0; + } + else + { + pThis->cbOpDefault = 4; + pThis->cbOpOvrd66 = 2; + pThis->cbOpOvrdRexW = 8; + } +} + + +/** + * Sets up SSE and maybe AVX. + * + * @returns true (if successful, false if not and the SSE instructions ends up + * being invalid). + * @param pThis The state. + */ +static bool BS3_NEAR_CODE Bs3Cg3SetupSseAndAvx(PBS3CG1STATE pThis) +{ + if (!pThis->fWorkExtCtx) + { + unsigned i; + uint32_t cr0 = ASMGetCR0(); + uint32_t cr4 = ASMGetCR4(); + + cr0 &= ~(X86_CR0_TS | X86_CR0_MP | X86_CR0_EM); + cr0 |= X86_CR0_NE; + ASMSetCR0(cr0); + if (pThis->pExtCtx->enmMethod == BS3EXTCTXMETHOD_XSAVE) + { + cr4 |= X86_CR4_OSFXSR | X86_CR4_OSXMMEEXCPT | X86_CR4_OSXSAVE; + ASMSetCR4(cr4); + ASMSetXcr0(pThis->pExtCtx->fXcr0Nominal); + } + else + { + cr4 |= X86_CR4_OSFXSR | X86_CR4_OSXMMEEXCPT; + ASMSetCR4(cr4); + } + + for (i = 0; i < RT_ELEMENTS(pThis->aInitialCtxs); i++) + { + pThis->aInitialCtxs[i].cr0.u32 = cr0; + pThis->aInitialCtxs[i].cr4.u32 = cr4; + } + pThis->fWorkExtCtx = true; + } + + return true; +} + + +/** + * Next CPU configuration to test the current instruction in. + * + * This is for testing FPU, SSE and AVX instructions with the various lazy state + * load and enable bits in different configurations to ensure we're getting the + * right response. + * + * This also cleans up the CPU and test driver state. + * + * @returns true if we're to do another round, false if we're done. + * @param pThis The state. + * @param iCpuSetup The current CPU setup number. + * @param pfInvalidInstr Where to indicate whether the setup causes an + * invalid instruction or not. This is also used as + * input to avoid unnecessary CPUID work. + */ +static bool BS3_NEAR_CODE Bs3Cg1CpuSetupNext(PBS3CG1STATE pThis, unsigned iCpuSetup, bool BS3_FAR *pfInvalidInstr) +{ + if ( (pThis->fFlags & BS3CG1INSTR_F_INVALID_64BIT) + && BS3CG1_IS_64BIT_TARGET(pThis)) + return false; + + switch (pThis->enmCpuTest) + { + case BS3CG1CPU_ANY: + case BS3CG1CPU_GE_80186: + case BS3CG1CPU_GE_80286: + case BS3CG1CPU_GE_80386: + case BS3CG1CPU_GE_80486: + case BS3CG1CPU_GE_Pentium: + case BS3CG1CPU_CLFSH: + case BS3CG1CPU_CLFLUSHOPT: + return false; + + case BS3CG1CPU_MMX: + return false; + + case BS3CG1CPU_SSE: + case BS3CG1CPU_SSE2: + case BS3CG1CPU_SSE3: + case BS3CG1CPU_SSE4_1: + case BS3CG1CPU_AVX: + case BS3CG1CPU_AVX2: + if (iCpuSetup > 0 || *pfInvalidInstr) + { + /** @todo do more configs here. */ + pThis->fWorkExtCtx = false; + ASMSetCR0(ASMGetCR0() | X86_CR0_EM | X86_CR0_MP); + ASMSetCR4(ASMGetCR4() & ~(X86_CR4_OSFXSR | X86_CR4_OSXMMEEXCPT | X86_CR4_OSXSAVE)); + return false; + } + return false; + + default: + Bs3TestFailedF("Invalid enmCpuTest value: %d", pThis->enmCpuTest); + return false; + } +} + + +/** + * Check if the instruction is supported by the CPU, possibly making state + * adjustments to enable support for it. + * + * @returns true if supported, false if not. + * @param pThis The state. + */ +static bool BS3_NEAR_CODE Bs3Cg1CpuSetupFirst(PBS3CG1STATE pThis) +{ + uint32_t fEax; + uint32_t fEbx; + uint32_t fEcx; + uint32_t fEdx; + + if ( (pThis->fFlags & BS3CG1INSTR_F_INVALID_64BIT) + && BS3CG1_IS_64BIT_TARGET(pThis)) + return false; + + switch (pThis->enmCpuTest) + { + case BS3CG1CPU_ANY: + return true; + + case BS3CG1CPU_GE_80186: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80186) + return true; + return false; + + case BS3CG1CPU_GE_80286: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80286) + return true; + return false; + + case BS3CG1CPU_GE_80386: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386) + return true; + return false; + + case BS3CG1CPU_GE_80486: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + return true; + return false; + + case BS3CG1CPU_GE_Pentium: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_Pentium) + return true; + return false; + + case BS3CG1CPU_MMX: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, NULL, &fEdx); + if (fEdx & X86_CPUID_FEATURE_EDX_MMX) + return Bs3Cg3SetupSseAndAvx(pThis); /** @todo only do FNSAVE/FXSAVE here? */ + } + return false; + + case BS3CG1CPU_SSE: + case BS3CG1CPU_SSE2: + case BS3CG1CPU_SSE3: + case BS3CG1CPU_SSE4_1: + case BS3CG1CPU_AVX: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, &fEcx, &fEdx); + switch (pThis->enmCpuTest) + { + case BS3CG1CPU_SSE: + if (fEdx & X86_CPUID_FEATURE_EDX_SSE) + return Bs3Cg3SetupSseAndAvx(pThis); + return false; + case BS3CG1CPU_SSE2: + if (fEdx & X86_CPUID_FEATURE_EDX_SSE2) + return Bs3Cg3SetupSseAndAvx(pThis); + return false; + case BS3CG1CPU_SSE3: + if (fEcx & X86_CPUID_FEATURE_ECX_SSE3) + return Bs3Cg3SetupSseAndAvx(pThis); + return false; + case BS3CG1CPU_SSE4_1: + if (fEcx & X86_CPUID_FEATURE_ECX_SSE4_1) + return Bs3Cg3SetupSseAndAvx(pThis); + return false; + case BS3CG1CPU_AVX: + if (fEcx & X86_CPUID_FEATURE_ECX_AVX) + return Bs3Cg3SetupSseAndAvx(pThis) && !BS3_MODE_IS_RM_OR_V86(pThis->bMode); + return false; + default: BS3_ASSERT(0); /* impossible */ + } + } + return false; + + case BS3CG1CPU_AVX2: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(7, 0, 0/*leaf*/, 0, &fEax, &fEbx, &fEcx, &fEdx); + switch (pThis->enmCpuTest) + { + case BS3CG1CPU_AVX2: + if (fEbx & X86_CPUID_STEXT_FEATURE_EBX_AVX2) + return Bs3Cg3SetupSseAndAvx(pThis) && !BS3_MODE_IS_RM_OR_V86(pThis->bMode); + return false; + default: BS3_ASSERT(0); return false; /* impossible */ + } + } + return false; + + case BS3CG1CPU_CLFSH: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, NULL, &fEdx); + if (fEdx & X86_CPUID_FEATURE_EDX_CLFSH) + return true; + } + return false; + + case BS3CG1CPU_CLFLUSHOPT: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(7, 0, 0/*leaf*/, 0, NULL, &fEbx, NULL, NULL); + if (fEbx & X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT) + return true; + } + return false; + + default: + Bs3TestFailedF("Invalid enmCpuTest value: %d", pThis->enmCpuTest); + return false; + } +} + + + +/** + * Checks the preconditions for a test. + * + * @returns true if the test be executed, false if not. + * @param pThis The state. + * @param pHdr The test header. + */ +static bool BS3_NEAR_CODE Bs3Cg1RunSelector(PBS3CG1STATE pThis, PCBS3CG1TESTHDR pHdr) +{ + + uint8_t const BS3_FAR *pbCode = (uint8_t const BS3_FAR *)(pHdr + 1); + unsigned cbLeft = pHdr->cbSelector; + while (cbLeft-- > 0) + { + switch (*pbCode++) + { +#define CASE_PRED(a_Pred, a_Expr) \ + case ((a_Pred) << BS3CG1SEL_OP_KIND_MASK) | BS3CG1SEL_OP_IS_TRUE: \ + if (!(a_Expr)) return false; \ + break; \ + case ((a_Pred) << BS3CG1SEL_OP_KIND_MASK) | BS3CG1SEL_OP_IS_FALSE: \ + if (a_Expr) return false; \ + break + CASE_PRED(BS3CG1PRED_SIZE_O16, pThis->cbOperand == 2); + CASE_PRED(BS3CG1PRED_SIZE_O32, pThis->cbOperand == 4); + CASE_PRED(BS3CG1PRED_SIZE_O64, pThis->cbOperand == 8); + CASE_PRED(BS3CG1PRED_VEXL_0, pThis->uVexL == 0); + CASE_PRED(BS3CG1PRED_VEXL_1, pThis->uVexL == 1); + CASE_PRED(BS3CG1PRED_RING_0, pThis->uCpl == 0); + CASE_PRED(BS3CG1PRED_RING_1, pThis->uCpl == 1); + CASE_PRED(BS3CG1PRED_RING_2, pThis->uCpl == 2); + CASE_PRED(BS3CG1PRED_RING_3, pThis->uCpl == 3); + CASE_PRED(BS3CG1PRED_RING_0_THRU_2, pThis->uCpl <= 2); + CASE_PRED(BS3CG1PRED_RING_1_THRU_3, pThis->uCpl >= 1); + CASE_PRED(BS3CG1PRED_CODE_64BIT, BS3CG1_IS_64BIT_TARGET(pThis)); + CASE_PRED(BS3CG1PRED_CODE_32BIT, BS3_MODE_IS_32BIT_CODE(pThis->bMode)); + CASE_PRED(BS3CG1PRED_CODE_16BIT, BS3_MODE_IS_16BIT_CODE(pThis->bMode)); + CASE_PRED(BS3CG1PRED_MODE_REAL, BS3_MODE_IS_RM_SYS(pThis->bMode)); + CASE_PRED(BS3CG1PRED_MODE_PROT, BS3_MODE_IS_PM_SYS(pThis->bMode)); + CASE_PRED(BS3CG1PRED_MODE_LONG, BS3_MODE_IS_64BIT_SYS(pThis->bMode)); + CASE_PRED(BS3CG1PRED_MODE_SMM, false); + CASE_PRED(BS3CG1PRED_MODE_VMX, false); + CASE_PRED(BS3CG1PRED_MODE_SVM, false); + CASE_PRED(BS3CG1PRED_PAGING_ON, BS3_MODE_IS_PAGED(pThis->bMode)); + CASE_PRED(BS3CG1PRED_PAGING_OFF, !BS3_MODE_IS_PAGED(pThis->bMode)); + CASE_PRED(BS3CG1PRED_VENDOR_AMD, pThis->bCpuVendor == BS3CPUVENDOR_AMD); + CASE_PRED(BS3CG1PRED_VENDOR_INTEL, pThis->bCpuVendor == BS3CPUVENDOR_INTEL); + CASE_PRED(BS3CG1PRED_VENDOR_VIA, pThis->bCpuVendor == BS3CPUVENDOR_VIA); + CASE_PRED(BS3CG1PRED_VENDOR_SHANGHAI, pThis->bCpuVendor == BS3CPUVENDOR_SHANGHAI); + CASE_PRED(BS3CG1PRED_VENDOR_HYGON, pThis->bCpuVendor == BS3CPUVENDOR_HYGON); + +#undef CASE_PRED + default: + return Bs3TestFailedF("Invalid selector opcode %#x!", pbCode[-1]); + } + } + + return true; +} + + +#ifdef BS3CG1_DEBUG_CTX_MOD +/** + * Translates the operator into a string. + * + * @returns Read-only string pointer. + * @param bOpcode The context modifier program opcode. + */ +static const char BS3_FAR * BS3_NEAR_CODE Bs3Cg1CtxOpToString(uint8_t bOpcode) +{ + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: return "="; + case BS3CG1_CTXOP_OR: return "|="; + case BS3CG1_CTXOP_AND: return "&="; + case BS3CG1_CTXOP_AND_INV: return "&~="; + default: return "?WTF?"; + } +} +#endif + + +/** + * Runs a context modifier program. + * + * @returns Success indicator (true/false). + * @param pThis The state. + * @param pCtx The context. + * @param pHdr The program header. + * @param off The program offset relative to the end of the header. + * @param cb The program size. + * @param pEflCtx The context to take undefined EFLAGS from. (This is NULL + * if we're processing a input context modifier program.) + * @param pbInstr Points to the first instruction byte. For storing + * immediate operands during input context modification. + * NULL for output contexts. + */ +static bool BS3_NEAR_CODE Bs3Cg1RunContextModifier(PBS3CG1STATE pThis, PBS3REGCTX pCtx, PCBS3CG1TESTHDR pHdr, + unsigned off, unsigned cb, + PCBS3REGCTX pEflCtx, uint8_t BS3_FAR *pbInstr) +{ + uint8_t const BS3_FAR *pbCode = (uint8_t const BS3_FAR *)(pHdr + 1) + off; + int cbLeft = cb; + while (cbLeft-- > 0) + { + /* + * Decode the instruction. + */ + uint8_t const bOpcode = *pbCode++; + unsigned cbValue; + unsigned cbDst; + BS3CG1DST idxField; + BS3PTRUNION PtrField; + uint8_t BS3_FAR *pbMemCopy = NULL; + bool fZxVlMax; + + /* Expand the destiation field (can be escaped). Set fZxVlMax. */ + switch (bOpcode & BS3CG1_CTXOP_DST_MASK) + { + case BS3CG1_CTXOP_OP1: + idxField = pThis->aOperands[0].idxField; + if (idxField == BS3CG1DST_INVALID) + idxField = BS3CG1DST_OP1; + fZxVlMax = pEflCtx != NULL && pThis->aOperands[0].enmLocation == BS3CG1OPLOC_CTX_ZX_VLMAX; + break; + + case BS3CG1_CTXOP_OP2: + idxField = pThis->aOperands[1].idxField; + if (idxField == BS3CG1DST_INVALID) + idxField = BS3CG1DST_OP2; + fZxVlMax = pEflCtx != NULL && pThis->aOperands[1].enmLocation == BS3CG1OPLOC_CTX_ZX_VLMAX; + break; + + case BS3CG1_CTXOP_EFL: + idxField = BS3CG1DST_EFL; + fZxVlMax = false; + break; + + case BS3CG1_CTXOP_DST_ESC: + if (cbLeft-- > 0) + { + idxField = (BS3CG1DST)*pbCode++; + if (idxField <= BS3CG1DST_OP4) + { + if (idxField > BS3CG1DST_INVALID) + { + unsigned idxOp = idxField - BS3CG1DST_OP1; + uint8_t idxField2 = pThis->aOperands[idxOp].idxField; + if (idxField2 != BS3CG1DST_INVALID) + idxField = idxField2; + fZxVlMax = pEflCtx != NULL && pThis->aOperands[idxOp].enmLocation == BS3CG1OPLOC_CTX_ZX_VLMAX; + break; + } + } + else if (idxField < BS3CG1DST_END) + { + fZxVlMax = false; + break; + } + return Bs3TestFailedF("Malformed context instruction: idxField=%d", idxField); + } + RT_FALL_THRU(); + default: + return Bs3TestFailed("Malformed context instruction: Destination"); + } + + /* Expand value size (can be escaped). */ + switch (bOpcode & BS3CG1_CTXOP_SIZE_MASK) + { + case BS3CG1_CTXOP_1_BYTE: cbValue = 1; break; + case BS3CG1_CTXOP_2_BYTES: cbValue = 2; break; + case BS3CG1_CTXOP_4_BYTES: cbValue = 4; break; + case BS3CG1_CTXOP_8_BYTES: cbValue = 8; break; + case BS3CG1_CTXOP_16_BYTES: cbValue = 16; break; + case BS3CG1_CTXOP_32_BYTES: cbValue = 32; break; + case BS3CG1_CTXOP_12_BYTES: cbValue = 12; break; + case BS3CG1_CTXOP_SIZE_ESC: + if (cbLeft-- > 0) + { + cbValue = *pbCode++; + if (cbValue) + break; + } + RT_FALL_THRU(); + default: + return Bs3TestFailed("Malformed context instruction: size"); + } + + /* Make sure there is enough instruction bytes for the value. */ + if (cbValue <= cbLeft) + { /* likely */ } + else + return Bs3TestFailedF("Malformed context instruction: %u bytes value, %u bytes left", cbValue, cbLeft); + + /* + * Do value processing specific to the target field size. + */ + cbDst = g_acbBs3Cg1DstFields[idxField]; + if (cbDst == BS3CG1DSTSIZE_OPERAND) + cbDst = pThis->aOperands[idxField - BS3CG1DST_OP1].cbOp; + else if (cbDst == BS3CG1DSTSIZE_OPERAND_SIZE_GRP) + cbDst = pThis->cbOperand; + if (cbDst <= 8) + { + unsigned const offField = g_aoffBs3Cg1DstFields[idxField]; + + /* + * Deal with fields up to 8-byte wide. + */ + + /* Get the value. */ + uint64_t uValue; + if ((bOpcode & BS3CG1_CTXOP_SIGN_EXT)) + switch (cbValue) + { + case 1: uValue = *(int8_t const BS3_FAR *)pbCode; break; + case 2: uValue = *(int16_t const BS3_FAR *)pbCode; break; + case 4: uValue = *(int32_t const BS3_FAR *)pbCode; break; + default: + if (cbValue >= 8) + { + uValue = *(uint64_t const BS3_FAR *)pbCode; + break; + } + return Bs3TestFailedF("Malformed context instruction: %u bytes value (%u dst)", cbValue, cbDst); + } + else + switch (cbValue) + { + case 1: uValue = *(uint8_t const BS3_FAR *)pbCode; break; + case 2: uValue = *(uint16_t const BS3_FAR *)pbCode; break; + case 4: uValue = *(uint32_t const BS3_FAR *)pbCode; break; + default: + if (cbValue >= 8) + { + uValue = *(uint64_t const BS3_FAR *)pbCode; + break; + } + return Bs3TestFailedF("Malformed context instruction: %u bytes value (%u dst)", cbValue, cbDst); + } + + /* Find the field. */ + if (offField < sizeof(BS3REGCTX)) + PtrField.pu8 = (uint8_t BS3_FAR *)pCtx + offField; + /* Non-register operands: */ + else if ((unsigned)(idxField - BS3CG1DST_OP1) < 4U) + { + unsigned const idxOp = idxField - BS3CG1DST_OP1; + + switch (pThis->aOperands[idxOp].enmLocation) + { + case BS3CG1OPLOC_IMM: + if (pbInstr) + PtrField.pu8 = &pbInstr[pThis->aOperands[idxOp].off]; + else + return Bs3TestFailedF("Immediate operand referenced in output context!"); + break; + + case BS3CG1OPLOC_MEM: + if (!pbInstr) + return Bs3TestFailedF("Read only operand specified in output!"); + PtrField.pu8 = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[idxOp].off]; + break; + + case BS3CG1OPLOC_MEM_RW: + case BS3CG1OPLOC_MEM_WO: + if (pbInstr) + { + PtrField.pu8 = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[idxOp].off]; + pbMemCopy = pThis->MemOp.ab; + } + else + PtrField.pu8 = pThis->MemOp.ab; + break; + + default: + if (pThis->enmEncoding != pThis->enmEncodingNonInvalid) + goto l_advance_to_next; + return Bs3TestFailedF("Internal error: cbDst=%u idxField=%d (%d) offField=%#x: enmLocation=%u off=%#x idxField=%u", + cbDst, idxField, idxOp, offField, pThis->aOperands[idxOp].enmLocation, + pThis->aOperands[idxOp].off, pThis->aOperands[idxOp].idxField); + } + } + /* Special field: Copying in undefined EFLAGS from the result context. */ + else if (idxField == BS3CG1DST_EFL_UNDEF) + { + if (!pEflCtx || (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) != BS3CG1_CTXOP_ASSIGN) + return Bs3TestFailed("Invalid BS3CG1DST_EFL_UNDEF usage"); + PtrField.pu32 = &pCtx->rflags.u32; + uValue = (*PtrField.pu32 & ~(uint32_t)uValue) | (pEflCtx->rflags.u32 & (uint32_t)uValue); + } + /* Special field: Expected value (in/result) exception. */ + else if (idxField == BS3CG1DST_VALUE_XCPT) + { + if (!pEflCtx || (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) != BS3CG1_CTXOP_ASSIGN || cbDst != 1) + return Bs3TestFailed("Invalid BS3CG1DST_VALUE_XCPT usage"); + PtrField.pu8 = &pThis->bValueXcpt; + } + /* FPU and FXSAVE format. */ + else if ( pThis->pExtCtx->enmMethod != BS3EXTCTXMETHOD_ANCIENT + && offField - sizeof(BS3REGCTX) < RT_UOFFSET_AFTER(BS3EXTCTX, Ctx.x87.aXMM[15])) + { + if (pThis->fWorkExtCtx) + PtrField.pb = (uint8_t *)pThis->pExtCtx + offField - sizeof(BS3REGCTX); + else if (!pThis->fCpuSetupFirstResult) + { + BS3CG1_DPRINTF(("dbg: Extended context disabled: skipping modification (<=8)\n")); + goto l_advance_to_next; + } + else + return Bs3TestFailedF("Extended context disabled: Field %d (%s) @ %#x LB %u\n", + idxField, g_aszBs3Cg1DstFields[idxField].sz, offField, cbDst); + } + /** @todo other FPU fields and FPU state formats. */ + else + return Bs3TestFailedF("Todo implement me: cbDst=%u idxField=%d %s offField=%#x (<= 8)", + cbDst, idxField, g_aszBs3Cg1DstFields[idxField].sz, offField); + +#ifdef BS3CG1_DEBUG_CTX_MOD + switch (cbDst) + { + case 1: + BS3CG1_DPRINTF(("dbg: modify %s: %#04RX8 (LB %u) %s %#RX64 (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + *PtrField.pu8, cbDst, Bs3Cg1CtxOpToString(bOpcode), uValue, cbValue)); + break; + case 2: + BS3CG1_DPRINTF(("dbg: modify %s: %#06RX16 (LB %u) %s %#RX64 (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + *PtrField.pu16, cbDst, Bs3Cg1CtxOpToString(bOpcode), uValue, cbValue)); + break; + case 4: + BS3CG1_DPRINTF(("dbg: modify %s: %#010RX32 (LB %u) %s %#RX64 (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + *PtrField.pu32, cbDst, Bs3Cg1CtxOpToString(bOpcode), uValue, cbValue)); + break; + default: + BS3CG1_DPRINTF(("dbg: modify %s: %#018RX64 (LB %u) %s %#RX64 (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + *PtrField.pu64, cbDst, Bs3Cg1CtxOpToString(bOpcode), uValue, cbValue)); + break; + } +#endif + + /* Modify the field. */ + switch (cbDst) + { + case 1: + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: *PtrField.pu8 = (uint8_t)uValue; break; + case BS3CG1_CTXOP_OR: *PtrField.pu8 |= (uint8_t)uValue; break; + case BS3CG1_CTXOP_AND: *PtrField.pu8 &= (uint8_t)uValue; break; + case BS3CG1_CTXOP_AND_INV: *PtrField.pu8 &= ~(uint8_t)uValue; break; + } + break; + + case 2: + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: *PtrField.pu16 = (uint16_t)uValue; break; + case BS3CG1_CTXOP_OR: *PtrField.pu16 |= (uint16_t)uValue; break; + case BS3CG1_CTXOP_AND: *PtrField.pu16 &= (uint16_t)uValue; break; + case BS3CG1_CTXOP_AND_INV: *PtrField.pu16 &= ~(uint16_t)uValue; break; + } + break; + + case 4: + if ( (unsigned)(idxField - BS3CG1DST_XMM0_DW0_ZX) <= (unsigned)(BS3CG1DST_XMM15_DW0_ZX - BS3CG1DST_XMM0_DW0_ZX) + || fZxVlMax) + { + PtrField.pu32[1] = 0; + PtrField.pu64[1] = 0; + } + else if (offField <= RT_UOFFSETOF(BS3REGCTX, r15) /* Clear the top dword. */) + PtrField.pu32[1] = 0; + else if ((unsigned)(idxField - BS3CG1DST_MM0_LO_ZX) <= (unsigned)(BS3CG1DST_MM7_LO_ZX - BS3CG1DST_MM0_LO_ZX)) + { + PtrField.pu32[1] = 0; + PtrField.pu32[2] = 0xffff; /* observed on skylake */ + } + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: *PtrField.pu32 = (uint32_t)uValue; break; + case BS3CG1_CTXOP_OR: *PtrField.pu32 |= (uint32_t)uValue; break; + case BS3CG1_CTXOP_AND: *PtrField.pu32 &= (uint32_t)uValue; break; + case BS3CG1_CTXOP_AND_INV: *PtrField.pu32 &= ~(uint32_t)uValue; break; + } + break; + + case 8: + if ( (unsigned)(idxField - BS3CG1DST_XMM0_LO_ZX) <= (unsigned)(BS3CG1DST_XMM15_LO_ZX - BS3CG1DST_XMM0_LO_ZX) + || fZxVlMax) + PtrField.pu64[1] = 0; + else if ((unsigned)(idxField - BS3CG1DST_MM0) <= (unsigned)(BS3CG1DST_MM7 - BS3CG1DST_MM0)) + PtrField.pu32[2] = 0xffff; /* observed on skylake */ + + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: *PtrField.pu64 = (uint64_t)uValue; break; + case BS3CG1_CTXOP_OR: *PtrField.pu64 |= (uint64_t)uValue; break; + case BS3CG1_CTXOP_AND: *PtrField.pu64 &= (uint64_t)uValue; break; + case BS3CG1_CTXOP_AND_INV: *PtrField.pu64 &= ~(uint64_t)uValue; break; + } + break; + + default: + return Bs3TestFailedF("Malformed context instruction: cbDst=%u, expected 1, 2, 4, or 8", cbDst); + } + +#ifdef BS3CG1_DEBUG_CTX_MOD + switch (cbDst) + { + case 1: BS3CG1_DPRINTF(("dbg: --> %s: %#04RX8\n", g_aszBs3Cg1DstFields[idxField].sz, *PtrField.pu8)); break; + case 2: BS3CG1_DPRINTF(("dbg: --> %s: %#06RX16\n", g_aszBs3Cg1DstFields[idxField].sz, *PtrField.pu16)); break; + case 4: BS3CG1_DPRINTF(("dbg: --> %s: %#010RX32\n", g_aszBs3Cg1DstFields[idxField].sz, *PtrField.pu32)); break; + default: BS3CG1_DPRINTF(("dbg: --> %s: %#018RX64\n", g_aszBs3Cg1DstFields[idxField].sz, *PtrField.pu64)); break; + } +#endif + if (fZxVlMax) + { + uintptr_t iReg = ((uintptr_t)PtrField.pu8 - (uintptr_t)&pThis->pExtCtx->Ctx.x87.aXMM[0]) + / sizeof(pThis->pExtCtx->Ctx.x87.aXMM[0]); + pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[0] = 0; + pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[1] = 0; +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: --> cleared YMM%u_HI\n", iReg)); +#endif + } + } + /* + * Deal with larger field (FPU, SSE, AVX, ...). + */ + else if (pThis->fWorkExtCtx) + { + union + { + X86FPUREG FpuReg; + X86XMMREG XmmReg; + X86YMMREG YmmReg; + X86ZMMREG ZmmReg; + uint8_t ab[sizeof(X86ZMMREG)]; + uint32_t au32[sizeof(X86ZMMREG) / sizeof(uint32_t)]; + uint64_t au64[sizeof(X86ZMMREG) / sizeof(uint64_t)]; + } Value; + unsigned const offField = g_aoffBs3Cg1DstFields[idxField]; + unsigned iReg; + + /* Copy the value into the union, doing the zero padding / extending. */ + Bs3MemCpy(&Value, pbCode, cbValue); + if (cbValue < sizeof(Value)) + { + if ((bOpcode & BS3CG1_CTXOP_SIGN_EXT) && (Value.ab[cbValue - 1] & 0x80)) + Bs3MemSet(&Value.ab[cbValue], 0xff, sizeof(Value) - cbValue); + else + Bs3MemSet(&Value.ab[cbValue], 0x00, sizeof(Value) - cbValue); + } + + /* Optimized access to XMM and STx registers. */ + if ( pThis->pExtCtx->enmMethod != BS3EXTCTXMETHOD_ANCIENT + && offField - sizeof(BS3REGCTX) < RT_UOFFSET_AFTER(BS3EXTCTX, Ctx.x87.aXMM[15]) ) + PtrField.pb = (uint8_t *)pThis->pExtCtx + offField - sizeof(BS3REGCTX); + /* Non-register operands: */ + else if ((unsigned)(idxField - BS3CG1DST_OP1) < 4U) + { + unsigned const idxOp = idxField - BS3CG1DST_OP1; + switch (pThis->aOperands[idxOp].enmLocation) + { + case BS3CG1OPLOC_MEM: + if (!pbInstr) + return Bs3TestFailedF("Read only operand specified in output!"); + PtrField.pu8 = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[idxOp].off]; + break; + + case BS3CG1OPLOC_MEM_RW: + case BS3CG1OPLOC_MEM_WO: + if (pbInstr) + { + PtrField.pu8 = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[idxOp].off]; + pbMemCopy = pThis->MemOp.ab; + } + else + PtrField.pu8 = pThis->MemOp.ab; + break; + + default: + return Bs3TestFailedF("Internal error: Field %d (%d) @ %#x LB %u: enmLocation=%u off=%#x idxField=%u", + idxField, idxOp, offField, cbDst, pThis->aOperands[idxOp].enmLocation, + pThis->aOperands[idxOp].off, pThis->aOperands[idxOp].idxField); + } + } + /* The YMM (AVX) registers have split storage in the state, so they need special handling. */ + else if ((iReg = idxField - BS3CG1DST_YMM0) < 16U) + { + /* The first 128-bits in XMM land. */ + PtrField.pu64 = &pThis->pExtCtx->Ctx.x87.aXMM[iReg].au64[0]; + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: + PtrField.pu64[0] = Value.au64[0]; + PtrField.pu64[1] = Value.au64[1]; + break; + case BS3CG1_CTXOP_OR: + PtrField.pu64[0] |= Value.au64[0]; + PtrField.pu64[1] |= Value.au64[1]; + break; + case BS3CG1_CTXOP_AND: + PtrField.pu64[0] &= Value.au64[0]; + PtrField.pu64[1] &= Value.au64[1]; + break; + case BS3CG1_CTXOP_AND_INV: + PtrField.pu64[0] &= ~Value.au64[0]; + PtrField.pu64[1] &= ~Value.au64[1]; + break; + } + + /* The second 128-bit in YMM_HI land. */ + PtrField.pu64 = &pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[0]; + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: + PtrField.pu64[0] = Value.au64[2]; + PtrField.pu64[1] = Value.au64[3]; + break; + case BS3CG1_CTXOP_OR: + PtrField.pu64[0] |= Value.au64[2]; + PtrField.pu64[1] |= Value.au64[3]; + break; + case BS3CG1_CTXOP_AND: + PtrField.pu64[0] &= Value.au64[2]; + PtrField.pu64[1] &= Value.au64[3]; + break; + case BS3CG1_CTXOP_AND_INV: + PtrField.pu64[0] &= ~Value.au64[2]; + PtrField.pu64[1] &= ~Value.au64[3]; + break; + } + PtrField.pb = NULL; + } + /* AVX512 needs handling like above, but more complicated. */ + else + return Bs3TestFailedF("TODO: implement me: cbDst=%d idxField=%d (AVX and other weird state)", cbDst, idxField); + + if (PtrField.pb) + { + /* Modify the field / memory. */ + unsigned i; + if (cbDst & 3) + return Bs3TestFailedF("Malformed context instruction: cbDst=%u, multiple of 4", cbDst); + +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: modify %s: %.*Rhxs (LB %u) %s %.*Rhxs (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + cbDst, PtrField.pb, cbDst, Bs3Cg1CtxOpToString(bOpcode), cbValue, Value.ab, cbValue)); +#endif + + i = cbDst / 4; + while (i-- > 0) + { + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: PtrField.pu32[i] = Value.au32[i]; break; + case BS3CG1_CTXOP_OR: PtrField.pu32[i] |= Value.au32[i]; break; + case BS3CG1_CTXOP_AND: PtrField.pu32[i] &= Value.au32[i]; break; + case BS3CG1_CTXOP_AND_INV: PtrField.pu32[i] &= ~Value.au32[i]; break; + } + } + +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: --> %s: %.*Rhxs\n", g_aszBs3Cg1DstFields[idxField].sz, cbDst, PtrField.pb)); +#endif + + if (fZxVlMax) + { + uintptr_t iReg = ((uintptr_t)PtrField.pu8 - (uintptr_t)&pThis->pExtCtx->Ctx.x87.aXMM[0]) + / sizeof(pThis->pExtCtx->Ctx.x87.aXMM[0]); + if (cbDst < 16) + { + for (i = cbDst / 4; i < 4; i++) + PtrField.pu32[i++] = 0; +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: --> cleared high %u bytes of XMM%u\n", 16 - cbDst, iReg)); +#endif + } + pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[0] = 0; + pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[1] = 0; +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: --> cleared YMM%u_HI\n", iReg)); +#endif + } + } + + /* + * Hack! Update pThis->MemOp when setting up the inputs so we can + * correctly validate value and alignment exceptions. + */ + if (pbMemCopy && PtrField.pv) + Bs3MemCpy(pbMemCopy, PtrField.pv, cbDst); + } + /* !pThis->fWorkExtCtx: */ + else if (pThis->fCpuSetupFirstResult) + return Bs3TestFailedF("Extended context disabled: Field %d (%s) @ %#x LB %u\n", + idxField, g_aszBs3Cg1DstFields[idxField].sz, g_aoffBs3Cg1DstFields[idxField], cbDst); + else + BS3CG1_DPRINTF(("dbg: Extended context disabled: skipping modification [> 8]\n")); + + /* + * Advance to the next instruction. + */ +l_advance_to_next: + pbCode += cbValue; + cbLeft -= cbValue; + } + + return true; +} + + +/** + * Checks the result of a run. + * + * @returns true if successful, false if not. + * @param pThis The state. + * @param bTestXcptExpected The exception causing the test code to stop + * executing. + * @param fInvalidEncodingPgFault Set if we've cut the instruction a byte + * short and is expecting a \#PF on the page + * boundrary rather than a \#UD. Only set if + * fInvalidEncoding is also set. + * @param iEncoding For error reporting. + */ +static bool BS3_NEAR_CODE Bs3Cg1CheckResult(PBS3CG1STATE pThis, uint8_t bTestXcptExpected, + bool fInvalidEncodingPgFault, unsigned iEncoding) +{ + unsigned iOperand; + + /* + * Check the exception state first. + */ + uint8_t bExpectedXcpt; + uint8_t cbAdjustPc; + if (!pThis->fInvalidEncoding) + { + bExpectedXcpt = pThis->bAlignmentXcpt; + if (bExpectedXcpt == UINT8_MAX) + bExpectedXcpt = pThis->bValueXcpt; + if (bExpectedXcpt == UINT8_MAX) + { + cbAdjustPc = pThis->cbCurInstr; + bExpectedXcpt = bTestXcptExpected; + if (bTestXcptExpected == X86_XCPT_PF) + pThis->Ctx.cr2.u = pThis->uCodePgFlat + X86_PAGE_SIZE; + } + else + cbAdjustPc = 0; + } + else + { + cbAdjustPc = 0; + if (!fInvalidEncodingPgFault) + bExpectedXcpt = X86_XCPT_UD; + else + { + bExpectedXcpt = X86_XCPT_PF; + pThis->Ctx.cr2.u = pThis->uCodePgFlat + X86_PAGE_SIZE; + } + } + if (RT_LIKELY( pThis->TrapFrame.bXcpt == bExpectedXcpt + && pThis->TrapFrame.Ctx.rip.u == pThis->Ctx.rip.u + cbAdjustPc)) + { + /* + * Check the register content. + */ + bool fOkay = Bs3TestCheckRegCtxEx(&pThis->TrapFrame.Ctx, &pThis->Ctx, + cbAdjustPc, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, + pThis->pszMode, iEncoding); + + /* + * Check memory output operands. + */ + if (!pThis->fInvalidEncoding) + { + iOperand = pThis->cOperands; + while (iOperand-- > 0) + if ( pThis->aOperands[iOperand].enmLocation == BS3CG1OPLOC_MEM_RW + || pThis->aOperands[iOperand].enmLocation == BS3CG1OPLOC_MEM_WO) + { + if (pThis->aOperands[iOperand].off) + { + BS3PTRUNION PtrUnion; + PtrUnion.pb = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[iOperand].off]; + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: + if (*PtrUnion.pu8 == pThis->MemOp.ab[0]) + continue; + Bs3TestFailedF("op%u: Wrote %#04RX8, expected %#04RX8", + iOperand, *PtrUnion.pu8, pThis->MemOp.ab[0]); + break; + case 2: + if (*PtrUnion.pu16 == pThis->MemOp.au16[0]) + continue; + Bs3TestFailedF("op%u: Wrote %#06RX16, expected %#06RX16", + iOperand, *PtrUnion.pu16, pThis->MemOp.au16[0]); + break; + case 4: + if (*PtrUnion.pu32 == pThis->MemOp.au32[0]) + continue; + Bs3TestFailedF("op%u: Wrote %#010RX32, expected %#010RX32", + iOperand, *PtrUnion.pu32, pThis->MemOp.au32[0]); + break; + case 8: + if (*PtrUnion.pu64 == pThis->MemOp.au64[0]) + continue; + Bs3TestFailedF("op%u: Wrote %#018RX64, expected %#018RX64", + iOperand, *PtrUnion.pu64, pThis->MemOp.au64[0]); + break; + default: + if (Bs3MemCmp(PtrUnion.pb, pThis->MemOp.ab, pThis->aOperands[iOperand].cbOp) == 0) + continue; + Bs3TestFailedF("op%u: Wrote %.*Rhxs, expected %.*Rhxs", + iOperand, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb, + pThis->aOperands[iOperand].cbOp, pThis->MemOp.ab); + break; + } + } + else + Bs3TestFailedF("op%u: off is zero\n", iOperand); + fOkay = false; + } + } + + /* + * Check extended context if enabled. + */ + if (pThis->fWorkExtCtx) + { + PBS3EXTCTX pExpect = pThis->pExtCtx; + PBS3EXTCTX pResult = pThis->pResultExtCtx; + unsigned i; + if ( pExpect->enmMethod == BS3EXTCTXMETHOD_XSAVE + || pExpect->enmMethod == BS3EXTCTXMETHOD_FXSAVE) + { + /* Compare the x87 state, ASSUMING XCR0 bit 1 is set. */ +#define CHECK_FIELD(a_Field, a_szFmt) \ + if (pResult->Ctx.a_Field != pExpect->Ctx.a_Field) fOkay = Bs3TestFailedF(a_szFmt, pResult->Ctx.a_Field, pExpect->Ctx.a_Field) + CHECK_FIELD(x87.FCW, "FCW: %#06x, expected %#06x"); + CHECK_FIELD(x87.FSW, "FSW: %#06x, expected %#06x"); + CHECK_FIELD(x87.FTW, "FTW: %#06x, expected %#06x"); + //CHECK_FIELD(x87.FOP, "FOP: %#06x, expected %#06x"); + //CHECK_FIELD(x87.FPUIP, "FPUIP: %#010RX32, expected %#010RX32"); + //CHECK_FIELD(x87.CS, "FPUCS: %#06x, expected %#06x"); + //CHECK_FIELD(x87.Rsrvd1, "Rsrvd1: %#06x, expected %#06x"); + //CHECK_FIELD(x87.DP, "FPUDP: %#010RX32, expected %#010RX32"); + //CHECK_FIELD(x87.DS, "FPUDS: %#06x, expected %#06x"); + //CHECK_FIELD(x87.Rsrvd2, "Rsrvd2: %#06x, expected %#06x"); + CHECK_FIELD(x87.MXCSR, "MXCSR: %#010RX32, expected %#010RX32"); +#undef CHECK_FIELD + for (i = 0; i < RT_ELEMENTS(pExpect->Ctx.x87.aRegs); i++) + if ( pResult->Ctx.x87.aRegs[i].au64[0] != pExpect->Ctx.x87.aRegs[i].au64[0] + || pResult->Ctx.x87.aRegs[i].au16[4] != pExpect->Ctx.x87.aRegs[i].au16[4]) + fOkay = Bs3TestFailedF("ST[%u]: %c m=%#RX64 e=%d, expected %c m=%#RX64 e=%d", i, + pResult->Ctx.x87.aRegs[i].r80Ex.s.fSign ? '-' : '+', + pResult->Ctx.x87.aRegs[i].r80Ex.s.uMantissa, + pResult->Ctx.x87.aRegs[i].r80Ex.s.uExponent, + pExpect->Ctx.x87.aRegs[i].r80Ex.s.fSign ? '-' : '+', + pExpect->Ctx.x87.aRegs[i].r80Ex.s.uMantissa, + pExpect->Ctx.x87.aRegs[i].r80Ex.s.uExponent); + for (i = 0; i < (ARCH_BITS == 64 ? 16 : 8); i++) + if ( pResult->Ctx.x87.aXMM[i].au64[0] != pExpect->Ctx.x87.aXMM[i].au64[0] + || pResult->Ctx.x87.aXMM[i].au64[1] != pExpect->Ctx.x87.aXMM[i].au64[1]) + fOkay = Bs3TestFailedF("XMM%u: %#010RX64'%016RX64, expected %#010RX64'%08RX64", i, + pResult->Ctx.x87.aXMM[i].au64[1], + pResult->Ctx.x87.aXMM[i].au64[0], + pExpect->Ctx.x87.aXMM[i].au64[1], + pExpect->Ctx.x87.aXMM[i].au64[0]); + if (pExpect->fXcr0Saved & XSAVE_C_YMM) + for (i = 0; i < (ARCH_BITS == 64 ? 16 : 8); i++) + if ( pResult->Ctx.x.u.YmmHi.aYmmHi[i].au64[0] != pExpect->Ctx.x.u.YmmHi.aYmmHi[i].au64[0] + || pResult->Ctx.x.u.YmmHi.aYmmHi[i].au64[1] != pExpect->Ctx.x.u.YmmHi.aYmmHi[i].au64[1]) + fOkay = Bs3TestFailedF("YMM%u_HI: %#010RX64'%016RX64, expected %#010RX64'%08RX64", i, + pResult->Ctx.x.u.YmmHi.aYmmHi[i].au64[1], + pResult->Ctx.x.u.YmmHi.aYmmHi[i].au64[0], + pExpect->Ctx.x.u.YmmHi.aYmmHi[i].au64[1], + pExpect->Ctx.x.u.YmmHi.aYmmHi[i].au64[0]); + } + else + fOkay = Bs3TestFailedF("Unsupported extended CPU context method: %d", pExpect->enmMethod); + } + + /* + * Done. + */ + if (fOkay) + return true; + + /* + * Report failure. + */ + Bs3TestFailedF("ins#%RU32/test#%u: encoding #%u: %.*Rhxs%s", + pThis->iInstr, pThis->iTest, iEncoding, pThis->cbCurInstr, pThis->abCurInstr, + fInvalidEncodingPgFault ? " (cut short)" : ""); + } + else + Bs3TestFailedF("ins#%RU32/test#%u: bXcpt=%#x expected %#x; rip=%RX64 expected %RX64; encoding#%u: %.*Rhxs%s", + pThis->iInstr, pThis->iTest, + pThis->TrapFrame.bXcpt, bExpectedXcpt, + pThis->TrapFrame.Ctx.rip.u, pThis->Ctx.rip.u + cbAdjustPc, + iEncoding, pThis->cbCurInstr, pThis->abCurInstr, fInvalidEncodingPgFault ? " (cut short)" : ""); + Bs3TestPrintf("cpl=%u cbOperands=%u\n", pThis->uCpl, pThis->cbOperand); + + /* + * Display memory operands. + */ + for (iOperand = 0; iOperand < pThis->cOperands; iOperand++) + { + BS3PTRUNION PtrUnion; + switch (pThis->aOperands[iOperand].enmLocation) + { + case BS3CG1OPLOC_CTX: + { + uint8_t idxField = pThis->aOperands[iOperand].idxField; + unsigned offField = g_aoffBs3Cg1DstFields[idxField]; + if (offField <= sizeof(BS3REGCTX)) + PtrUnion.pb = (uint8_t BS3_FAR *)&pThis->Ctx + offField; + else + { + Bs3TestPrintf("op%u: ctx%u: xxxx\n", iOperand, pThis->aOperands[iOperand].cbOp * 8); + break; + } + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: Bs3TestPrintf("op%u: ctx08: %#04RX8\n", iOperand, *PtrUnion.pu8); break; + case 2: Bs3TestPrintf("op%u: ctx16: %#06RX16\n", iOperand, *PtrUnion.pu16); break; + case 4: Bs3TestPrintf("op%u: ctx32: %#010RX32\n", iOperand, *PtrUnion.pu32); break; + case 8: Bs3TestPrintf("op%u: ctx64: %#018RX64\n", iOperand, *PtrUnion.pu64); break; + default: + Bs3TestPrintf("op%u: ctx%u: %.*Rhxs\n", iOperand, pThis->aOperands[iOperand].cbOp * 8, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb); + break; + } + break; + } + + case BS3CG1OPLOC_IMM: + PtrUnion.pb = &pThis->pbCodePg[pThis->aOperands[iOperand].off]; + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: Bs3TestPrintf("op%u: imm08: %#04RX8\n", iOperand, *PtrUnion.pu8); break; + case 2: Bs3TestPrintf("op%u: imm16: %#06RX16\n", iOperand, *PtrUnion.pu16); break; + case 4: Bs3TestPrintf("op%u: imm32: %#010RX32\n", iOperand, *PtrUnion.pu32); break; + case 8: Bs3TestPrintf("op%u: imm64: %#018RX64\n", iOperand, *PtrUnion.pu64); break; + default: + Bs3TestPrintf("op%u: imm%u: %.*Rhxs\n", iOperand, pThis->aOperands[iOperand].cbOp * 8, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb); + break; + } + break; + + case BS3CG1OPLOC_MEM: + case BS3CG1OPLOC_MEM_RW: + case BS3CG1OPLOC_MEM_WO: + if (pThis->aOperands[iOperand].off) + { + PtrUnion.pb = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[iOperand].off]; + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: Bs3TestPrintf("op%u: result mem08: %#04RX8\n", iOperand, *PtrUnion.pu8); break; + case 2: Bs3TestPrintf("op%u: result mem16: %#06RX16\n", iOperand, *PtrUnion.pu16); break; + case 4: Bs3TestPrintf("op%u: result mem32: %#010RX32\n", iOperand, *PtrUnion.pu32); break; + case 8: Bs3TestPrintf("op%u: result mem64: %#018RX64\n", iOperand, *PtrUnion.pu64); break; + default: + Bs3TestPrintf("op%u: result mem%u: %.*Rhxs\n", iOperand, pThis->aOperands[iOperand].cbOp * 8, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb); + break; + } + if ( pThis->aOperands[iOperand].enmLocation == BS3CG1OPLOC_MEM_WO + || pThis->aOperands[iOperand].enmLocation == BS3CG1OPLOC_MEM_RW) + { + PtrUnion.pb = pThis->MemOp.ab; + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: Bs3TestPrintf("op%u: expect mem08: %#04RX8\n", iOperand, *PtrUnion.pu8); break; + case 2: Bs3TestPrintf("op%u: expect mem16: %#06RX16\n", iOperand, *PtrUnion.pu16); break; + case 4: Bs3TestPrintf("op%u: expect mem32: %#010RX32\n", iOperand, *PtrUnion.pu32); break; + case 8: Bs3TestPrintf("op%u: expect mem64: %#018RX64\n", iOperand, *PtrUnion.pu64); break; + default: + Bs3TestPrintf("op%u: expect mem%u: %.*Rhxs\n", iOperand, pThis->aOperands[iOperand].cbOp * 8, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb); + break; + } + } + } + else + Bs3TestPrintf("op%u: mem%u: zero off value!!\n", iOperand, pThis->aOperands[iOperand].cbOp * 8); + break; + } + } + + /* + * Display contexts. + */ + Bs3TestPrintf("-- Expected context:\n"); + Bs3RegCtxPrint(&pThis->Ctx); + if (pThis->fWorkExtCtx) + Bs3TestPrintf("xcr0=%RX64\n", pThis->pExtCtx->fXcr0Saved); + Bs3TestPrintf("-- Actual context:\n"); + Bs3TrapPrintFrame(&pThis->TrapFrame); + if (pThis->fWorkExtCtx) + Bs3TestPrintf("xcr0=%RX64\n", pThis->pResultExtCtx->fXcr0Saved); + Bs3TestPrintf("\n"); +ASMHalt(); + return false; +} + + +/** + * Destroys the state, freeing all allocations and such. + * + * @param pThis The state. + */ +static void BS3_NEAR_CODE Bs3Cg1Destroy(PBS3CG1STATE pThis) +{ + if (BS3_MODE_IS_PAGED(pThis->bMode)) + { +#if ARCH_BITS != 16 + Bs3MemGuardedTestPageFree(pThis->pbCodePg); + Bs3MemGuardedTestPageFree(pThis->pbDataPg); +#endif + } + else + { + Bs3MemFree(pThis->pbCodePg, X86_PAGE_SIZE); + Bs3MemFree(pThis->pbDataPg, X86_PAGE_SIZE); + } + + if (pThis->pExtCtx) + Bs3MemFree(pThis->pExtCtx, pThis->pExtCtx->cb * 3); + + pThis->pbCodePg = NULL; + pThis->pbDataPg = NULL; + pThis->pExtCtx = NULL; + pThis->pResultExtCtx = NULL; + pThis->pInitialExtCtx = NULL; +} + + +/** + * Initializes the state. + * + * @returns Success indicator (true/false) + * @param pThis The state. + * @param bMode The mode being tested. + */ +bool BS3_NEAR_CODE BS3_CMN_NM(Bs3Cg1Init)(PBS3CG1STATE pThis, uint8_t bMode) +{ + BS3MEMKIND const enmMemKind = BS3_MODE_IS_RM_OR_V86(bMode) ? BS3MEMKIND_REAL + : !BS3_MODE_IS_64BIT_CODE(bMode) ? BS3MEMKIND_TILED : BS3MEMKIND_FLAT32; + unsigned iRing; + unsigned cb; + unsigned i; + uint64_t fFlags; + PBS3EXTCTX pExtCtx; + + Bs3MemSet(pThis, 0, sizeof(*pThis)); + + pThis->iFirstRing = BS3_MODE_IS_V86(bMode) ? 3 : 0; + pThis->iEndRing = BS3_MODE_IS_RM_SYS(bMode) ? 1 : 4; + pThis->bMode = bMode; + pThis->pszMode = Bs3GetModeName(bMode); + pThis->pszModeShort = Bs3GetModeNameShortLower(bMode); + pThis->bCpuVendor = Bs3GetCpuVendor(); + pThis->pchMnemonic = g_achBs3Cg1Mnemonics; + pThis->pabOperands = g_abBs3Cg1Operands; + pThis->pabOpcodes = g_abBs3Cg1Opcodes; + pThis->fAdvanceMnemonic = 1; + + /* Allocate extended context structures. */ + cb = Bs3ExtCtxGetSize(&fFlags); + pExtCtx = Bs3MemAlloc(BS3MEMKIND_TILED, cb * 3); + if (!pExtCtx) + return Bs3TestFailedF("Bs3MemAlloc(tiled,%#x)", cb * 3); + pThis->pExtCtx = pExtCtx; + pThis->pResultExtCtx = (PBS3EXTCTX)((uint8_t BS3_FAR *)pExtCtx + cb); + pThis->pInitialExtCtx = (PBS3EXTCTX)((uint8_t BS3_FAR *)pExtCtx + cb + cb); + + Bs3ExtCtxInit(pThis->pExtCtx, cb, fFlags); + Bs3ExtCtxInit(pThis->pResultExtCtx, cb, fFlags); + Bs3ExtCtxInit(pThis->pInitialExtCtx, cb, fFlags); + //Bs3TestPrintf("fCR0=%RX64 cbExtCtx=%#x method=%d\n", fFlags, cb, pExtCtx->enmMethod); + + /* Allocate guarded exectuable and data memory. */ + if (BS3_MODE_IS_PAGED(bMode)) + { +#if ARCH_BITS != 16 + pThis->pbCodePg = Bs3MemGuardedTestPageAlloc(enmMemKind); + pThis->pbDataPg = Bs3MemGuardedTestPageAlloc(enmMemKind); + if (!pThis->pbCodePg || !pThis->pbDataPg) + { + Bs3TestFailedF("Bs3MemGuardedTestPageAlloc(%d) failed", enmMemKind); + Bs3MemPrintInfo(); + Bs3Shutdown(); + return Bs3TestFailedF("Bs3MemGuardedTestPageAlloc(%d) failed", enmMemKind); + } + if ( BS3_MODE_IS_64BIT_CODE(bMode) + && (uintptr_t)pThis->pbDataPg >= _2G) + return Bs3TestFailedF("pbDataPg=%p is above 2GB and not simple to address from 64-bit code", pThis->pbDataPg); +#else + return Bs3TestFailed("WTF?! #1"); +#endif + } + else + { + pThis->pbCodePg = Bs3MemAlloc(enmMemKind, X86_PAGE_SIZE); + pThis->pbDataPg = Bs3MemAlloc(enmMemKind, X86_PAGE_SIZE); + if (!pThis->pbCodePg || !pThis->pbDataPg) + { + Bs3MemPrintInfo(); + return Bs3TestFailedF("Bs3MemAlloc(%d,Pg) failed", enmMemKind); + } + } + pThis->uCodePgFlat = Bs3SelPtrToFlat(pThis->pbCodePg); + pThis->uDataPgFlat = Bs3SelPtrToFlat(pThis->pbDataPg); +#if ARCH_BITS == 16 + pThis->CodePgFar.sel = BS3_FP_SEG(pThis->pbCodePg); + pThis->CodePgFar.off = BS3_FP_OFF(pThis->pbCodePg); + pThis->CodePgRip = BS3_FP_OFF(pThis->pbCodePg); + pThis->DataPgFar.sel = BS3_FP_SEG(pThis->pbDataPg); + pThis->DataPgFar.off = BS3_FP_OFF(pThis->pbDataPg); +#else + if (BS3_MODE_IS_RM_OR_V86(bMode)) + { + *(uint32_t *)&pThis->DataPgFar = Bs3SelFlatDataToRealMode(pThis->uDataPgFlat); + ASMCompilerBarrier(); + pThis->CodePgFar.off = 0; + pThis->CodePgFar.sel = pThis->uCodePgFlat >> 4; + pThis->CodePgRip = pThis->CodePgFar.off; + } + else if (BS3_MODE_IS_16BIT_CODE(bMode)) + { + *(uint32_t *)&pThis->DataPgFar = Bs3SelFlatDataToProtFar16(pThis->uDataPgFlat); + ASMCompilerBarrier(); + pThis->CodePgFar.sel = BS3_SEL_SPARE_00; + pThis->CodePgFar.off = 0; + pThis->CodePgRip = 0; + } + else if (BS3_MODE_IS_32BIT_CODE(bMode)) + { + *(uint32_t *)&pThis->DataPgFar = Bs3SelFlatDataToProtFar16(pThis->uDataPgFlat); + ASMCompilerBarrier(); + pThis->CodePgFar.sel = 0; + pThis->CodePgFar.off = 0; + pThis->CodePgRip = (uintptr_t)pThis->pbCodePg; + } + else + { + pThis->DataPgFar.off = 0; + pThis->DataPgFar.sel = 0; + pThis->CodePgFar.off = 0; + pThis->CodePgFar.sel = 0; + pThis->CodePgRip = (uintptr_t)pThis->pbCodePg; + } +#endif + BS3CG1_DPRINTF(("pbDataPg=%p %04x:%04x pbCodePg=%p %04x:%04x\n", + pThis->pbDataPg, pThis->DataPgFar.sel, pThis->DataPgFar.off, + pThis->pbCodePg, pThis->CodePgFar.sel, pThis->CodePgFar.off)); + + /* + * Create basic context for each target ring. + * + * In protected 16-bit code we need set up code selectors that can access + * pbCodePg. + * + * In long mode we make sure the high 32-bits of GPRs (sans RSP) have some + * bits set so we can check that the implicit clearing is tested. + */ + Bs3RegCtxSaveEx(&pThis->aInitialCtxs[pThis->iFirstRing], bMode, 1024 * 3); +#if ARCH_BITS == 64 + pThis->aInitialCtxs[pThis->iFirstRing].rax.u |= UINT64_C(0x0101010100000000); + pThis->aInitialCtxs[pThis->iFirstRing].rbx.u |= UINT64_C(0x0202020200000000); + pThis->aInitialCtxs[pThis->iFirstRing].rcx.u |= UINT64_C(0x0303030300000000); + pThis->aInitialCtxs[pThis->iFirstRing].rdx.u |= UINT64_C(0x0404040400000000); + pThis->aInitialCtxs[pThis->iFirstRing].rbp.u |= UINT64_C(0x0505050500000000); + pThis->aInitialCtxs[pThis->iFirstRing].rdi.u |= UINT64_C(0x0606060600000000); + pThis->aInitialCtxs[pThis->iFirstRing].rsi.u |= UINT64_C(0x0707070700000000); + pThis->aInitialCtxs[pThis->iFirstRing].r8.u |= UINT64_C(0x0808080800000000); + pThis->aInitialCtxs[pThis->iFirstRing].r9.u |= UINT64_C(0x0909090900000000); + pThis->aInitialCtxs[pThis->iFirstRing].r10.u |= UINT64_C(0x1010101000000000); + pThis->aInitialCtxs[pThis->iFirstRing].r11.u |= UINT64_C(0x1111111100000000); + pThis->aInitialCtxs[pThis->iFirstRing].r12.u |= UINT64_C(0x1212121200000000); + pThis->aInitialCtxs[pThis->iFirstRing].r13.u |= UINT64_C(0x1313131300000000); + pThis->aInitialCtxs[pThis->iFirstRing].r14.u |= UINT64_C(0x1414141400000000); + pThis->aInitialCtxs[pThis->iFirstRing].r15.u |= UINT64_C(0x1515151500000000); +#endif + + if (BS3_MODE_IS_RM_OR_V86(bMode)) + { + pThis->aInitialCtxs[pThis->iFirstRing].cs = pThis->CodePgFar.sel; + BS3_ASSERT(pThis->iFirstRing + 1 == pThis->iEndRing); + } + else if (BS3_MODE_IS_16BIT_CODE(bMode)) + { +#if ARCH_BITS == 16 + uintptr_t const uFlatCodePgSeg = Bs3SelPtrToFlat(BS3_FP_MAKE(BS3_FP_SEG(pThis->pbCodePg), 0)); +#else + uintptr_t const uFlatCodePgSeg = (uintptr_t)pThis->pbCodePg; +#endif + for (iRing = pThis->iFirstRing + 1; iRing < pThis->iEndRing; iRing++) + { + Bs3MemCpy(&pThis->aInitialCtxs[iRing], &pThis->aInitialCtxs[pThis->iFirstRing], sizeof(pThis->aInitialCtxs[iRing])); + Bs3RegCtxConvertToRingX(&pThis->aInitialCtxs[iRing], iRing); + } + for (iRing = pThis->iFirstRing; iRing < pThis->iEndRing; iRing++) + { + pThis->aInitialCtxs[iRing].cs = BS3_SEL_SPARE_00 + iRing * 8 + iRing; + Bs3SelSetup16BitCode(&Bs3GdteSpare00 + iRing, uFlatCodePgSeg, iRing); + } + } + else + { + Bs3RegCtxSetRipCsFromCurPtr(&pThis->aInitialCtxs[pThis->iFirstRing], (FPFNBS3FAR)pThis->pbCodePg); + for (iRing = pThis->iFirstRing + 1; iRing < pThis->iEndRing; iRing++) + { + Bs3MemCpy(&pThis->aInitialCtxs[iRing], &pThis->aInitialCtxs[pThis->iFirstRing], sizeof(pThis->aInitialCtxs[iRing])); + Bs3RegCtxConvertToRingX(&pThis->aInitialCtxs[iRing], iRing); + } + } + + /* + * Create an initial extended CPU context. + */ + pExtCtx = pThis->pInitialExtCtx; + if ( pExtCtx->enmMethod == BS3EXTCTXMETHOD_FXSAVE + || pExtCtx->enmMethod == BS3EXTCTXMETHOD_XSAVE) + { + pExtCtx->Ctx.x87.FCW = X86_FCW_MASK_ALL | X86_FCW_PC_64 | X86_FCW_RC_NEAREST; + pExtCtx->Ctx.x87.FSW = 0; + pExtCtx->Ctx.x87.MXCSR = X86_MXCSR_IM | X86_MXCSR_DM | X86_MXCSR_RC_NEAREST; + pExtCtx->Ctx.x87.MXCSR_MASK = 0; + for (i = 0; i < RT_ELEMENTS(pExtCtx->Ctx.x87.aRegs); i++) + { + pExtCtx->Ctx.x87.aRegs[i].au16[0] = i << 4; + pExtCtx->Ctx.x87.aRegs[i].au16[1] = i << 4; + pExtCtx->Ctx.x87.aRegs[i].au16[2] = i << 4; + pExtCtx->Ctx.x87.aRegs[i].au16[3] = i << 4; + } + for (i = 0; i < RT_ELEMENTS(pExtCtx->Ctx.x87.aXMM); i++) + { + pExtCtx->Ctx.x87.aXMM[i].au16[0] = i | UINT16_C(0x8f00); + pExtCtx->Ctx.x87.aXMM[i].au16[1] = i | UINT16_C(0x8e00); + pExtCtx->Ctx.x87.aXMM[i].au16[2] = i | UINT16_C(0x8d00); + pExtCtx->Ctx.x87.aXMM[i].au16[3] = i | UINT16_C(0x8c00); + pExtCtx->Ctx.x87.aXMM[i].au16[4] = i | UINT16_C(0x8b00); + pExtCtx->Ctx.x87.aXMM[i].au16[5] = i | UINT16_C(0x8a00); + pExtCtx->Ctx.x87.aXMM[i].au16[6] = i | UINT16_C(0x8900); + pExtCtx->Ctx.x87.aXMM[i].au16[7] = i | UINT16_C(0x8800); + } + if (pExtCtx->fXcr0Nominal & XSAVE_C_YMM) + for (i = 0; i < RT_ELEMENTS(pExtCtx->Ctx.x.u.YmmHi.aYmmHi); i++) + { + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[0] = (i << 8) | (i << 12) | 0xff; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[1] = (i << 8) | (i << 12) | 0xfe; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[2] = (i << 8) | (i << 12) | 0xfd; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[3] = (i << 8) | (i << 12) | 0xfc; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[4] = (i << 8) | (i << 12) | 0xfb; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[5] = (i << 8) | (i << 12) | 0xfa; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[6] = (i << 8) | (i << 12) | 0xf9; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[7] = (i << 8) | (i << 12) | 0xf8; + } + + } + //else if (pExtCtx->enmMethod == BS3EXTCTXMETHOD_ANCIENT) + else + return Bs3TestFailedF("Unsupported extended CPU context method: %d", pExtCtx->enmMethod); + + return true; +} + + +static uint8_t BS3_NEAR_CODE BS3_CMN_NM(Bs3Cg1WorkerInner)(PBS3CG1STATE pThis) +{ + uint8_t iRing; + unsigned iInstr; + + /* + * Test the instructions. + */ + for (iInstr = 0; iInstr < g_cBs3Cg1Instructions; + iInstr++, + pThis->pchMnemonic += pThis->fAdvanceMnemonic * pThis->cchMnemonic, + pThis->pabOperands += pThis->cOperands, + pThis->pabOpcodes += pThis->cbOpcodes) + { + uint8_t const bTestXcptExpected = BS3_MODE_IS_PAGED(pThis->bMode) ? X86_XCPT_PF : X86_XCPT_UD; + bool fOuterInvalidInstr = false; + unsigned iCpuSetup; + + /* + * Expand the instruction information into the state. + * Note! 16-bit will switch to a two level test header lookup once we exceed 64KB. + */ + PCBS3CG1INSTR pInstr = &g_aBs3Cg1Instructions[iInstr]; + pThis->iInstr = iInstr; + pThis->pTestHdr = (PCBS3CG1TESTHDR)&g_abBs3Cg1Tests[pInstr->offTests]; + pThis->fFlags = pInstr->fFlags; + pThis->enmEncoding = (BS3CG1ENC)pInstr->enmEncoding; + pThis->enmEncodingNonInvalid = (BS3CG1ENC)pInstr->enmEncoding; + pThis->enmCpuTest = (BS3CG1CPU)pInstr->enmCpuTest; + pThis->enmPrefixKind = (BS3CG1PFXKIND)pInstr->enmPrefixKind; + pThis->enmXcptType = (BS3CG1XCPTTYPE)pInstr->enmXcptType; + pThis->cchMnemonic = pInstr->cchMnemonic; + if (pThis->fAdvanceMnemonic) + Bs3TestSubF("%s / %.*s", pThis->pszModeShort, pThis->cchMnemonic, pThis->pchMnemonic); + pThis->fAdvanceMnemonic = pInstr->fAdvanceMnemonic; + pThis->uOpcodeMap = pInstr->uOpcodeMap; + pThis->cOperands = pInstr->cOperands; + pThis->cbOpcodes = pInstr->cbOpcodes; + switch (pThis->cOperands) + { + case 4: pThis->aenmOperands[3] = (BS3CG1OP)pThis->pabOperands[3]; + case 3: pThis->aenmOperands[2] = (BS3CG1OP)pThis->pabOperands[2]; + case 2: pThis->aenmOperands[1] = (BS3CG1OP)pThis->pabOperands[1]; + case 1: pThis->aenmOperands[0] = (BS3CG1OP)pThis->pabOperands[0]; + } + switch (pThis->cbOpcodes) + { + case 4: pThis->abOpcodes[3] = pThis->pabOpcodes[3]; + case 3: pThis->abOpcodes[2] = pThis->pabOpcodes[2]; + case 2: pThis->abOpcodes[1] = pThis->pabOpcodes[1]; + case 1: pThis->abOpcodes[0] = pThis->pabOpcodes[0]; + } + + /* + * Check if the CPU supports the instruction. + */ + pThis->fCpuSetupFirstResult = Bs3Cg1CpuSetupFirst(pThis); + if ( !pThis->fCpuSetupFirstResult + || (pThis->fFlags & (BS3CG1INSTR_F_UNUSED | BS3CG1INSTR_F_INVALID))) + fOuterInvalidInstr = true; + + /* Switch the encoder for some of the invalid instructions on non-intel CPUs. */ + if ( (pThis->fFlags & BS3CG1INSTR_F_INTEL_DECODES_INVALID) + && pThis->bCpuVendor != BS3CPUVENDOR_INTEL + && ( (pThis->fFlags & (BS3CG1INSTR_F_UNUSED | BS3CG1INSTR_F_INVALID)) + || (BS3CG1_IS_64BIT_TARGET(pThis) && (pThis->fFlags & BS3CG1INSTR_F_INVALID_64BIT)) + || fOuterInvalidInstr ) ) + pThis->enmEncoding = Bs3Cg1CalcNoneIntelInvalidEncoding(pThis->enmEncoding); + + for (iCpuSetup = 0;; iCpuSetup++) + { + unsigned iEncoding; + unsigned iEncodingNext; + + /* + * Prep the operands and encoding handling. + */ + Bs3Cg1SetOpSizes(pThis, pThis->bMode); + if (!Bs3Cg1EncodePrep(pThis)) + break; + + /* + * Encode the instruction in various ways and check out the test values. + */ + for (iEncoding = 0;; iEncoding = iEncodingNext) + { + /* + * Encode the next instruction variation. + */ + pThis->fInvalidEncoding = fOuterInvalidInstr; + iEncodingNext = Bs3Cg1EncodeNext(pThis, iEncoding); + if (iEncodingNext <= iEncoding) + break; + BS3CG1_DPRINTF(("\ndbg: Encoding #%u: cbCurInst=%u: %.*Rhxs fInvalidEncoding=%d\n", + iEncoding, pThis->cbCurInstr, pThis->cbCurInstr, pThis->abCurInstr, pThis->fInvalidEncoding)); + + /* + * Do the rings. + */ + for (iRing = pThis->iFirstRing + pThis->fSameRingNotOkay; iRing < pThis->iEndRing; iRing++) + { + PCBS3CG1TESTHDR pHdr; + + pThis->uCpl = iRing; + BS3CG1_DPRINTF(("dbg: Ring %u\n", iRing)); + + /* + * Do the tests one by one. + */ + pHdr = pThis->pTestHdr; + for (pThis->iTest = 0;; pThis->iTest++) + { + if (Bs3Cg1RunSelector(pThis, pHdr)) + { + /* Okay, set up the execution context. */ + unsigned offCode; + uint8_t BS3_FAR *pbCode; + + Bs3MemCpy(&pThis->Ctx, &pThis->aInitialCtxs[iRing], sizeof(pThis->Ctx)); + if (pThis->fWorkExtCtx) + Bs3ExtCtxCopy(pThis->pExtCtx, pThis->pInitialExtCtx); + if (BS3_MODE_IS_PAGED(pThis->bMode)) + { + offCode = X86_PAGE_SIZE - pThis->cbCurInstr; + pbCode = &pThis->pbCodePg[offCode]; + //if (iEncoding > 0) { pbCode[-1] = 0xf4; offCode--; } + } + else + { + pbCode = pThis->pbCodePg; + pbCode[pThis->cbCurInstr] = 0x0f; /* UD2 */ + pbCode[pThis->cbCurInstr + 1] = 0x0b; + offCode = 0; + } + pThis->Ctx.rip.u = pThis->CodePgRip + offCode; + Bs3MemCpy(pbCode, pThis->abCurInstr, pThis->cbCurInstr); + + if (Bs3Cg1RunContextModifier(pThis, &pThis->Ctx, pHdr, pHdr->cbSelector, pHdr->cbInput, NULL, pbCode)) + { + /* Run the instruction. */ + BS3CG1_DPRINTF(("dbg: Running test #%u\n", pThis->iTest)); + //Bs3RegCtxPrint(&pThis->Ctx); + if (pThis->fWorkExtCtx) + Bs3ExtCtxRestore(pThis->pExtCtx); + Bs3TrapSetJmpAndRestore(&pThis->Ctx, &pThis->TrapFrame); + if (pThis->fWorkExtCtx) + Bs3ExtCtxSave(pThis->pResultExtCtx); + BS3CG1_DPRINTF(("dbg: bXcpt=%#x rip=%RX64 -> %RX64\n", + pThis->TrapFrame.bXcpt, pThis->Ctx.rip.u, pThis->TrapFrame.Ctx.rip.u)); + + /* + * Apply the output modification program to the context. + */ + pThis->Ctx.rflags.u32 &= ~X86_EFL_RF; + pThis->Ctx.rflags.u32 |= pThis->TrapFrame.Ctx.rflags.u32 & X86_EFL_RF; + pThis->bValueXcpt = UINT8_MAX; //??? + if ( pThis->fInvalidEncoding + || pThis->bAlignmentXcpt != UINT8_MAX + || pThis->bValueXcpt != UINT8_MAX + || Bs3Cg1RunContextModifier(pThis, &pThis->Ctx, pHdr, + pHdr->cbSelector + pHdr->cbInput, pHdr->cbOutput, + &pThis->TrapFrame.Ctx, NULL /*pbCode*/)) + Bs3Cg1CheckResult(pThis, bTestXcptExpected, false /*fInvalidEncodingPgFault*/, iEncoding); + else + { + Bs3TestPrintf("Bs3Cg1RunContextModifier(out): iEncoding=%u iTest=%RU32 iInstr=%u %.*s\n", + iEncoding, pThis->iTest, pThis->iInstr, pThis->cchMnemonic, pThis->pchMnemonic); + ASMHalt(); + } + + /* + * If this is an invalid encoding or instruction, check that we + * get a page fault when shortening it by one byte. + * (Since we didn't execute the output context modifier, we don't + * need to re-initialize the start context.) + */ + if ( pThis->fInvalidEncoding + && BS3_MODE_IS_PAGED(pThis->bMode) + && pThis->cbCurInstr) + { + pbCode += 1; + offCode += 1; + pThis->Ctx.rip.u = pThis->CodePgRip + offCode; + Bs3MemCpy(pbCode, pThis->abCurInstr, pThis->cbCurInstr - 1); + + /* Run the instruction. */ + BS3CG1_DPRINTF(("dbg: Running test #%u (cut short #PF)\n", pThis->iTest)); + //Bs3RegCtxPrint(&pThis->Ctx); + if (pThis->fWorkExtCtx) + Bs3ExtCtxRestore(pThis->pExtCtx); + Bs3TrapSetJmpAndRestore(&pThis->Ctx, &pThis->TrapFrame); + if (pThis->fWorkExtCtx) + Bs3ExtCtxSave(pThis->pResultExtCtx); + BS3CG1_DPRINTF(("dbg: bXcpt=%#x rip=%RX64 -> %RX64 (cut short #PF)\n", + pThis->TrapFrame.bXcpt, pThis->Ctx.rip.u, pThis->TrapFrame.Ctx.rip.u)); + + /* Check it */ + pThis->Ctx.rflags.u32 &= ~X86_EFL_RF; + pThis->Ctx.rflags.u32 |= pThis->TrapFrame.Ctx.rflags.u32 & X86_EFL_RF; + Bs3Cg1CheckResult(pThis, X86_XCPT_PF, true /*fInvalidEncodingPgFault*/, iEncoding); + } + } + else + { + Bs3TestPrintf("Bs3Cg1RunContextModifier(in): iEncoding=%u iTest=%u iInstr=%RU32 %.*s\n", + iEncoding, pThis->iTest, pThis->iInstr, pThis->cchMnemonic, pThis->pchMnemonic); + ASMHalt(); + } + } + else + BS3CG1_DPRINTF(("dbg: Skipping #%u\n", pThis->iTest)); + + /* advance */ + if (pHdr->fLast) + { + BS3CG1_DPRINTF(("dbg: Last\n\n")); + break; + } + pHdr = (PCBS3CG1TESTHDR)((uint8_t BS3_FAR *)(pHdr + 1) + pHdr->cbInput + pHdr->cbOutput + pHdr->cbSelector); + } + } + } + + /* + * Clean up (segment registers, etc) and get the next CPU config. + */ + Bs3Cg1EncodeCleanup(pThis); + if (!Bs3Cg1CpuSetupNext(pThis, iCpuSetup, &fOuterInvalidInstr)) + break; + if (pThis->fFlags & (BS3CG1INSTR_F_UNUSED | BS3CG1INSTR_F_INVALID)) + fOuterInvalidInstr = true; + } + } + + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(Bs3Cg1Worker)(uint8_t bMode) +{ + uint8_t bRet = 1; + BS3CG1STATE This; + +#if 0 + /* (for debugging) */ + if (bMode != BS3_MODE_LM64) + return BS3TESTDOMODE_SKIPPED; +#endif + + if (BS3_CMN_NM(Bs3Cg1Init)(&This, bMode)) + { + bRet = BS3_CMN_NM(Bs3Cg1WorkerInner)(&This); + Bs3TestSubDone(); + } + Bs3Cg1Destroy(&This); + +#if 0 + /* (for debugging) */ + if (bMode == BS3_MODE_PPV86) + { + Bs3TestTerm(); + Bs3Shutdown(); + } +#endif + return bRet; +} + -- cgit v1.2.3