finished simplifying string operations - correct TF flag handling for string operations and ss loading - simplified basic block exit code generation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@381 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
4cbb86e1c4
commit
dbc5594cb6
543
translate-i386.c
543
translate-i386.c
@ -60,11 +60,15 @@ typedef struct DisasContext {
|
||||
int cpl;
|
||||
int iopl;
|
||||
int tf; /* TF cpu flag */
|
||||
int jmp_opt; /* use direct block chaining for direct jumps */
|
||||
int mem_index; /* select memory access functions */
|
||||
struct TranslationBlock *tb;
|
||||
int popl_esp_hack; /* for correct popl with esp base handling */
|
||||
} DisasContext;
|
||||
|
||||
static void gen_eob(DisasContext *s);
|
||||
static void gen_jmp(DisasContext *s, unsigned int eip);
|
||||
|
||||
/* i386 arith/logic operations */
|
||||
enum {
|
||||
OP_ADDL,
|
||||
@ -635,31 +639,6 @@ static GenOpFunc *gen_op_st_T0_A0[3 * 3] = {
|
||||
gen_op_stl_user_T0_A0,
|
||||
};
|
||||
|
||||
/* the _a32 and _a16 string operations use A0 as the base register. */
|
||||
|
||||
#define STRINGOP_NB 9
|
||||
|
||||
#define STRINGOP(x) \
|
||||
gen_op_ ## x ## b_fast, \
|
||||
gen_op_ ## x ## w_fast, \
|
||||
gen_op_ ## x ## l_fast, \
|
||||
gen_op_ ## x ## b_a32, \
|
||||
gen_op_ ## x ## w_a32, \
|
||||
gen_op_ ## x ## l_a32, \
|
||||
gen_op_ ## x ## b_a16, \
|
||||
gen_op_ ## x ## w_a16, \
|
||||
gen_op_ ## x ## l_a16,
|
||||
|
||||
static GenOpFunc *gen_op_scas[STRINGOP_NB * 3] = {
|
||||
STRINGOP(repz_scas)
|
||||
STRINGOP(repnz_scas)
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_cmps[STRINGOP_NB * 3] = {
|
||||
STRINGOP(repz_cmps)
|
||||
STRINGOP(repnz_cmps)
|
||||
};
|
||||
|
||||
static inline void gen_string_movl_A0_ESI(DisasContext *s)
|
||||
{
|
||||
int override;
|
||||
@ -712,12 +691,17 @@ static GenOpFunc2 *gen_op_jz_ecx[2] = {
|
||||
gen_op_jz_ecxl,
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_op_jz_ecx_im[2] = {
|
||||
gen_op_jz_ecxw_im,
|
||||
gen_op_jz_ecxl_im,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_dec_ECX[2] = {
|
||||
gen_op_decw_ECX,
|
||||
gen_op_decl_ECX,
|
||||
};
|
||||
|
||||
static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = {
|
||||
static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = {
|
||||
{
|
||||
gen_op_string_jnz_subb,
|
||||
gen_op_string_jnz_subw,
|
||||
@ -730,6 +714,19 @@ static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = {
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_op_string_jnz_sub_im[2][3] = {
|
||||
{
|
||||
gen_op_string_jnz_subb_im,
|
||||
gen_op_string_jnz_subw_im,
|
||||
gen_op_string_jnz_subl_im,
|
||||
},
|
||||
{
|
||||
gen_op_string_jz_subb_im,
|
||||
gen_op_string_jz_subw_im,
|
||||
gen_op_string_jz_subl_im,
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_in_DX_T0[3] = {
|
||||
gen_op_inb_DX_T0,
|
||||
gen_op_inw_DX_T0,
|
||||
@ -758,18 +755,23 @@ static inline void gen_movs(DisasContext *s, int ot)
|
||||
}
|
||||
}
|
||||
|
||||
/* same method as Valgrind : we generate jumps to current or next
|
||||
instruction */
|
||||
static inline void gen_repz_movs(DisasContext *s, int ot,
|
||||
unsigned int cur_eip, unsigned int next_eip)
|
||||
static inline void gen_update_cc_op(DisasContext *s)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
if (s->cc_op != CC_OP_DYNAMIC) {
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip);
|
||||
gen_movs(s, ot);
|
||||
gen_op_dec_ECX[s->aflag]();
|
||||
gen_op_jmp_tb_next((long)s->tb, cur_eip);
|
||||
s->is_jmp = 3;
|
||||
s->cc_op = CC_OP_DYNAMIC;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_jz_ecx_string(DisasContext *s, unsigned int next_eip)
|
||||
{
|
||||
if (s->jmp_opt) {
|
||||
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip);
|
||||
} else {
|
||||
/* XXX: does not work with gdbstub "ice" single step - not a
|
||||
serious problem */
|
||||
gen_op_jz_ecx_im[s->aflag](next_eip);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_stos(DisasContext *s, int ot)
|
||||
@ -785,18 +787,6 @@ static inline void gen_stos(DisasContext *s, int ot)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_repz_stos(DisasContext *s, int ot,
|
||||
unsigned int cur_eip, unsigned int next_eip)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip);
|
||||
gen_stos(s, ot);
|
||||
gen_op_dec_ECX[s->aflag]();
|
||||
gen_op_jmp_tb_next((long)s->tb, cur_eip);
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
static inline void gen_lods(DisasContext *s, int ot)
|
||||
{
|
||||
gen_string_movl_A0_ESI(s);
|
||||
@ -810,18 +800,6 @@ static inline void gen_lods(DisasContext *s, int ot)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_repz_lods(DisasContext *s, int ot,
|
||||
unsigned int cur_eip, unsigned int next_eip)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip);
|
||||
gen_lods(s, ot);
|
||||
gen_op_dec_ECX[s->aflag]();
|
||||
gen_op_jmp_tb_next((long)s->tb, cur_eip);
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
static inline void gen_scas(DisasContext *s, int ot)
|
||||
{
|
||||
gen_op_mov_TN_reg[OT_LONG][0][R_EAX]();
|
||||
@ -836,23 +814,6 @@ static inline void gen_scas(DisasContext *s, int ot)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline void gen_repz_scas(DisasContext *s, int ot,
|
||||
unsigned int cur_eip, unsigned int next_eip,
|
||||
int nz)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip);
|
||||
gen_scas(s, ot);
|
||||
gen_op_set_cc_op(CC_OP_SUBB + ot);
|
||||
gen_op_string_jnz_sub[nz][ot]((long)s->tb, next_eip);
|
||||
gen_op_dec_ECX[s->aflag]();
|
||||
gen_op_jmp_tb_next((long)s->tb, cur_eip);
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void gen_cmps(DisasContext *s, int ot)
|
||||
{
|
||||
gen_string_movl_A0_ESI(s);
|
||||
@ -883,18 +844,6 @@ static inline void gen_ins(DisasContext *s, int ot)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_repz_ins(DisasContext *s, int ot,
|
||||
unsigned int cur_eip, unsigned int next_eip)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip);
|
||||
gen_ins(s, ot);
|
||||
gen_op_dec_ECX[s->aflag]();
|
||||
gen_op_jmp_tb_next((long)s->tb, cur_eip);
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
static inline void gen_outs(DisasContext *s, int ot)
|
||||
{
|
||||
gen_string_movl_A0_ESI(s);
|
||||
@ -908,59 +857,50 @@ static inline void gen_outs(DisasContext *s, int ot)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_repz_outs(DisasContext *s, int ot,
|
||||
unsigned int cur_eip, unsigned int next_eip)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip);
|
||||
gen_outs(s, ot);
|
||||
gen_op_dec_ECX[s->aflag]();
|
||||
gen_op_jmp_tb_next((long)s->tb, cur_eip);
|
||||
s->is_jmp = 3;
|
||||
/* same method as Valgrind : we generate jumps to current or next
|
||||
instruction */
|
||||
#define GEN_REPZ(op) \
|
||||
static inline void gen_repz_ ## op(DisasContext *s, int ot, \
|
||||
unsigned int cur_eip, unsigned int next_eip) \
|
||||
{ \
|
||||
gen_update_cc_op(s); \
|
||||
gen_jz_ecx_string(s, next_eip); \
|
||||
gen_ ## op(s, ot); \
|
||||
gen_op_dec_ECX[s->aflag](); \
|
||||
/* a loop would cause two single step exceptions if ECX = 1 \
|
||||
before rep string_insn */ \
|
||||
if (!s->jmp_opt) \
|
||||
gen_op_jz_ecx_im[s->aflag](next_eip); \
|
||||
gen_jmp(s, cur_eip); \
|
||||
}
|
||||
|
||||
static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
|
||||
{
|
||||
int index, override;
|
||||
|
||||
override = s->override;
|
||||
if (s->aflag) {
|
||||
/* 32 bit address */
|
||||
if (s->addseg && override < 0)
|
||||
override = R_DS;
|
||||
if (override >= 0) {
|
||||
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
|
||||
index = 3 + ot;
|
||||
} else {
|
||||
index = ot;
|
||||
}
|
||||
} else {
|
||||
if (override < 0)
|
||||
override = R_DS;
|
||||
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
|
||||
/* 16 address, always override */
|
||||
index = 6 + ot;
|
||||
}
|
||||
func[index]();
|
||||
}
|
||||
|
||||
static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (s->aflag) {
|
||||
if (s->addseg) {
|
||||
index = 3 + ot;
|
||||
} else {
|
||||
index = ot;
|
||||
}
|
||||
} else {
|
||||
index = 6 + ot;
|
||||
}
|
||||
func[index]();
|
||||
#define GEN_REPZ2(op) \
|
||||
static inline void gen_repz_ ## op(DisasContext *s, int ot, \
|
||||
unsigned int cur_eip, \
|
||||
unsigned int next_eip, \
|
||||
int nz) \
|
||||
{ \
|
||||
gen_update_cc_op(s); \
|
||||
gen_jz_ecx_string(s, next_eip); \
|
||||
gen_ ## op(s, ot); \
|
||||
gen_op_dec_ECX[s->aflag](); \
|
||||
gen_op_set_cc_op(CC_OP_SUBB + ot); \
|
||||
if (!s->jmp_opt) \
|
||||
gen_op_string_jnz_sub_im[nz][ot](next_eip); \
|
||||
else \
|
||||
gen_op_string_jnz_sub[nz][ot]((long)s->tb); \
|
||||
if (!s->jmp_opt) \
|
||||
gen_op_jz_ecx_im[s->aflag](next_eip); \
|
||||
gen_jmp(s, cur_eip); \
|
||||
}
|
||||
|
||||
GEN_REPZ(movs)
|
||||
GEN_REPZ(stos)
|
||||
GEN_REPZ(lods)
|
||||
GEN_REPZ(ins)
|
||||
GEN_REPZ(outs)
|
||||
GEN_REPZ2(scas)
|
||||
GEN_REPZ2(cmps)
|
||||
|
||||
static GenOpFunc *gen_op_in[3] = {
|
||||
gen_op_inb_T0_T1,
|
||||
@ -1420,71 +1360,86 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip)
|
||||
|
||||
inv = b & 1;
|
||||
jcc_op = (b >> 1) & 7;
|
||||
switch(s->cc_op) {
|
||||
/* we optimize the cmp/jcc case */
|
||||
case CC_OP_SUBB:
|
||||
case CC_OP_SUBW:
|
||||
case CC_OP_SUBL:
|
||||
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
|
||||
break;
|
||||
|
||||
/* some jumps are easy to compute */
|
||||
case CC_OP_ADDB:
|
||||
case CC_OP_ADDW:
|
||||
case CC_OP_ADDL:
|
||||
case CC_OP_ADCB:
|
||||
case CC_OP_ADCW:
|
||||
case CC_OP_ADCL:
|
||||
case CC_OP_SBBB:
|
||||
case CC_OP_SBBW:
|
||||
case CC_OP_SBBL:
|
||||
case CC_OP_LOGICB:
|
||||
case CC_OP_LOGICW:
|
||||
case CC_OP_LOGICL:
|
||||
case CC_OP_INCB:
|
||||
case CC_OP_INCW:
|
||||
case CC_OP_INCL:
|
||||
case CC_OP_DECB:
|
||||
case CC_OP_DECW:
|
||||
case CC_OP_DECL:
|
||||
case CC_OP_SHLB:
|
||||
case CC_OP_SHLW:
|
||||
case CC_OP_SHLL:
|
||||
case CC_OP_SARB:
|
||||
case CC_OP_SARW:
|
||||
case CC_OP_SARL:
|
||||
switch(jcc_op) {
|
||||
case JCC_Z:
|
||||
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
|
||||
|
||||
if (s->jmp_opt) {
|
||||
switch(s->cc_op) {
|
||||
/* we optimize the cmp/jcc case */
|
||||
case CC_OP_SUBB:
|
||||
case CC_OP_SUBW:
|
||||
case CC_OP_SUBL:
|
||||
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
|
||||
break;
|
||||
case JCC_S:
|
||||
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
|
||||
|
||||
/* some jumps are easy to compute */
|
||||
case CC_OP_ADDB:
|
||||
case CC_OP_ADDW:
|
||||
case CC_OP_ADDL:
|
||||
case CC_OP_ADCB:
|
||||
case CC_OP_ADCW:
|
||||
case CC_OP_ADCL:
|
||||
case CC_OP_SBBB:
|
||||
case CC_OP_SBBW:
|
||||
case CC_OP_SBBL:
|
||||
case CC_OP_LOGICB:
|
||||
case CC_OP_LOGICW:
|
||||
case CC_OP_LOGICL:
|
||||
case CC_OP_INCB:
|
||||
case CC_OP_INCW:
|
||||
case CC_OP_INCL:
|
||||
case CC_OP_DECB:
|
||||
case CC_OP_DECW:
|
||||
case CC_OP_DECL:
|
||||
case CC_OP_SHLB:
|
||||
case CC_OP_SHLW:
|
||||
case CC_OP_SHLL:
|
||||
case CC_OP_SARB:
|
||||
case CC_OP_SARW:
|
||||
case CC_OP_SARL:
|
||||
switch(jcc_op) {
|
||||
case JCC_Z:
|
||||
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
|
||||
break;
|
||||
case JCC_S:
|
||||
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
|
||||
break;
|
||||
default:
|
||||
func = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
func = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
func = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
|
||||
if (!func) {
|
||||
gen_setcc_slow[jcc_op]();
|
||||
func = gen_op_jcc;
|
||||
}
|
||||
if (!func) {
|
||||
gen_setcc_slow[jcc_op]();
|
||||
func = gen_op_jcc;
|
||||
}
|
||||
|
||||
tb = s->tb;
|
||||
if (!inv) {
|
||||
func((long)tb, val, next_eip);
|
||||
tb = s->tb;
|
||||
if (!inv) {
|
||||
func((long)tb, val, next_eip);
|
||||
} else {
|
||||
func((long)tb, next_eip, val);
|
||||
}
|
||||
s->is_jmp = 3;
|
||||
} else {
|
||||
func((long)tb, next_eip, val);
|
||||
if (s->cc_op != CC_OP_DYNAMIC) {
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
s->cc_op = CC_OP_DYNAMIC;
|
||||
}
|
||||
gen_setcc_slow[jcc_op]();
|
||||
if (!inv) {
|
||||
gen_op_jcc_im(val, next_eip);
|
||||
} else {
|
||||
gen_op_jcc_im(next_eip, val);
|
||||
}
|
||||
gen_eob(s);
|
||||
}
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
static void gen_setcc(DisasContext *s, int b)
|
||||
@ -1557,7 +1512,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
|
||||
stop as a special handling must be done to disable hardware
|
||||
interrupts for the next instruction */
|
||||
if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS))
|
||||
s->is_jmp = 2;
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
/* generate a push. It depends on ss32, addseg and dflag */
|
||||
@ -1727,7 +1682,7 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jmp_im(cur_eip);
|
||||
gen_op_raise_exception(trapno);
|
||||
s->is_jmp = 1;
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
/* an interrupt is different from an exception because of the
|
||||
@ -1739,7 +1694,7 @@ static void gen_interrupt(DisasContext *s, int intno,
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jmp_im(cur_eip);
|
||||
gen_op_raise_interrupt(intno, next_eip);
|
||||
s->is_jmp = 1;
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
static void gen_debug(DisasContext *s, unsigned int cur_eip)
|
||||
@ -1748,7 +1703,22 @@ static void gen_debug(DisasContext *s, unsigned int cur_eip)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jmp_im(cur_eip);
|
||||
gen_op_debug();
|
||||
s->is_jmp = 1;
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
/* generate a generic end of block. Trace exception is also generated
|
||||
if needed */
|
||||
static void gen_eob(DisasContext *s)
|
||||
{
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
if (s->tf) {
|
||||
gen_op_raise_exception(EXCP01_SSTP);
|
||||
} else {
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
}
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
|
||||
/* generate a jump to eip. No segment change must happen before as a
|
||||
@ -1757,16 +1727,20 @@ static void gen_jmp(DisasContext *s, unsigned int eip)
|
||||
{
|
||||
TranslationBlock *tb = s->tb;
|
||||
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jmp_tb_next((long)tb, eip);
|
||||
s->is_jmp = 3;
|
||||
if (s->jmp_opt) {
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jmp((long)tb, eip);
|
||||
s->is_jmp = 3;
|
||||
} else {
|
||||
gen_op_jmp_im(eip);
|
||||
gen_eob(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
|
||||
is set to true if the instruction sets the PC (last instruction of
|
||||
a basic block) */
|
||||
long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
/* convert one instruction. s->is_jmp is set if the translation must
|
||||
be stopped. Return the next pc value */
|
||||
static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
{
|
||||
int b, prefixes, aflag, dflag;
|
||||
int shift, ot;
|
||||
@ -2106,9 +2080,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
next_eip = s->pc - s->cs_base;
|
||||
gen_op_movl_T0_im(next_eip);
|
||||
gen_push_T0(s);
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 3: /* lcall Ev */
|
||||
case 3: /*< lcall Ev */
|
||||
gen_op_ld_T1_A0[ot + s->mem_index]();
|
||||
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
|
||||
gen_op_ld_T0_A0[OT_WORD + s->mem_index]();
|
||||
@ -2121,13 +2095,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
} else {
|
||||
gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base);
|
||||
}
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 4: /* jmp Ev */
|
||||
if (s->dflag == 0)
|
||||
gen_op_andl_T0_ffff();
|
||||
gen_op_jmp_T0();
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 5: /* ljmp Ev */
|
||||
gen_op_ld_T1_A0[ot + s->mem_index]();
|
||||
@ -2144,7 +2118,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_movl_T0_T1();
|
||||
gen_op_jmp_T0();
|
||||
}
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 6: /* push Ev */
|
||||
gen_push_T0(s);
|
||||
@ -2366,6 +2340,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (reg == R_SS) {
|
||||
/* if reg == SS, inhibit interrupts/trace */
|
||||
gen_op_set_inhibit_irq();
|
||||
s->tf = 0;
|
||||
}
|
||||
if (s->is_jmp) {
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
}
|
||||
break;
|
||||
case 0x1a1: /* pop fs */
|
||||
@ -2373,6 +2352,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_pop_T0(s);
|
||||
gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base);
|
||||
gen_pop_update(s);
|
||||
if (s->is_jmp) {
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
}
|
||||
break;
|
||||
|
||||
/**************************/
|
||||
@ -2428,6 +2411,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (reg == R_SS) {
|
||||
/* if reg == SS, inhibit interrupts/trace */
|
||||
gen_op_set_inhibit_irq();
|
||||
s->tf = 0;
|
||||
}
|
||||
if (s->is_jmp) {
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
}
|
||||
break;
|
||||
case 0x8c: /* mov Gv, seg */
|
||||
@ -2635,6 +2623,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_movl_seg_T0(s, op, pc_start - s->cs_base);
|
||||
/* then put the data */
|
||||
gen_op_mov_reg_T1[ot][reg]();
|
||||
if (s->is_jmp) {
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
}
|
||||
break;
|
||||
|
||||
/************************/
|
||||
@ -3191,15 +3183,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
if (prefixes & PREFIX_REPNZ) {
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_string_es(s, ot, gen_op_scas + STRINGOP_NB);
|
||||
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
|
||||
gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
|
||||
} else if (prefixes & PREFIX_REPZ) {
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_string_es(s, ot, gen_op_scas);
|
||||
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
|
||||
gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
|
||||
} else {
|
||||
gen_scas(s, ot);
|
||||
s->cc_op = CC_OP_SUBB + ot;
|
||||
@ -3213,15 +3199,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
else
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
if (prefixes & PREFIX_REPNZ) {
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_string_ds(s, ot, gen_op_cmps + STRINGOP_NB);
|
||||
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
|
||||
gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
|
||||
} else if (prefixes & PREFIX_REPZ) {
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_string_ds(s, ot, gen_op_cmps);
|
||||
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
|
||||
gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
|
||||
} else {
|
||||
gen_cmps(s, ot);
|
||||
s->cc_op = CC_OP_SUBB + ot;
|
||||
@ -3333,7 +3313,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (s->dflag == 0)
|
||||
gen_op_andl_T0_ffff();
|
||||
gen_op_jmp_T0();
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 0xc3: /* ret */
|
||||
gen_pop_T0(s);
|
||||
@ -3341,7 +3321,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (s->dflag == 0)
|
||||
gen_op_andl_T0_ffff();
|
||||
gen_op_jmp_T0();
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 0xca: /* lret im */
|
||||
val = ldsw(s->pc);
|
||||
@ -3368,7 +3348,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
/* add stack offset */
|
||||
gen_stack_update(s, val + (4 << s->dflag));
|
||||
}
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 0xcb: /* lret */
|
||||
val = 0;
|
||||
@ -3387,7 +3367,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_iret_protected(s->dflag);
|
||||
s->cc_op = CC_OP_EFLAGS;
|
||||
}
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 0xe8: /* call im */
|
||||
{
|
||||
@ -3512,7 +3492,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
}
|
||||
gen_pop_update(s);
|
||||
s->cc_op = CC_OP_EFLAGS;
|
||||
s->is_jmp = 2; /* abort translation because TF flag may change */
|
||||
/* abort translation because TF flag may change */
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
}
|
||||
break;
|
||||
case 0x9e: /* sahf */
|
||||
@ -3713,19 +3695,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
case 0xfb: /* sti */
|
||||
if (!s->vm86) {
|
||||
if (s->cpl <= s->iopl) {
|
||||
gen_sti:
|
||||
gen_op_sti();
|
||||
/* interruptions are enabled only the first insn after sti */
|
||||
gen_op_set_inhibit_irq();
|
||||
s->is_jmp = 2; /* give a chance to handle pending irqs */
|
||||
/* give a chance to handle pending irqs */
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
} else {
|
||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||
}
|
||||
} else {
|
||||
if (s->iopl == 3) {
|
||||
gen_op_sti();
|
||||
/* interruptions are enabled only the first insn after sti */
|
||||
gen_op_set_inhibit_irq();
|
||||
s->is_jmp = 2; /* give a chance to handle pending irqs */
|
||||
goto gen_sti;
|
||||
} else {
|
||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||
}
|
||||
@ -3769,7 +3751,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (s->dflag == 0)
|
||||
val &= 0xffff;
|
||||
gen_op_loop[s->aflag][b & 3](val, next_eip);
|
||||
s->is_jmp = 1;
|
||||
gen_eob(s);
|
||||
break;
|
||||
case 0x130: /* wrmsr */
|
||||
case 0x132: /* rdmsr */
|
||||
@ -3796,7 +3778,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_op_hlt();
|
||||
s->is_jmp = 1;
|
||||
s->is_jmp = 3;
|
||||
}
|
||||
break;
|
||||
case 0x100:
|
||||
@ -3968,7 +3950,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (b & 2) {
|
||||
gen_op_mov_TN_reg[OT_LONG][0][rm]();
|
||||
gen_op_movl_crN_T0(reg);
|
||||
s->is_jmp = 2;
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
} else {
|
||||
gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg]));
|
||||
gen_op_mov_reg_T0[OT_LONG][rm]();
|
||||
@ -3995,7 +3978,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (b & 2) {
|
||||
gen_op_mov_TN_reg[OT_LONG][0][rm]();
|
||||
gen_op_movl_drN_T0(reg);
|
||||
s->is_jmp = 2;
|
||||
gen_op_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
} else {
|
||||
gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg]));
|
||||
gen_op_mov_reg_T0[OT_LONG][rm]();
|
||||
@ -4015,10 +3999,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
/* lock generation */
|
||||
if (s->prefix & PREFIX_LOCK)
|
||||
gen_op_unlock();
|
||||
return (long)s->pc;
|
||||
return s->pc;
|
||||
illegal_op:
|
||||
/* XXX: ensure that no lock was generated */
|
||||
return -1;
|
||||
gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
|
||||
return s->pc;
|
||||
}
|
||||
|
||||
#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C)
|
||||
@ -4265,23 +4250,6 @@ static uint16_t opc_write_flags[NB_OPS] = {
|
||||
[INDEX_op_bsrw_T0_cc] = CC_OSZAPC,
|
||||
[INDEX_op_bsrl_T0_cc] = CC_OSZAPC,
|
||||
|
||||
#undef STRINGOP
|
||||
#define STRINGOP(x) \
|
||||
[INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \
|
||||
[INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \
|
||||
[INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \
|
||||
[INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \
|
||||
[INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \
|
||||
[INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \
|
||||
[INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \
|
||||
[INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \
|
||||
[INDEX_op_ ## x ## l_a16] = CC_OSZAPC,
|
||||
|
||||
STRINGOP(repz_scas)
|
||||
STRINGOP(repnz_scas)
|
||||
STRINGOP(repz_cmps)
|
||||
STRINGOP(repnz_cmps)
|
||||
|
||||
[INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
|
||||
@ -4383,7 +4351,6 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
uint8_t *pc_ptr;
|
||||
uint16_t *gen_opc_end;
|
||||
int flags, j, lj;
|
||||
long ret;
|
||||
uint8_t *pc_start;
|
||||
uint8_t *cs_base;
|
||||
|
||||
@ -4413,7 +4380,11 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
else
|
||||
dc->mem_index = 3;
|
||||
}
|
||||
|
||||
dc->jmp_opt = !(dc->tf || env->singlestep_enabled
|
||||
#ifndef CONFIG_SOFT_MMU
|
||||
|| (flags & HF_SOFTMMU_MASK)
|
||||
#endif
|
||||
);
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
@ -4428,12 +4399,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
if (flags & HF_INHIBIT_IRQ_MASK) {
|
||||
gen_op_reset_inhibit_irq();
|
||||
}
|
||||
do {
|
||||
for(;;) {
|
||||
if (env->nb_breakpoints > 0) {
|
||||
for(j = 0; j < env->nb_breakpoints; j++) {
|
||||
if (env->breakpoints[j] == (unsigned long)pc_ptr) {
|
||||
gen_debug(dc, pc_ptr - dc->cs_base);
|
||||
goto the_end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4448,44 +4419,24 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
gen_opc_cc_op[lj] = dc->cc_op;
|
||||
gen_opc_instr_start[lj] = 1;
|
||||
}
|
||||
ret = disas_insn(dc, pc_ptr);
|
||||
if (ret == -1) {
|
||||
/* we trigger an illegal instruction operation only if it
|
||||
is the first instruction. Otherwise, we simply stop
|
||||
generating the code just before it */
|
||||
if (pc_ptr == pc_start)
|
||||
return -1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
pc_ptr = (void *)ret;
|
||||
pc_ptr = disas_insn(dc, pc_ptr);
|
||||
/* stop translation if indicated */
|
||||
if (dc->is_jmp)
|
||||
break;
|
||||
/* if single step mode, we generate only one instruction and
|
||||
generate an exception */
|
||||
if (dc->tf)
|
||||
if (dc->tf) {
|
||||
gen_op_jmp_im(pc_ptr - dc->cs_base);
|
||||
gen_eob(dc);
|
||||
break;
|
||||
}
|
||||
/* if too long translation, stop generation too */
|
||||
if (gen_opc_ptr >= gen_opc_end ||
|
||||
(pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
|
||||
gen_op_jmp_im(pc_ptr - dc->cs_base);
|
||||
gen_eob(dc);
|
||||
break;
|
||||
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
||||
(pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||
if (!dc->tf && dc->is_jmp == DISAS_NEXT) {
|
||||
gen_jmp(dc, ret - (unsigned long)dc->cs_base);
|
||||
}
|
||||
|
||||
/* we must store the eflags state if it is not already done */
|
||||
if (dc->is_jmp != DISAS_TB_JUMP) {
|
||||
if (dc->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(dc->cc_op);
|
||||
if (dc->is_jmp != DISAS_JUMP) {
|
||||
/* we add an additionnal jmp to update the simulated PC */
|
||||
gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
|
||||
}
|
||||
}
|
||||
if (dc->tf) {
|
||||
gen_op_raise_exception(EXCP01_SSTP);
|
||||
}
|
||||
the_end:
|
||||
if (dc->is_jmp != DISAS_TB_JUMP) {
|
||||
/* indicate that the hash table must be used to find the next TB */
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
}
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
/* we don't forget to fill the last values */
|
||||
|
Loading…
Reference in New Issue
Block a user