/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT 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; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT 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
/******************************************************************************
* x86_emulate.c
*
* Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
*
* Copyright (c) 2005-2007 Keir Fraser
*
* 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; 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __XEN__
#include <stddef.h>
#include <stdint.h>
#include <public/xen.h>
#else
#include <xen/config.h>
#include <xen/types.h>
#include <xen/lib.h>
#include <asm/regs.h>
#undef cmpxchg
#endif
#include <asm-x86/x86_emulate.h>
/* Operand sizes: 8-bit operands or specified/overridden size. */
#define ByteOp (1<<0) /* 8-bit operands. */
/* Destination operand type. */
#define DstBitBase (0<<1) /* Memory operand, bit string. */
#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
#define DstReg (2<<1) /* Register operand. */
#define DstMem (3<<1) /* Memory operand. */
#define DstMask (3<<1)
/* Source operand type. */
#define SrcNone (0<<3) /* No source operand. */
#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
#define SrcReg (1<<3) /* Register operand. */
#define SrcMem (2<<3) /* Memory operand. */
#define SrcMem16 (3<<3) /* Memory operand (16-bit). */
#define SrcImm (4<<3) /* Immediate operand. */
#define SrcImmByte (5<<3) /* 8-bit sign-extended immediate operand. */
#define SrcMask (7<<3)
/* Generic ModRM decode. */
#define ModRM (1<<6)
/* Destination is only written; never read. */
#define Mov (1<<7)
static uint8_t opcode_table[256] = {
/* 0x00 - 0x07 */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
/* 0x08 - 0x0F */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
/* 0x10 - 0x17 */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
/* 0x18 - 0x1F */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, 0,
/* 0x20 - 0x27 */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, ImplicitOps,
/* 0x28 - 0x2F */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, ImplicitOps,
/* 0x30 - 0x37 */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, ImplicitOps,
/* 0x38 - 0x3F */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcImm, DstReg|SrcImm, 0, ImplicitOps,
/* 0x40 - 0x4F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x50 - 0x5F */
ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov, ImplicitOps|Mov,
/* 0x60 - 0x67 */
ImplicitOps, ImplicitOps, DstReg|SrcMem|ModRM, DstReg|SrcMem16|ModRM|Mov,
0, 0, 0, 0,
/* 0x68 - 0x6F */
ImplicitOps|Mov, DstMem|SrcImm|ModRM|Mov,
ImplicitOps|Mov, DstMem|SrcImmByte|ModRM|Mov,
0, 0, 0, 0,
/* 0x70 - 0x77 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x78 - 0x7F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x80 - 0x87 */
ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
/* 0x88 - 0x8F */
ByteOp|DstMem|SrcReg|ModRM|Mov, DstMem|SrcReg|ModRM|Mov,
ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
0, DstReg|SrcNone|ModRM, 0, DstMem|SrcNone|ModRM|Mov,
/* 0x90 - 0x97 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x98 - 0x9F */
ImplicitOps, ImplicitOps, 0, 0, 0, 0, ImplicitOps, ImplicitOps,
/* 0xA0 - 0xA7 */
ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, 0, 0,
/* 0xA8 - 0xAF */
ByteOp|DstReg|SrcImm, DstReg|SrcImm,
ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, 0, 0,
/* 0xB0 - 0xB7 */
ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
ByteOp|DstReg|SrcImm|Mov, ByteOp|DstReg|SrcImm|Mov,
/* 0xB8 - 0xBF */
DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov, DstReg|SrcImm|Mov,
/* 0xC0 - 0xC7 */
ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
ImplicitOps, ImplicitOps,
0, 0, ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov,
/* 0xC8 - 0xCF */
0, 0, 0, 0, 0, 0, 0, 0,
/* 0xD0 - 0xD7 */
ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0xD8 - 0xDF */
0, 0, 0, 0, 0, 0, 0, 0,
/* 0xE0 - 0xE7 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, 0, 0, 0, 0,
/* 0xE8 - 0xEF */
ImplicitOps, ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0,
/* 0xF0 - 0xF7 */
0, 0, 0, 0,
0, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
/* 0xF8 - 0xFF */
ImplicitOps, ImplicitOps, 0, 0,
ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
};
static uint8_t twobyte_table[256] = {
/* 0x00 - 0x0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0,
/* 0x10 - 0x17 */
0, 0, 0, 0, 0, 0, 0, 0,
/* 0x18 - 0x1F */
ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM,
ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM, ImplicitOps|ModRM,
/* 0x20 - 0x2F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 - 0x3F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 - 0x47 */
DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
/* 0x48 - 0x4F */
DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
/* 0x50 - 0x5F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x60 - 0x6F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x70 - 0x7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x80 - 0x87 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x88 - 0x8F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x90 - 0x97 */
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
/* 0x98 - 0x9F */
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
/* 0xA0 - 0xA7 */
0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0,
/* 0xA8 - 0xAF */
0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, DstReg|SrcMem|ModRM,
/* 0xB0 - 0xB7 */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
0, DstBitBase|SrcReg|ModRM,
0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
/* 0xB8 - 0xBF */
0, 0, DstBitBase|SrcImmByte|ModRM, DstBitBase|SrcReg|ModRM,
DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
/* 0xC0 - 0xC7 */
ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, 0,
0, 0, 0, ImplicitOps|ModRM,
/* 0xC8 - 0xCF */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0xD0 - 0xDF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xE0 - 0xEF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xF0 - 0xFF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* Type, address-of, and value of an instruction's operand. */
struct operand {
enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
unsigned int bytes;
unsigned long val, orig_val;
union {
/* OP_REG: Pointer to register field. */
unsigned long *reg;
/* OP_MEM: Segment and offset. */
struct {
enum x86_segment seg;
unsigned long off;
} mem;
};
};
/* EFLAGS bit definitions. */
#define EFLG_OF (1<<11)
#define EFLG_DF (1<<10)
#define EFLG_SF (1<<7)
#define EFLG_ZF (1<<6)
#define EFLG_AF (1<<4)
#define EFLG_PF (1<<2)
#define EFLG_CF (1<<0)
/* Exception definitions. */
#define EXC_DE 0
#define EXC_BR 5
#define EXC_UD 6
#define EXC_GP 13
/*
* Instruction emulation:
* Most instructions are emulated directly via a fragment of inline assembly
* code. This allows us to save/restore EFLAGS and thus very easily pick up
* any modified flags.
*/
#if defined(__x86_64__)
#define _LO32 "k" /* force 32-bit operand */
#define _STK "%%rsp" /* stack pointer */
#elif defined(__i386__)
#define _LO32 "" /* force 32-bit operand */
#define _STK "%%esp" /* stack pointer */
#endif
/*
* These EFLAGS bits are restored from saved value during emulation, and
* any changes are written back to the saved value after emulation.
*/
#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)
/* Before executing instruction: restore necessary bits in EFLAGS. */
#define _PRE_EFLAGS(_sav, _msk, _tmp) \
/* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); */\
"push %"_sav"; " \
"movl %"_msk",%"_LO32 _tmp"; " \
"andl %"_LO32 _tmp",("_STK"); " \
"pushf; " \
"notl %"_LO32 _tmp"; " \
"andl %"_LO32 _tmp",("_STK"); " \
"pop %"_tmp"; " \
"orl %"_LO32 _tmp",("_STK"); " \
"popf; " \
/* _sav &= ~msk; */ \
"movl %"_msk",%"_LO32 _tmp"; " \
"notl %"_LO32 _tmp"; " \
"andl %"_LO32 _tmp",%"_sav"; "
/* After executing instruction: write-back necessary bits in EFLAGS. */
#define _POST_EFLAGS(_sav, _msk, _tmp) \
/* _sav |= EFLAGS & _msk; */ \
"pushf; " \
"pop %"_tmp"; " \
"andl %"_msk",%"_LO32 _tmp"; " \
"orl %"_LO32 _tmp",%"_sav"; "
/* Raw emulation: instruction has two explicit operands. */
#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy)\
do{ unsigned long _tmp; \
switch ( (_dst).bytes ) \
{ \
case 2: \
__asm__ __volatile__ ( \
_PRE_EFLAGS("0","4","2") \
_op"w %"_wx"3,%1; " \
_POST_EFLAGS("0","4","2") \
: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
: _wy ((_src).val), "i" (EFLAGS_MASK), \
"m" (_eflags), "m" ((_dst).val) ); \
break; \
case 4: \
__asm__ __volatile__ ( \
_PRE_EFLAGS("0","4","2") \
_op"l %"_lx"3,%1; " \
_POST_EFLAGS("0","4","2") \
: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
: _ly ((_src).val), "i" (EFLAGS_MASK), \
"m" (_eflags), "m" ((_dst).val) ); \
break; \
case 8: \
__emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy); \
break; \
} \
} while (0)
#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy)\
do{ unsigned long _tmp; \
switch ( (_dst).bytes ) \
{ \
case 1: \
__asm__ __volatile__ ( \
_PRE_EFLAGS("0","4","2") \
_op"b %"_bx"3,%1; " \
_POST_EFLAGS("0","4","2") \
: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
: _by ((_src).val), "i" (EFLAGS_MASK), \
"m" (_eflags), "m" ((_dst).val) ); \
break; \
default: \
__emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy);\
break; \
} \
} while (0)
/* Source operand is byte-sized and may be restricted to just %cl. */
#define emulate_2op_SrcB(_op, _src, _dst, _eflags) \
__emulate_2op(_op, _src, _dst, _eflags, \
"b", "c", "b", "c", "b", "c", "b", "c")
/* Source operand is byte, word, long or quad sized. */
#define emulate_2op_SrcV(_op, _src, _dst, _eflags) \
__emulate_2op(_op, _src, _dst, _eflags, \
"b", "q", "w", "r", _LO32, "r", "", "r")
/* Source operand is word, long or quad sized. */
#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags) \
__emulate_2op_nobyte(_op, _src, _dst, _eflags, \
"w", "r", _LO32, "r", "", "r")
/* Instruction has only one explicit operand (no source operand). */
#define emulate_1op(_op,_dst,_eflags) \
do{ unsigned long _tmp; \
switch ( (_dst).bytes ) \
{ \
case 1: \
__asm__ __volatile__ ( \
_PRE_EFLAGS("0","3","2") \
_op"b %1; " \
_POST_EFLAGS("0","3","2") \
: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
: "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) ); \
break; \
case 2: \
__asm__ __volatile__ ( \
_PRE_EFLAGS("0","3","2") \
_op"w %1; " \
_POST_EFLAGS("0","3","2") \
: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
: "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) ); \
break; \
case 4: \
__asm__ __volatile__ ( \
_PRE_EFLAGS("0","3","2") \
_op"l %1; " \
_POST_EFLAGS("0","3","2") \
: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
: "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) ); \
break; \
case 8: \
__emulate_1op_8byte(_op, _dst, _eflags); \
break; \
} \
} while (0)
/* Emulate an instruction with quadword operands (x86/64 only). */
#if defined(__x86_64__)
#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) \
do{ __asm__ __volatile__ ( \
_PRE_EFLAGS("0","4","2") \
_op"q %"_qx"3,%1; " \
_POST_EFLAGS("0","4","2") \
: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
: _qy ((_src).val), "i" (EFLAGS_MASK), \
"m" (_eflags), "m" ((_dst).val) ); \
} while (0)
#define __emulate_1op_8byte(_op, _dst, _eflags) \
do{ __asm__ __volatile__ ( \
_PRE_EFLAGS("0","3","2") \
_op"q %1; " \
_POST_EFLAGS("0","3","2") \
: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
: "i" (EFLAGS_MASK), "m" (_eflags), "m" ((_dst).val) ); \
} while (0)
#elif defined(__i386__)
#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)
#define __emulate_1op_8byte(_op, _dst, _eflags)
#endif /* __i386__ */
/* Fetch next part of the instruction being emulated. */
#define insn_fetch_bytes(_size) \
({ unsigned long _x, _eip = _regs.eip; \
if ( !mode_64bit() ) _eip = (uint32_t)_eip; /* ignore upper dword */ \
_regs.eip += (_size); /* real hardware doesn't truncate */ \
generate_exception_if((uint8_t)(_regs.eip - ctxt->regs->eip) > 15, \
EXC_GP); \
rc = ops->insn_fetch(x86_seg_cs, _eip, &_x, (_size), ctxt); \
if ( rc ) goto done; \
_x; \
})
#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type)))
#define _truncate_ea(ea, byte_width) \
({ unsigned long __ea = (ea); \
(((byte_width) == sizeof(unsigned long)) ? __ea : \
(__ea & ((1UL << ((byte_width) << 3)) - 1))); \
})
#define truncate_ea(ea) _truncate_ea((ea), ad_bytes)
#define mode_64bit() (def_ad_bytes == 8)
#define fail_if(p) \
do { \
rc = (p) ? X86EMUL_UNHANDLEABLE : 0; \
if ( rc ) goto done; \
} while (0)
/* In future we will be able to generate arbitrary exceptions. */
#define generate_exception_if(p, e) fail_if(p)
/* Given byte has even parity (even number of 1s)? */
static int even_parity(uint8_t v)
{
__asm__ ( "test %%al,%%al; setp %%al"
: "=a" (v) : "0" (v) );
return v;
}
/* Update address held in a register, based on addressing mode. */
#define _register_address_increment(reg, inc, byte_width) \
do { \
int _inc = (inc); /* signed type ensures sign extension to long */ \
if ( (byte_width) == sizeof(unsigned long) ) \
(reg) += _inc; \
else if ( mode_64bit() ) \
(reg) = ((reg) + _inc) & ((1UL << ((byte_width) << 3)) - 1); \
else \
(reg) = ((reg) & ~((1UL << ((byte_width) << 3)) - 1)) | \
(((reg) + _inc) & ((1UL << ((byte_width) << 3)) - 1)); \
} while (0)
#define register_address_increment(reg, inc) \
_register_address_increment((reg), (inc), ad_bytes)
#define jmp_rel(rel) \
do { \
_regs.eip += (int)(rel); \
if ( !mode_64bit() ) \
_regs.eip = ((op_bytes == 2) \
? (uint16_t)_regs.eip : (uint32_t)_regs.eip); \
} while (0)
/*
* Unsigned multiplication with double-word result.
* IN: Multiplicand=m[0], Multiplier=m[1]
* OUT: Return CF/OF (overflow status); Result=m[1]:m[0]
*/
static int mul_dbl(unsigned long m[2])
{
int rc;
asm ( "mul %4; seto %b2"
: "=a" (m[0]), "=d" (m[1]), "=q" (rc)
: "0" (m[0]), "1" (m[1]), "2" (0) );
return rc;
}
/*
* Signed multiplication with double-word result.
* IN: Multiplicand=m[0], Multiplier=m[1]
* OUT: Return CF/OF (overflow status); Result=m[1]:m[0]
*/
static int imul_dbl(unsigned long m[2])
{
int rc;
asm ( "imul %4; seto %b2"
: "=a" (m[0]), "=d" (m[1]), "=q" (rc)
: "0" (m[0]), "1" (m[1]), "2" (0) );
return rc;
}
/*
* Unsigned division of double-word dividend.
* IN: Dividend=u[1]:u[0], Divisor=v
* OUT: Return 1: #DE
* Return 0: Quotient=u[0], Remainder=u[1]
*/
static int div_dbl(unsigned long u[2], unsigned long v)
{
if ( (v == 0) || (u[1] > v) || ((u[1] == v) && (u[0] != 0)) )
return 1;
asm ( "div %4"
: "=a" (u[0]), "=d" (u[1])
: "0" (u[0]), "1" (u[1]), "r" (v) );
return 0;
}
/*
* Signed division of double-word dividend.
* IN: Dividend=u[1]:u[0], Divisor=v
* OUT: Return 1: #DE
* Return 0: Quotient=u[0], Remainder=u[1]
* NB. We don't use idiv directly as it's moderately hard to work out
* ahead of time whether it will #DE, which we cannot allow to happen.
*/
static int idiv_dbl(unsigned long u[2], unsigned long v)
{
int negu = (long)u[1] < 0, negv = (long)v < 0;
/* u = abs(u) */
if ( negu )
{
u[1] = ~u[1];
if ( (u[0] = -u[0]) == 0 )
u[1]++;
}
/* abs(u) / abs(v) */
if ( div_dbl(u, negv ? -v : v) )
return 1;
/* Remainder has same sign as dividend. It cannot overflow. */
if ( negu )
u[1] = -u[1];
/* Quotient is overflowed if sign bit is set. */
if ( negu ^ negv )
{
if ( (long)u[0] >= 0 )
u[0] = -u[0];
else if ( (u[0] << 1) != 0 ) /* == 0x80...0 is okay */
return 1;
}
else if ( (long)u[0] < 0 )
return 1;
return 0;
}
static int
test_cc(
unsigned int condition, unsigned int flags)
{
int rc = 0;
switch ( (condition & 15) >> 1 )
{
case 0: /* o */
rc |= (flags & EFLG_OF);
break;
case 1: /* b/c/nae */
rc |= (flags & EFLG_CF);
break;
case 2: /* z/e */
rc |= (flags & EFLG_ZF);
break;
case 3: /* be/na */
rc |= (flags & (EFLG_CF|EFLG_ZF));
break;
case 4: /* s */
rc |= (flags & EFLG_SF);
break;
case 5: /* p/pe */
rc |= (flags & EFLG_PF);
break;
case 7: /* le/ng */
rc |= (flags & EFLG_ZF);
/* fall through */
case 6: /* l/nge */
rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF));
break;
}
/* Odd condition identifiers (lsb == 1) have inverted sense. */
return (!!rc ^ (condition & 1));
}
void *
decode_register(
uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs)
{
void *p;
switch ( modrm_reg )
{
case 0: p = ®s->eax; break;
case 1: p = ®s->ecx; break;
case 2: p = ®s->edx; break;
case 3: p = ®s->ebx; break;
case 4: p = (highbyte_regs ?
((unsigned char *)®s->eax + 1) :
(unsigned char *)®s->esp); break;
case 5: p = (highbyte_regs ?
((unsigned char *)®s->ecx + 1) :
(unsigned char *)®s->ebp); break;
case 6: p = (highbyte_regs ?
((unsigned char *)®s->edx + 1) :
(unsigned char *)®s->esi); break;
case 7: p = (highbyte_regs ?
((unsigned char *)®s->ebx + 1) :
(unsigned char *)®s->edi); break;
#if defined(__x86_64__)
case 8: p = ®s->r8; break;
case 9: p = ®s->r9; break;
case 10: p = ®s->r10; break;
case 11: p = ®s->r11; break;
case 12: p = ®s->r12; break;
case 13: p = ®s->r13; break;
case 14: p = ®s->r14; break;
case 15: p = ®s->r15; break;
#endif
default: p = NULL; break;
}
return p;
}
int
x86_emulate(
struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
/* Shadow copy of register state. Committed on successful emulation. */
struct cpu_user_regs _regs = *ctxt->regs;
uint8_t b, d, sib, sib_index, sib_base, twobyte = 0, rex_prefix = 0;
uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes;
unsigned int lock_prefix = 0, rep_prefix = 0;
int rc = 0;
struct operand src, dst;
/* Data operand effective address (usually computed from ModRM). */
struct operand ea;
/* Default is a memory operand relative to segment DS. */
ea.type = OP_MEM;
ea.mem.seg = x86_seg_ds;
ea.mem.off = 0;
op_bytes = def_op_bytes = ad_bytes = def_ad_bytes = ctxt->address_bytes;
if ( op_bytes == 8 )
{
op_bytes = def_op_bytes = 4;
#ifndef __x86_64__
return -1;
#endif
}
/* Prefix bytes. */
for ( ; ; )
{
switch ( b = insn_fetch_type(uint8_t) )
{
case 0x66: /* operand-size override */
op_bytes = def_op_bytes ^ 6;
break;
case 0x67: /* address-size override */
ad_bytes = def_ad_bytes ^ (mode_64bit() ? 12 : 6);
break;
case 0x2e: /* CS override */
ea.mem.seg = x86_seg_cs;
break;
case 0x3e: /* DS override */
ea.mem.seg = x86_seg_ds;
break;
case 0x26: /* ES override */
ea.mem.seg = x86_seg_es;
break;
case 0x64: /* FS override */
ea.mem.seg = x86_seg_fs;
break;
case 0x65: /* GS override */
ea.mem.seg = x86_seg_gs;
break;
case 0x36: /* SS override */
ea.mem.seg = x86_seg_ss;
break;
case 0xf0: /* LOCK */
lock_prefix = 1;
break;
case 0xf2: /* REPNE/REPNZ */
case 0xf3: /* REP/REPE/REPZ */
rep_prefix = 1;
break;
case 0x40 ... 0x4f: /* REX */
if ( !mode_64bit() )
goto done_prefixes;
rex_prefix = b;
continue;
default:
goto done_prefixes;
}
/* Any legacy prefix after a REX prefix nullifies its effect. */
rex_prefix = 0;
}
done_prefixes:
if ( rex_prefix & 8 ) /* REX.W */
op_bytes = 8;
/* Opcode byte(s). */
d = opcode_table[b];
if ( d == 0 )
{
/* Two-byte opcode? */
if ( b == 0x0f )
{
twobyte = 1;
b = insn_fetch_type(uint8_t);
d = twobyte_table[b];
}
/* Unrecognised? */
if ( d == 0 )
goto cannot_emulate;
}
/* Lock prefix is allowed only on RMW instructions. */
generate_exception_if((d & Mov) && lock_prefix, EXC_GP);
/* ModRM and SIB bytes. */
if ( d & ModRM )
{
modrm = insn_fetch_type(uint8_t);
modrm_mod = (modrm & 0xc0) >> 6;