b4e1af8961
According to Intel(R)64 and IA-32 Architectures Software Developer's Manual, the following one-byte registers should be fetched when REX prefix is present (sorted by reg encoding index): AL, CL, DL, BL, SPL, BPL, SIL, DIL, R8L - R15L The first 8 are fetched if REX.R is zero, the last 8 if non-zero. The following registers should be fetched for instructions without REX prefix (also sorted by reg encoding index): AL, CL, DL, BL, AH, CH, DH, BH Current emulation code doesn't handle accesses to SPL, BPL, SIL, DIL when REX is present, thefore an instruction 40883e "mov %dil,(%rsi)" is decoded as "mov %bh,(%rsi)". That caused an infinite loop in vp_reset: https://lists.gnu.org/archive/html/qemu-devel/2018-10/msg03293.html Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Message-Id: <20181018134401.44471-1-r.bolshakov@yadro.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
326 lines
8.4 KiB
C
326 lines
8.4 KiB
C
/*
|
|
* Copyright (C) 2016 Veertu Inc,
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef HVF_X86_DECODE_H
|
|
#define HVF_X86_DECODE_H 1
|
|
|
|
#include "cpu.h"
|
|
#include "x86.h"
|
|
|
|
typedef enum x86_prefix {
|
|
/* group 1 */
|
|
PREFIX_LOCK = 0xf0,
|
|
PREFIX_REPN = 0xf2,
|
|
PREFIX_REP = 0xf3,
|
|
/* group 2 */
|
|
PREFIX_CS_SEG_OVEERIDE = 0x2e,
|
|
PREFIX_SS_SEG_OVEERIDE = 0x36,
|
|
PREFIX_DS_SEG_OVEERIDE = 0x3e,
|
|
PREFIX_ES_SEG_OVEERIDE = 0x26,
|
|
PREFIX_FS_SEG_OVEERIDE = 0x64,
|
|
PREFIX_GS_SEG_OVEERIDE = 0x65,
|
|
/* group 3 */
|
|
PREFIX_OP_SIZE_OVERRIDE = 0x66,
|
|
/* group 4 */
|
|
PREFIX_ADDR_SIZE_OVERRIDE = 0x67,
|
|
|
|
PREFIX_REX = 0x40,
|
|
} x86_prefix;
|
|
|
|
enum x86_decode_cmd {
|
|
X86_DECODE_CMD_INVL = 0,
|
|
|
|
X86_DECODE_CMD_PUSH,
|
|
X86_DECODE_CMD_PUSH_SEG,
|
|
X86_DECODE_CMD_POP,
|
|
X86_DECODE_CMD_POP_SEG,
|
|
X86_DECODE_CMD_MOV,
|
|
X86_DECODE_CMD_MOVSX,
|
|
X86_DECODE_CMD_MOVZX,
|
|
X86_DECODE_CMD_CALL_NEAR,
|
|
X86_DECODE_CMD_CALL_NEAR_ABS_INDIRECT,
|
|
X86_DECODE_CMD_CALL_FAR_ABS_INDIRECT,
|
|
X86_DECODE_CMD_CALL_FAR,
|
|
X86_DECODE_RET_NEAR,
|
|
X86_DECODE_RET_FAR,
|
|
X86_DECODE_CMD_ADD,
|
|
X86_DECODE_CMD_OR,
|
|
X86_DECODE_CMD_ADC,
|
|
X86_DECODE_CMD_SBB,
|
|
X86_DECODE_CMD_AND,
|
|
X86_DECODE_CMD_SUB,
|
|
X86_DECODE_CMD_XOR,
|
|
X86_DECODE_CMD_CMP,
|
|
X86_DECODE_CMD_INC,
|
|
X86_DECODE_CMD_DEC,
|
|
X86_DECODE_CMD_TST,
|
|
X86_DECODE_CMD_NOT,
|
|
X86_DECODE_CMD_NEG,
|
|
X86_DECODE_CMD_JMP_NEAR,
|
|
X86_DECODE_CMD_JMP_NEAR_ABS_INDIRECT,
|
|
X86_DECODE_CMD_JMP_FAR,
|
|
X86_DECODE_CMD_JMP_FAR_ABS_INDIRECT,
|
|
X86_DECODE_CMD_LEA,
|
|
X86_DECODE_CMD_JXX,
|
|
X86_DECODE_CMD_JCXZ,
|
|
X86_DECODE_CMD_SETXX,
|
|
X86_DECODE_CMD_MOV_TO_SEG,
|
|
X86_DECODE_CMD_MOV_FROM_SEG,
|
|
X86_DECODE_CMD_CLI,
|
|
X86_DECODE_CMD_STI,
|
|
X86_DECODE_CMD_CLD,
|
|
X86_DECODE_CMD_STD,
|
|
X86_DECODE_CMD_STC,
|
|
X86_DECODE_CMD_CLC,
|
|
X86_DECODE_CMD_OUT,
|
|
X86_DECODE_CMD_IN,
|
|
X86_DECODE_CMD_INS,
|
|
X86_DECODE_CMD_OUTS,
|
|
X86_DECODE_CMD_LIDT,
|
|
X86_DECODE_CMD_SIDT,
|
|
X86_DECODE_CMD_LGDT,
|
|
X86_DECODE_CMD_SGDT,
|
|
X86_DECODE_CMD_SMSW,
|
|
X86_DECODE_CMD_LMSW,
|
|
X86_DECODE_CMD_RDTSCP,
|
|
X86_DECODE_CMD_INVLPG,
|
|
X86_DECODE_CMD_MOV_TO_CR,
|
|
X86_DECODE_CMD_MOV_FROM_CR,
|
|
X86_DECODE_CMD_MOV_TO_DR,
|
|
X86_DECODE_CMD_MOV_FROM_DR,
|
|
X86_DECODE_CMD_PUSHF,
|
|
X86_DECODE_CMD_POPF,
|
|
X86_DECODE_CMD_CPUID,
|
|
X86_DECODE_CMD_ROL,
|
|
X86_DECODE_CMD_ROR,
|
|
X86_DECODE_CMD_RCL,
|
|
X86_DECODE_CMD_RCR,
|
|
X86_DECODE_CMD_SHL,
|
|
X86_DECODE_CMD_SAL,
|
|
X86_DECODE_CMD_SHR,
|
|
X86_DECODE_CMD_SHRD,
|
|
X86_DECODE_CMD_SHLD,
|
|
X86_DECODE_CMD_SAR,
|
|
X86_DECODE_CMD_DIV,
|
|
X86_DECODE_CMD_IDIV,
|
|
X86_DECODE_CMD_MUL,
|
|
X86_DECODE_CMD_IMUL_3,
|
|
X86_DECODE_CMD_IMUL_2,
|
|
X86_DECODE_CMD_IMUL_1,
|
|
X86_DECODE_CMD_MOVS,
|
|
X86_DECODE_CMD_CMPS,
|
|
X86_DECODE_CMD_SCAS,
|
|
X86_DECODE_CMD_LODS,
|
|
X86_DECODE_CMD_STOS,
|
|
X86_DECODE_CMD_BSWAP,
|
|
X86_DECODE_CMD_XCHG,
|
|
X86_DECODE_CMD_RDTSC,
|
|
X86_DECODE_CMD_RDMSR,
|
|
X86_DECODE_CMD_WRMSR,
|
|
X86_DECODE_CMD_ENTER,
|
|
X86_DECODE_CMD_LEAVE,
|
|
X86_DECODE_CMD_BT,
|
|
X86_DECODE_CMD_BTS,
|
|
X86_DECODE_CMD_BTC,
|
|
X86_DECODE_CMD_BTR,
|
|
X86_DECODE_CMD_BSF,
|
|
X86_DECODE_CMD_BSR,
|
|
X86_DECODE_CMD_IRET,
|
|
X86_DECODE_CMD_INT,
|
|
X86_DECODE_CMD_POPA,
|
|
X86_DECODE_CMD_PUSHA,
|
|
X86_DECODE_CMD_CWD,
|
|
X86_DECODE_CMD_CBW,
|
|
X86_DECODE_CMD_DAS,
|
|
X86_DECODE_CMD_AAD,
|
|
X86_DECODE_CMD_AAM,
|
|
X86_DECODE_CMD_AAS,
|
|
X86_DECODE_CMD_LOOP,
|
|
X86_DECODE_CMD_SLDT,
|
|
X86_DECODE_CMD_STR,
|
|
X86_DECODE_CMD_LLDT,
|
|
X86_DECODE_CMD_LTR,
|
|
X86_DECODE_CMD_VERR,
|
|
X86_DECODE_CMD_VERW,
|
|
X86_DECODE_CMD_SAHF,
|
|
X86_DECODE_CMD_LAHF,
|
|
X86_DECODE_CMD_WBINVD,
|
|
X86_DECODE_CMD_LDS,
|
|
X86_DECODE_CMD_LSS,
|
|
X86_DECODE_CMD_LES,
|
|
X86_DECODE_XMD_LGS,
|
|
X86_DECODE_CMD_LFS,
|
|
X86_DECODE_CMD_CMC,
|
|
X86_DECODE_CMD_XLAT,
|
|
X86_DECODE_CMD_NOP,
|
|
X86_DECODE_CMD_CMOV,
|
|
X86_DECODE_CMD_CLTS,
|
|
X86_DECODE_CMD_XADD,
|
|
X86_DECODE_CMD_HLT,
|
|
X86_DECODE_CMD_CMPXCHG8B,
|
|
X86_DECODE_CMD_CMPXCHG,
|
|
X86_DECODE_CMD_POPCNT,
|
|
|
|
X86_DECODE_CMD_FNINIT,
|
|
X86_DECODE_CMD_FLD,
|
|
X86_DECODE_CMD_FLDxx,
|
|
X86_DECODE_CMD_FNSTCW,
|
|
X86_DECODE_CMD_FNSTSW,
|
|
X86_DECODE_CMD_FNSETPM,
|
|
X86_DECODE_CMD_FSAVE,
|
|
X86_DECODE_CMD_FRSTOR,
|
|
X86_DECODE_CMD_FXSAVE,
|
|
X86_DECODE_CMD_FXRSTOR,
|
|
X86_DECODE_CMD_FDIV,
|
|
X86_DECODE_CMD_FMUL,
|
|
X86_DECODE_CMD_FSUB,
|
|
X86_DECODE_CMD_FADD,
|
|
X86_DECODE_CMD_EMMS,
|
|
X86_DECODE_CMD_MFENCE,
|
|
X86_DECODE_CMD_SFENCE,
|
|
X86_DECODE_CMD_LFENCE,
|
|
X86_DECODE_CMD_PREFETCH,
|
|
X86_DECODE_CMD_CLFLUSH,
|
|
X86_DECODE_CMD_FST,
|
|
X86_DECODE_CMD_FABS,
|
|
X86_DECODE_CMD_FUCOM,
|
|
X86_DECODE_CMD_FUCOMI,
|
|
X86_DECODE_CMD_FLDCW,
|
|
X86_DECODE_CMD_FXCH,
|
|
X86_DECODE_CMD_FCHS,
|
|
X86_DECODE_CMD_FCMOV,
|
|
X86_DECODE_CMD_FRNDINT,
|
|
X86_DECODE_CMD_FXAM,
|
|
|
|
X86_DECODE_CMD_LAST,
|
|
};
|
|
|
|
const char *decode_cmd_to_string(enum x86_decode_cmd cmd);
|
|
|
|
typedef struct x86_modrm {
|
|
union {
|
|
uint8_t modrm;
|
|
struct {
|
|
uint8_t rm:3;
|
|
uint8_t reg:3;
|
|
uint8_t mod:2;
|
|
};
|
|
};
|
|
} __attribute__ ((__packed__)) x86_modrm;
|
|
|
|
typedef struct x86_sib {
|
|
union {
|
|
uint8_t sib;
|
|
struct {
|
|
uint8_t base:3;
|
|
uint8_t index:3;
|
|
uint8_t scale:2;
|
|
};
|
|
};
|
|
} __attribute__ ((__packed__)) x86_sib;
|
|
|
|
typedef struct x86_rex {
|
|
union {
|
|
uint8_t rex;
|
|
struct {
|
|
uint8_t b:1;
|
|
uint8_t x:1;
|
|
uint8_t r:1;
|
|
uint8_t w:1;
|
|
uint8_t unused:4;
|
|
};
|
|
};
|
|
} __attribute__ ((__packed__)) x86_rex;
|
|
|
|
typedef enum x86_var_type {
|
|
X86_VAR_IMMEDIATE,
|
|
X86_VAR_OFFSET,
|
|
X86_VAR_REG,
|
|
X86_VAR_RM,
|
|
|
|
/* for floating point computations */
|
|
X87_VAR_REG,
|
|
X87_VAR_FLOATP,
|
|
X87_VAR_INTP,
|
|
X87_VAR_BYTEP,
|
|
} x86_var_type;
|
|
|
|
typedef struct x86_decode_op {
|
|
enum x86_var_type type;
|
|
int size;
|
|
|
|
int reg;
|
|
target_ulong val;
|
|
|
|
target_ulong ptr;
|
|
} x86_decode_op;
|
|
|
|
typedef struct x86_decode {
|
|
int len;
|
|
uint8_t opcode[4];
|
|
uint8_t opcode_len;
|
|
enum x86_decode_cmd cmd;
|
|
int addressing_size;
|
|
int operand_size;
|
|
int lock;
|
|
int rep;
|
|
int op_size_override;
|
|
int addr_size_override;
|
|
int segment_override;
|
|
int control_change_inst;
|
|
bool fwait;
|
|
bool fpop_stack;
|
|
bool frev;
|
|
|
|
uint32_t displacement;
|
|
uint8_t displacement_size;
|
|
struct x86_rex rex;
|
|
bool is_modrm;
|
|
bool sib_present;
|
|
struct x86_sib sib;
|
|
struct x86_modrm modrm;
|
|
struct x86_decode_op op[4];
|
|
bool is_fpu;
|
|
uint32_t flags_mask;
|
|
|
|
} x86_decode;
|
|
|
|
uint64_t sign(uint64_t val, int size);
|
|
|
|
uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode);
|
|
|
|
target_ulong get_reg_ref(CPUX86State *env, int reg, int rex, int is_extended,
|
|
int size);
|
|
target_ulong get_reg_val(CPUX86State *env, int reg, int rex, int is_extended,
|
|
int size);
|
|
void calc_modrm_operand(CPUX86State *env, struct x86_decode *decode,
|
|
struct x86_decode_op *op);
|
|
target_ulong decode_linear_addr(CPUX86State *env, struct x86_decode *decode,
|
|
target_ulong addr, enum X86Seg seg);
|
|
|
|
void init_decoder(void);
|
|
void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode,
|
|
struct x86_decode_op *op);
|
|
void calc_modrm_operand32(CPUX86State *env, struct x86_decode *decode,
|
|
struct x86_decode_op *op);
|
|
void calc_modrm_operand64(CPUX86State *env, struct x86_decode *decode,
|
|
struct x86_decode_op *op);
|
|
void set_addressing_size(CPUX86State *env, struct x86_decode *decode);
|
|
void set_operand_size(CPUX86State *env, struct x86_decode *decode);
|
|
|
|
#endif
|