/* $Id$ */
/** @file
* CPU Instruction Decoding & Execution Tests - C/C++ Header.
*/
/*
* Copyright (C) 2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE 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.
*/
#ifndef ___cidet_h___
#define ___cidet_h___
/** @name CIDET - Operand flags.
* @{ */
#define CIDET_OF_Z_VAR_WDQ UINT32_C(0x00000900) /**< Variable size depending on size prefix (2, 4, or 8 bytes). */
#define CIDET_OF_Z_SPECIAL UINT32_C(0x00000f00) /**< Special size, see instruction flags or smth. */
#define CIDET_OF_K_GPR UINT32_C(0x00001000) /**< General purpose register. Includes memory when used with CIDET_OF_M_RM. */
#define CIDET_OF_K_VRX_TST_MASK UINT32_C(0x0000c000) /**< Used for testing for VRX register kind, see CIDET_OF_K_IS_VRX. */
#define CIDET_OF_K_VRX_TST_RES UINT32_C(0x00004000) /**< Used for testing for VRX register kind, see CIDET_OF_K_IS_VRX. */
/** Check if @a a_fOp is a general purpose register. */
/** Check if @a a_fOp is a XMM (SSE), YMM (AVX), ZMM (AVX-512) or similar register. */
/** Check if @a a_fOp1 and @a a_fOp2 specify the same kind of register,
* treating SSE, AVX, AVX-512 and AVX-future as the same kind and ignoring the
* special register kind. */
/** The operand defaults to 64-bit width in 64-bit mode, making 32-bit width
* inaccessible. */
/** Operand always uses the ES segment for memory accesses. */
/** @} */
/** @name CIDET - Instruction flags.
* @{ */
/** @} */
/**
* Callback function for setting up the input and expected output CPU contexts.
*
* @returns VBox status.
* @retval VINF_EOF when static test data wraps (first entry is returned).
* @retval VERR_NO_DATA if @a fInvalid is set and there are no invalid operand
* values for this instruction.
* @retval VERR_NOT_SUPPORTED if something in the setup prevents us from
* comming up with working set of inputs and outputs.
*
* @param pThis The core CIDET state structure. The InCtx
* and ExpectedCtx members will be modified.
* @param fInvalid When set, get the next invalid operands that will
* cause exceptions/faults.
*/
/** Pointer to a FNCIDETSETUPINOUT function. */
/**
* Instruction test descriptor.
*/
typedef struct CIDETINSTR
{
/** The mnemonic (kind of). */
const char *pszMnemonic;
/** Setup input and outputs. */
/** Number of opcode bytes. */
/** Opcode byte(s). */
/** Mandatory prefix (zero if not applicable). */
/** Number of operands. */
/** Operand flags. */
/** Flags. */
} CIDETINSTR;
/** Pointer to an instruction test descriptor. */
/**
* CPU Context with a few extra bits for expectations and results.
*/
typedef struct CIDETCPUCTX
{
#ifndef CIDET_REDUCED_CTX
#else
#endif
#ifndef CIDET_REDUCED_CTX
#endif
bool fTrickyStack; /**< Set if the stack might be bad. May come at the cost of accurate flags (32-bit). */
} CIDETCPUCTX;
/** Number of bytes of CIDETCPUCTX that can be compared quickly using memcmp.
* Anything following these bytes are not relevant to the compare. */
/** @name CPU mode + bits + environment.
* @{ */
#define CIDETMODE_BIT_MASK UINT8_C(0x0e) /**< The instruction bit count. Results in byte size when masked. */
/** Test if @a a_bMode is a 16-bit mode. */
/** Test if @a a_bMode is a 32-bit mode. */
/** Test if @a a_bMode is a 64-bit mode. */
/** Get the instruction bit count. */
/** Get the instruction byte count. */
/** Test if @a a_bMode long mode. */
/** Test if @a a_bMode some kind of protected mode. */
/** @} */
/** @name Test Configuration Flags.
* @{ */
/** @} */
/** */
typedef enum CIDETREG
{
&& (a_iReg) == kCidetReg_Ctrl_cr2 \
&& (a_iReg) == kCidetReg_Ctrl_cr3 \
&& (a_iReg) == kCidetReg_Ctrl_cr4 \
&& (a_iReg) == kCidetReg_Ctrl_cr8 )
#define CIDETREG_DBG_IS_VALID(a_iReg) ((a_iReg) < kCidetReg_Dbg_dr8 && (a_iReg) >= kCidetReg_Dbg_First)
} CIDETREG;
/** @name CIDETBUF_XXX - buffer flags.
* @{ */
#define CIDETBUF_PROT_RWX_1NP UINT32_C(0x00000005) /**< Read + write + execute; 1 page not present. */
#define CIDETBUF_PROT_RWX_1RWNX UINT32_C(0x00000006) /**< Read + write + execute; 1 page read + write + no execute. */
#define CIDETBUF_PROT_RWX_1RNX UINT32_C(0x00000007) /**< Read + write + execute; 1 page read + no execute. */
#define CIDETBUF_PROT_RWX_1RWXS UINT32_C(0x00000008) /**< Read + write + execute; 1 page read + execute + supervisor. */
/** Buffer located at top and start of the 32-bit address space. */
/** Buffer located at the low canonical boundrary (AMD64). */
/** Buffer located at the high canonical boundrary (AMD64). */
/** Segment protection mask. */
#define CIDETBUF_SEG_LIMIT_BASE_CAP UINT32_C(0x00008000) /**< Capability to change segment limit and base. */
/** Checks if @a a_fFlags describes a code buffer. */
/** Checks if @a a_fFlags describes a data buffer. */
/** @} */
/** Code buffer size. (At least two pages.) */
/** Data buffer size. (At least two pages.) */
/**
* Detailed expected exception.
*
* This is used to internally in the core to calculate the expected exception
* considering all the things that may cause exceptions.
*/
typedef enum CIDETEXPECTXCPT
{
/** No exception expected. */
/** Page not present. */
/** Write access to a non-writable page. */
/** Executable access to a non-executable page. */
/** Access to supervisor page from user mode code. */
/** Read or write access to an execute only segment. */
/** Write to a read only or execute+read segment. */
/** Exceeded the limit of a non-stack access. */
/** Non-canonical address via any segment other than the stack. */
/** Misaligned 16 or 32 byte SSE or AVX operand. */
/** Privileged instruction. */
/** Exceeded the limit of a stack access. */
/** Non-canonical stack address. */
/** Misaligned memory operand (and alignment checking is in effect) if AC is
* enabled (executing in ring-3). */
/** Misaligned 16 byte memory operand resulting in \#AC if ring-3 and
* enable, otherwise \#GP(0). */
/**
* Buffer configuration.
*/
typedef struct CIDETBUFCFG
{
/** The name of this buffer configuration. */
const char *pszName;
/** The buffer flags (CIDETBUF_XXX) */
} CIDETBUFCFG;
/** Pointer to a constant buffer configuration. */
/**
* CIDET buffer for code or data.
*
* ASSUMES page aligned buffers.
*/
typedef struct CIDETBUF
{
/** @name Owned & modified by the front end.
* @{ */
/** Effective buffer address. */
/** The segment base address. */
/** The active segment limit (see also cbSegLimit). UINT64_MAX if flat. */
/** This specifies the selector to use if a non-flat segment limit or special
* segment flags was requested via pfnSetupBuf. UINT32_MAX if any segment is
* selector works. */
/** The off value at the last pfnReinitBuf call. */
/** The cb value at the last pfnReinitBuf call. */
/** Prologue (or front fence) size. */
/** Epilogue (or tail fence) size. */
/** @} */
/** @name Set by the core before pfnReinitBuf call.
* @{ */
/** Pointer to the buffer config. */
/** The configuration index. */
/** The offset into the buffer of the data / code. */
/** The number of bytes of data / code. */
/** The segment limit relative to the start of the buffer (last byte included
* in count). UINT16_MAX if maximum segment size should be used. */
/** Desired segment base offset.
* This is for checking where the alignment checks are performed. */
/** Set if this buffer is actively being used. */
/** The operand index (if data), 7 if not active. */
/** Code: Set if the expected exception is supposed to occur on the
* following insturction, not the instruction unter test. */
/** Set if the instruction will read from the buffer. */
/** Set if the instruction will write to the buffer. */
/** The expected exception. */
/** @} */
} CIDETBUF;
/** Pointer to a CIDET buffer for code or data. */
/**
* CPU Instruction Decoding & Execution Testing (CIDET) state.
*/
typedef struct CIDETCORE
{
/** Magic number (CIDETCORE_MAGIC). */
/** The target CPU mode / environment. */
/** The target ring. */
/** Unused padding bytes. */
/** Test configuration. */
/** Code buffer configurations to test.
* The first buffer must be a normal buffer that does not cause any problems. */
/** The number of code buffer configurations to test (pafCodeBufConfigs). */
/** The number of data buffer configurations to test (pafDataBufConfigs). */
/** Data buffer configurations to test.
* The first buffer must be a normal buffer that does not cause any problems. */
/** The instruction currently under testing. */
/** Primary data buffer. */
/** Secondary data buffer. */
/** Handle to the random number source. */
/**
* Re-initializes one of the data buffers.
*
* @returns true on succes, false if the request cannot be satisfied.
* @param pThis The core state.
* @param pBuf Pointer to the buffer structure.
*/
/**
* Copies bytes into the data buffer and sets it up for execution.
*
* @returns true on succes, false if the request cannot be satisfied.
* @param pThis The core state.
* @param pBuf Pointer to the buffer structure.
* @param pvSrc The source bytes (size and destination offset
* given in pfnReinitBuf call).
*/
DECLCALLBACKMEMBER(bool, pfnSetupDataBuf)(struct CIDETCORE *pThis, PCIDETBUF pBuf, void const *pvSrc);
/**
* Compares buffer content after test execution.
*
* This also checks any fill bytes in the buffer that the front end may
* have put up. The front end will double buffer the content of supposedly
* inaccessible pages as well as non-existing pages to simplify things for
* the core code.
*
* @returns true if equal, false if not.
* @param pThis The core state.
* @param pBuf Pointer to the buffer structure.
* @param pvExpected Pointer to the expected source bytes (size and
* buffer offset given in pfnReinitBuf call).
*/
DECLCALLBACKMEMBER(bool, pfnIsBufEqual)(struct CIDETCORE *pThis, struct CIDETBUF *pBuf, void const *pvExpected);
/**
* Re-initializes the code buffer.
*
* @returns true on succes, false if the request cannot be satisfied.
* @param pThis The core state.
* @param pBuf Pointer to the CodeBuf member. The off and cb
* members represent what the core wants to
* execute.
*/
/**
* Emit code into the code buffer, making everything ready for pfnExecute.
*
* @returns VBox status code.
* @param pThis Pointer to the core structure.
* @param pBuf Pointer to the CodeBuf member.
* @param pvInstr Pointer to the encoded instruction bytes.
*/
DECLCALLBACKMEMBER(bool, pfnSetupCodeBuf)(struct CIDETCORE *pThis, PCIDETBUF pBuf, void const *pvInstr);
/**
* Executes the code indicated by InCtx, returning the result in ActualCtx.
*
* @returns true if execute, false if skipped.
* @param pThis Pointer to the core structure.
*/
/**
* Report a test failure.
*
* @param pThis Pointer to the core structure.
* @param pszFormat Format string containing failure details.
* @param va Arguments referenced in @a pszFormat.
*/
/** Array of indexes for use by FNCIDETSETUPINOUT.
* Reset when changing instruction or switching between valid and invalid
* inputs. */
/** @name Copyied and extracted instruction information.
* @{ */
/** The flags (CIDET_OF_XXX) for the MODRM.REG operand, 0 if not applicable. */
/** The flags (CIDET_OF_XXX) for the MODRM.RM operand, 0 if not applicable. */
/** Instruction flags (CIDETINSTR::fFlags). */
/** Number of operands (CIDETINSTR::cOperands). */
/** Number of memory operands (set by CidetCoreSetupFirstMemoryOperandConfig). */
/** Set if we're working on a MOD R/M byte. */
/** The index of the MODRM.REG operand, 7 if not applicable. */
/** The index of the MODRM.RM operand, 7 if not applicable. */
/** Set if the SIB byte uses VEX registers for indexing. */
/** @} */
/** @name Basic encoding knobs, wheels and indicators.
* @{ */
/** Set if we're working on a SIB byte. */
/** Required segment prefix (X86_SREG_XXX), X86_SREG_COUNT if not. */
/** The address size prefix. */
/** The operand size prefix. */
/** The REX.W prefix value. */
/** The REX.R prefix value. */
/** The REX.X prefix value. */
/** The REX.B prefix value. */
/** Set if a REX prefix is required with or without flags (for byte regs). */
/** Use VEX encoding. */
/** Use EVEX encoding. */
/** Indicator: Effective addressing mode in bytes (2, 4, 8). */
/** Indicator: Set if there is an operand accessing memory. */
/** Indicator: Set if a register is used in two or more operands, and one of
* them being for addressing. */
/** Indicator: Helper indicator for tracking SIB.BASE collision. */
/** Indicator: Helper indicator for tracking SIB.INDEX collision. */
/** Indicator: Set if a register is used directly in more than one operand. */
/** Indicator: Set if MODRM.REG is the stack register. */
/** Indicator: Set if MODRM.RM or SIB.BASE is the stack register. */
/** Indicator: High byte-register specified by MODRM.REG. */
/** Indicator: High byte-register specified by MODRM.RM. */
/** Indicator: Set if REX prefixes are incompatible with the byte-register
* specified by MODRM.REG. */
/** Indicator: Set if REX prefixes are incompatible with the byte-register
* specified by MODRM.RM. */
/** Indicator: fNoRexPrefixMrmReg || fNoRexPrefixMrmMr. */
/** The MOD R/M byte we're working on (if fUsesModRm is set). */
/** @} */
/** The effective instruction address. (See InCtx.rip and InCtx.cs for the
* rest of the instruction addressing stuff.) */
/** Operand information, mainly for the FNCIDETSETUPINOUT and similar. */
struct
{
/** The operand flags copied from (CIDETINSTR::afOperands). */
/** The encoded register number, if register, UINT8_MAX if not. */
/** The actual operand size (encoded). */
/** Set if immediate value. */
/** Set if memory access. */
/** Set if addressing is relative to RIP. */
/** Set if it's a high byte register. */
/** Size of the disposition, 0 if none. */
/** Base register, UINT8_MAX if not applicable. */
/** Index register, UINT8_MAX if not applicable. */
/** Index register, 1 if not applicable. */
/** Effective segment register, UINT8_MAX if not memory access. */
/** Segment offset if memory access. Undefined if not memory access. */
/** The effective address if memory access. */
/** Immediate or displacement value. */
/** Base register value, undefined if irrelevant. */
/** Index register value, undefined if irrelevant. */
/** Points to where the input data for this operand should be placed,
* when possible. In the fIsMem = true case, it either points directly
* to the input buffer or to a temporary one. While in the other case,
* it'll point into InCtx when possible. */
/** Points to where the expected output data for this operand should be
* stored, when possible. In the fIsMem = false case, it'll point into
* ExpectedCtx when possible. */
/** Pointer to the data buffer for this operand. */
/** Buffer where we assemble the instruction. */
/** The size of the instruction in abInstr. */
/** Offset of the instruction into the buffer. */
/** Current code buffer. */
/** The input context. Initalized by driver and FNCIDETSETUPINOUT. */
/** The expected output context. */
/** The actual output context. */
/** Template input context, initialized when setting the mode. */
/** Input and expected output temporary memory buffers. */
/** Number of skipped tests because of pfnSetupInOut failures. */
/** Number of skipped tests because of pfnReInitDataBuf failures. */
/** Number of skipped tests because of pfnSetupDataBuf failures. */
/** Number of skipped tests because RIP relative addressing constraints. */
/** Number of skipped tests because of assemble failures. */
/** Number of skipped tests because of pfnReInitCodeBuf failures. */
/** Number of skipped tests because of pfnSetupCodeBuf failures. */
/** Number of skipped tests because the base and index registers are the same
* one and there was a remainder when trying to point to the data buffer. */
/** Number of skipped tests because index-only addressing left a remainder. */
/** Number of skipped tests because of direct addressing overflowed. */
} CIDETCORE;
/** Pointer to the CIDET core state. */
/** Magic number for CIDETCORE (Lee Konitz). */
extern const CIDETINSTR g_aCidetInstructions1[];
extern const uint32_t g_cCidetInstructions1;
#endif