cidet-core.cpp revision 9f4f6a59c4f15adc4398bdfbf271ffd2ef521085
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * CPU Instruction Decoding & Execution Tests - Simple Instructions.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Copyright (C) 2014 Oracle Corporation
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * available from http://www.virtualbox.org. This file is free software;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * General Public License (GPL) as published by the Free Software
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * The contents of this file may alternatively be used under the terms
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * of the Common Development and Distribution License Version 1.0
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * VirtualBox OSE distribution, in which case the provisions of the
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * CDDL are applicable instead of those of the GPL.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * You may elect to license modified versions of this file under the
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * terms and conditions of either the GPL or the CDDL or both.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/*******************************************************************************
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync* Defined Constants And Macros *
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync*******************************************************************************/
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#define CIDET_INSTR_TEST_OP_FLAG(a_pInstr, a_fFlag) \
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync#define CIDET_INSTR_TEST_OP_MASK_VALUE(a_pInstr, a_fMask, a_fValue) \
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync ( ((a_pInstr)->afOperands[0] & (a_fMask)) == (a_fValue) \
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync || ((a_pInstr)->afOperands[1] & (a_fMask)) == (a_fValue) \
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync && ( ((a_pInstr)->afOperands[2] & (a_fMask)) == (a_fValue) \
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync || ((a_pInstr)->afOperands[3] & (a_fMask)) == (a_fValue) ) ) )
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/** @def CIDET_DPRINTF
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Debug printf. */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync# define CIDET_DPRINTF(a) do { RTPrintf a; } while (0)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync# define CIDET_DPRINTF(a) do { } while (0)
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync/** @def CIDET_DEBUG_DISAS
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * Enables instruction disassembly. */
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync/*******************************************************************************
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync* Header Files *
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync*******************************************************************************/
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#if defined(CIDET_DPRINTF_ENABLED) || defined(CIDET_DEBUG_DISAS)
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/*******************************************************************************
d645696bf70e804f18f661a9b1b8b79c32a1b331vboxsync* Global Variables *
dccbbd8ec5b45b567312112e7edd5c7130d56262vboxsync*******************************************************************************/
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/** For translating CIDET_OF_Z_XXX values (after shifting). */
3f72ab7ee9d1539bfa4ed19972430194627b9273vboxsync /* [CIDET_OF_Z_NONE] = */ 0,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* [0xa] = */ 0,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* [0xb] = */ 0,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* [0xc] = */ 0,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* [0xd] = */ 0,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* [0xe] = */ 0,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/** Converts operand sizes in bytes to 64-bit masks. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/** Converts operand sizes in bytes to 64-bit signed max values. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncbool CidetInstrHasMrmMemOperand(PCCIDETINSTR pInstr)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync return CIDET_INSTR_TEST_OP_FLAG(pInstr, CIDET_OF_M_RM_ONLY_M);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncbool CidetInstrHasMrmRegOperand(PCCIDETINSTR pInstr)
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync return CIDET_INSTR_TEST_OP_FLAG(pInstr, CIDET_OF_M_RM_ONLY_R);
73a750ff6ce8ed53244049d291856a1eea296654vboxsyncbool CidetInstrRespondsToOperandSizePrefixes(PCCIDETINSTR pInstr)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync return CIDET_INSTR_TEST_OP_MASK_VALUE(pInstr, CIDET_OF_Z_MASK, CIDET_OF_Z_VAR_WDQ);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync AssertPtr(pThis); Assert(pThis->u32Magic == CIDETCORE_MAGIC);
83204c5c9e83c7825a8e0537821a199459b783c8vboxsync * Report a test failure via CIDET::pfnFailure
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @returns false
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync * @param pThis Pointer to the core structure.
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync * @param pszFormat Format string containing failure details.
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync * @param va Arguments referenced in @a pszFormat.
060664c5bfb70021bf92e01127d02b178b8c20acvboxsyncint CidetCoreSetErrorV(PCIDETCORE pThis, const char *pszFormat, va_list va)
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync return false;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Report a test failure via CIDET::pfnFailure
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @returns false
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pThis Pointer to the core structure.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pszFormat Format string containing failure details.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param ... Arguments referenced in @a pszFormat.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncbool CidetCoreSetError(PCIDETCORE pThis, const char *pszFormat, ...)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync return false;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Get a signed random number, with a given number of significant bytes.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @returns Random number.
83204c5c9e83c7825a8e0537821a199459b783c8vboxsync * @param pThis Pointer to the core structure.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param cbSignificant The number of significant bytes.
df3a016ea59e69ab2758221fd91e62a9782b144evboxsyncint64_t CidetCoreGetRandS64(PCIDETCORE pThis, uint8_t cbSignificant)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Get an unsigned random number, with a given number of significant bytes.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @returns Random number.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pThis Pointer to the core structure.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param cbSignificant The number of significant bytes.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncuint64_t CidetCoreGetRandU64(PCIDETCORE pThis, uint8_t cbSignificant)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync Assert(cbSignificant == 1 || cbSignificant == 2 || cbSignificant == 4 || cbSignificant == 8);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncvoid CidetCoreInitializeCtxTemplate(PCIDETCORE pThis)
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync pThis->InTemplateCtx.rfl = X86_EFL_1 | X86_EFL_ID | X86_EFL_IF | X86_EFL_RF;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync unsigned i = RT_ELEMENTS(pThis->InTemplateCtx.aGRegs);
7a6ba152515c963d275e7c1371ba39155ec6cf58vboxsync while (i-- > 0)
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync pThis->InTemplateCtx.aGRegs[i] = UINT64_C(0x3fefcc00daba005d)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync while (i-- > 0)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync pThis->InTemplateCtx.aGRegs[i] = UINT64_C(0xfada009b)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync while (i-- > 0)
41738f3838049e665b571d59d971cc5c74efb6dcvboxsync pThis->InTemplateCtx.aSRegs[i] = 0; /* Front end sets these afterwards. */
dfff275f489de72e78be4fb4fbc3a2780f0ee2aavboxsync * Sets the target mode.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Caller must set up default selector values after calling this function.
587f936a5f1c792ede2dcb60a7769780a3487c6fvboxsync * @returns VBox status code.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * @param pThis Pointer to the core structure.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync * @param bMode The new mode.
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsyncint CidetCoreSetTargetMode(PCIDETCORE pThis, uint8_t bMode)
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == CIDETCORE_MAGIC, VERR_INVALID_HANDLE);
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_RM:
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_PE_16:
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_PE_32:
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_PE_V86:
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_PP_16:
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_PP_V86:
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_PAE_16:
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_PAE_V86:
ae9f3922b0becc4f4b4fca43422314700a4ed8a7vboxsync //case CIDETMODE_LM_S16:
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync //case CIDETMODE_LM_32:
3238841f4d74fd0e37778c270ae81b177a98e21bvboxsyncbool CidetCoreIsEncodingCompatibleWithInstruction(PCIDETCORE pThis)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync return true;
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync * Selects the next address size mode.
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync * @returns @c true if done, @c false if the next wheel needs to be moved.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pThis The core state structure.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncstatic bool cidetCoreSetupNextBaseEncoding_AddressSize(PCIDETCORE pThis)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Reset to default.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync pThis->cbAddrMode = CIDETMODE_GET_BYTE_COUNT(pThis->bMode);
Assert(pThis->idxMrmRegOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRegOp].fIsMem);
pThis->idxMrmRegOp, pThis->aOperands[pThis->idxMrmRegOp].cb, CIDET_OF_K_IS_GPR(pThis->fMrmRegOp), iReg,
iReg++;
return iReg != 0;
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
iRm++;
iMod = 0;
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
iRm++;
switch (iRm)
if (iMod == 0)
if (iMod == 0)
default: AssertReleaseFailed();
iMod++;
static void cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(PCIDETCORE pThis, uint8_t iReg, bool f64Bit)
static bool cidetCoreSetupNextBaseEncoding_MrmRmMod_32bit64bit(PCIDETCORE pThis, uint8_t iReg, bool f64Bit)
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
if (CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fRexX && !pThis->fNoRexPrefix) /* should be ignored. */
iRm++;
iRm++;
iMod = 0;
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
iRm++;
iMod++;
AssertReleaseFailedReturn(false);
return iBase != 0;
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
return iIndex != 0;
default: AssertReleaseFailedReturn(false);
case X86_SREG_COUNT:
case X86_SREG_ES:
case X86_SREG_CS:
case X86_SREG_SS:
case X86_SREG_DS:
case X86_SREG_FS:
case X86_SREG_GS:
default: AssertReleaseFailedBreak();
while (iOp-- > 0)
default: AssertReleaseFailed();
AssertFailedReturn(false);
AssertReleaseFailedReturn(false);
AssertFailedReturn(false);
while (idxOp-- > 0)
pDataBuf++;
uint32_t cbOp = g_acbCidetOfSizes[(pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) >> CIDET_OF_Z_SHIFT];
return cbOp;
if (cbOp)
#ifdef VBOX_STRICT
switch (cbOp)
default: AssertFailed();
return cbOp;
AssertFailedReturn(false);
while (idxOp-- > 0)
: X86_SREG_ES;
pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
if (uRemainder != 0)
+ uRemainder;
pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
pThis->aOperands[idxOp].uImmDispValue += offSeg & (RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1);
pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffff00000000);
pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffffffff0000);
pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffff00000000);
pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffffffff0000);
case CIDET_OF_K_GPR:
case CIDET_OF_K_IMM:
case CIDET_OF_K_SREG:
case CIDET_OF_K_CR:
case CIDET_OF_K_SSE:
case CIDET_OF_K_AVX:
case CIDET_OF_K_AVX512:
case CIDET_OF_K_FPU:
case CIDET_OF_K_MMX:
case CIDET_OF_K_AVXFUTURE:
case CIDET_OF_K_SPECIAL:
case CIDET_OF_K_TEST:
case CIDET_OF_K_NONE:
AssertReleaseFailedReturn(false);
while (idxOp-- > 0)
if (!pThis->pfnSetupDataBuf(pThis, pThis->aOperands[idxOp].pDataBuf, pThis->aOperands[idxOp].In.pv))
|| pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iMemBaseReg] == pThis->aOperands[idxOp].uMemBaseRegValue);
off++;
off++;
off++;
AssertReleaseFailedReturn(false);
off++;
off++;
default: AssertReleaseFailedReturn(false);
while (iOp-- > 0)
default: AssertReleaseFailedReturn(false);
pThis->abInstr[off++] = 0x40 | (pThis->fRexB * 1) | (pThis->fRexX * 2) | (pThis->fRexR * 4) | (pThis->fRexW * 8);
AssertReleaseFailedReturn(false);
default: AssertReleaseFailedReturn(false);
while (iOp-- > 0)
default: AssertReleaseFailedReturn(false);
pThis->ExpectedCtx.rip = pThis->InCtx.rip + pThis->cbInstr; /** @todo account for expected traps. */
#ifdef CIDET_DEBUG_DISAS
static DECLCALLBACK(int) cidetCoreDisReadBytes(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
return VINF_SUCCESS;
#ifdef CIDET_DEBUG_DISAS
&Dis,
&cbInstr,
unsigned cExecuted = 0;
unsigned cSkipped = 0;
cExecuted++;
cSkipped++;
cSkipped++;
cSkipped++;
return fResult;