60 |
int cpl; |
int cpl; |
61 |
int iopl; |
int iopl; |
62 |
int tf; /* TF cpu flag */ |
int tf; /* TF cpu flag */ |
63 |
|
int jmp_opt; /* use direct block chaining for direct jumps */ |
64 |
int mem_index; /* select memory access functions */ |
int mem_index; /* select memory access functions */ |
65 |
struct TranslationBlock *tb; |
struct TranslationBlock *tb; |
66 |
int popl_esp_hack; /* for correct popl with esp base handling */ |
int popl_esp_hack; /* for correct popl with esp base handling */ |
67 |
} DisasContext; |
} DisasContext; |
68 |
|
|
69 |
|
static void gen_eob(DisasContext *s); |
70 |
|
static void gen_jmp(DisasContext *s, unsigned int eip); |
71 |
|
|
72 |
/* i386 arith/logic operations */ |
/* i386 arith/logic operations */ |
73 |
enum { |
enum { |
74 |
OP_ADDL, |
OP_ADDL, |
639 |
gen_op_stl_user_T0_A0, |
gen_op_stl_user_T0_A0, |
640 |
}; |
}; |
641 |
|
|
|
/* 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) |
|
|
}; |
|
|
|
|
642 |
static inline void gen_string_movl_A0_ESI(DisasContext *s) |
static inline void gen_string_movl_A0_ESI(DisasContext *s) |
643 |
{ |
{ |
644 |
int override; |
int override; |
691 |
gen_op_jz_ecxl, |
gen_op_jz_ecxl, |
692 |
}; |
}; |
693 |
|
|
694 |
|
static GenOpFunc1 *gen_op_jz_ecx_im[2] = { |
695 |
|
gen_op_jz_ecxw_im, |
696 |
|
gen_op_jz_ecxl_im, |
697 |
|
}; |
698 |
|
|
699 |
static GenOpFunc *gen_op_dec_ECX[2] = { |
static GenOpFunc *gen_op_dec_ECX[2] = { |
700 |
gen_op_decw_ECX, |
gen_op_decw_ECX, |
701 |
gen_op_decl_ECX, |
gen_op_decl_ECX, |
702 |
}; |
}; |
703 |
|
|
704 |
static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = { |
static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = { |
705 |
{ |
{ |
706 |
gen_op_string_jnz_subb, |
gen_op_string_jnz_subb, |
707 |
gen_op_string_jnz_subw, |
gen_op_string_jnz_subw, |
714 |
}, |
}, |
715 |
}; |
}; |
716 |
|
|
717 |
|
static GenOpFunc1 *gen_op_string_jnz_sub_im[2][3] = { |
718 |
|
{ |
719 |
|
gen_op_string_jnz_subb_im, |
720 |
|
gen_op_string_jnz_subw_im, |
721 |
|
gen_op_string_jnz_subl_im, |
722 |
|
}, |
723 |
|
{ |
724 |
|
gen_op_string_jz_subb_im, |
725 |
|
gen_op_string_jz_subw_im, |
726 |
|
gen_op_string_jz_subl_im, |
727 |
|
}, |
728 |
|
}; |
729 |
|
|
730 |
static GenOpFunc *gen_op_in_DX_T0[3] = { |
static GenOpFunc *gen_op_in_DX_T0[3] = { |
731 |
gen_op_inb_DX_T0, |
gen_op_inb_DX_T0, |
732 |
gen_op_inw_DX_T0, |
gen_op_inw_DX_T0, |
755 |
} |
} |
756 |
} |
} |
757 |
|
|
758 |
/* same method as Valgrind : we generate jumps to current or next |
static inline void gen_update_cc_op(DisasContext *s) |
|
instruction */ |
|
|
static inline void gen_repz_movs(DisasContext *s, int ot, |
|
|
unsigned int cur_eip, unsigned int next_eip) |
|
759 |
{ |
{ |
760 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) { |
761 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
762 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
s->cc_op = CC_OP_DYNAMIC; |
763 |
gen_movs(s, ot); |
} |
764 |
gen_op_dec_ECX[s->aflag](); |
} |
765 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
766 |
s->is_jmp = 3; |
static inline void gen_jz_ecx_string(DisasContext *s, unsigned int next_eip) |
767 |
|
{ |
768 |
|
if (s->jmp_opt) { |
769 |
|
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
770 |
|
} else { |
771 |
|
/* XXX: does not work with gdbstub "ice" single step - not a |
772 |
|
serious problem */ |
773 |
|
gen_op_jz_ecx_im[s->aflag](next_eip); |
774 |
|
} |
775 |
} |
} |
776 |
|
|
777 |
static inline void gen_stos(DisasContext *s, int ot) |
static inline void gen_stos(DisasContext *s, int ot) |
787 |
} |
} |
788 |
} |
} |
789 |
|
|
|
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; |
|
|
} |
|
|
|
|
790 |
static inline void gen_lods(DisasContext *s, int ot) |
static inline void gen_lods(DisasContext *s, int ot) |
791 |
{ |
{ |
792 |
gen_string_movl_A0_ESI(s); |
gen_string_movl_A0_ESI(s); |
800 |
} |
} |
801 |
} |
} |
802 |
|
|
|
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; |
|
|
} |
|
|
|
|
803 |
static inline void gen_scas(DisasContext *s, int ot) |
static inline void gen_scas(DisasContext *s, int ot) |
804 |
{ |
{ |
805 |
gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); |
gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); |
814 |
} |
} |
815 |
} |
} |
816 |
|
|
|
#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 |
|
|
|
|
817 |
static inline void gen_cmps(DisasContext *s, int ot) |
static inline void gen_cmps(DisasContext *s, int ot) |
818 |
{ |
{ |
819 |
gen_string_movl_A0_ESI(s); |
gen_string_movl_A0_ESI(s); |
844 |
} |
} |
845 |
} |
} |
846 |
|
|
|
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; |
|
|
} |
|
|
|
|
847 |
static inline void gen_outs(DisasContext *s, int ot) |
static inline void gen_outs(DisasContext *s, int ot) |
848 |
{ |
{ |
849 |
gen_string_movl_A0_ESI(s); |
gen_string_movl_A0_ESI(s); |
857 |
} |
} |
858 |
} |
} |
859 |
|
|
860 |
static inline void gen_repz_outs(DisasContext *s, int ot, |
/* same method as Valgrind : we generate jumps to current or next |
861 |
unsigned int cur_eip, unsigned int next_eip) |
instruction */ |
862 |
{ |
#define GEN_REPZ(op) \ |
863 |
if (s->cc_op != CC_OP_DYNAMIC) |
static inline void gen_repz_ ## op(DisasContext *s, int ot, \ |
864 |
gen_op_set_cc_op(s->cc_op); |
unsigned int cur_eip, unsigned int next_eip) \ |
865 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
{ \ |
866 |
gen_outs(s, ot); |
gen_update_cc_op(s); \ |
867 |
gen_op_dec_ECX[s->aflag](); |
gen_jz_ecx_string(s, next_eip); \ |
868 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
gen_ ## op(s, ot); \ |
869 |
s->is_jmp = 3; |
gen_op_dec_ECX[s->aflag](); \ |
870 |
} |
/* a loop would cause two single step exceptions if ECX = 1 \ |
871 |
|
before rep string_insn */ \ |
872 |
static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) |
if (!s->jmp_opt) \ |
873 |
{ |
gen_op_jz_ecx_im[s->aflag](next_eip); \ |
874 |
int index, override; |
gen_jmp(s, cur_eip); \ |
875 |
|
} |
876 |
override = s->override; |
|
877 |
if (s->aflag) { |
#define GEN_REPZ2(op) \ |
878 |
/* 32 bit address */ |
static inline void gen_repz_ ## op(DisasContext *s, int ot, \ |
879 |
if (s->addseg && override < 0) |
unsigned int cur_eip, \ |
880 |
override = R_DS; |
unsigned int next_eip, \ |
881 |
if (override >= 0) { |
int nz) \ |
882 |
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
{ \ |
883 |
index = 3 + ot; |
gen_update_cc_op(s); \ |
884 |
} else { |
gen_jz_ecx_string(s, next_eip); \ |
885 |
index = ot; |
gen_ ## op(s, ot); \ |
886 |
} |
gen_op_dec_ECX[s->aflag](); \ |
887 |
} else { |
gen_op_set_cc_op(CC_OP_SUBB + ot); \ |
888 |
if (override < 0) |
if (!s->jmp_opt) \ |
889 |
override = R_DS; |
gen_op_string_jnz_sub_im[nz][ot](next_eip); \ |
890 |
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
else \ |
891 |
/* 16 address, always override */ |
gen_op_string_jnz_sub[nz][ot]((long)s->tb); \ |
892 |
index = 6 + ot; |
if (!s->jmp_opt) \ |
893 |
} |
gen_op_jz_ecx_im[s->aflag](next_eip); \ |
894 |
func[index](); |
gen_jmp(s, cur_eip); \ |
895 |
} |
} |
896 |
|
|
897 |
static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func) |
GEN_REPZ(movs) |
898 |
{ |
GEN_REPZ(stos) |
899 |
int index; |
GEN_REPZ(lods) |
900 |
|
GEN_REPZ(ins) |
901 |
if (s->aflag) { |
GEN_REPZ(outs) |
902 |
if (s->addseg) { |
GEN_REPZ2(scas) |
903 |
index = 3 + ot; |
GEN_REPZ2(cmps) |
|
} else { |
|
|
index = ot; |
|
|
} |
|
|
} else { |
|
|
index = 6 + ot; |
|
|
} |
|
|
func[index](); |
|
|
} |
|
|
|
|
904 |
|
|
905 |
static GenOpFunc *gen_op_in[3] = { |
static GenOpFunc *gen_op_in[3] = { |
906 |
gen_op_inb_T0_T1, |
gen_op_inb_T0_T1, |
1360 |
|
|
1361 |
inv = b & 1; |
inv = b & 1; |
1362 |
jcc_op = (b >> 1) & 7; |
jcc_op = (b >> 1) & 7; |
1363 |
switch(s->cc_op) { |
|
1364 |
/* we optimize the cmp/jcc case */ |
if (s->jmp_opt) { |
1365 |
case CC_OP_SUBB: |
switch(s->cc_op) { |
1366 |
case CC_OP_SUBW: |
/* we optimize the cmp/jcc case */ |
1367 |
case CC_OP_SUBL: |
case CC_OP_SUBB: |
1368 |
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; |
case CC_OP_SUBW: |
1369 |
break; |
case CC_OP_SUBL: |
1370 |
|
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][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]; |
|
1371 |
break; |
break; |
1372 |
case JCC_S: |
|
1373 |
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
/* some jumps are easy to compute */ |
1374 |
|
case CC_OP_ADDB: |
1375 |
|
case CC_OP_ADDW: |
1376 |
|
case CC_OP_ADDL: |
1377 |
|
case CC_OP_ADCB: |
1378 |
|
case CC_OP_ADCW: |
1379 |
|
case CC_OP_ADCL: |
1380 |
|
case CC_OP_SBBB: |
1381 |
|
case CC_OP_SBBW: |
1382 |
|
case CC_OP_SBBL: |
1383 |
|
case CC_OP_LOGICB: |
1384 |
|
case CC_OP_LOGICW: |
1385 |
|
case CC_OP_LOGICL: |
1386 |
|
case CC_OP_INCB: |
1387 |
|
case CC_OP_INCW: |
1388 |
|
case CC_OP_INCL: |
1389 |
|
case CC_OP_DECB: |
1390 |
|
case CC_OP_DECW: |
1391 |
|
case CC_OP_DECL: |
1392 |
|
case CC_OP_SHLB: |
1393 |
|
case CC_OP_SHLW: |
1394 |
|
case CC_OP_SHLL: |
1395 |
|
case CC_OP_SARB: |
1396 |
|
case CC_OP_SARW: |
1397 |
|
case CC_OP_SARL: |
1398 |
|
switch(jcc_op) { |
1399 |
|
case JCC_Z: |
1400 |
|
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
1401 |
|
break; |
1402 |
|
case JCC_S: |
1403 |
|
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
1404 |
|
break; |
1405 |
|
default: |
1406 |
|
func = NULL; |
1407 |
|
break; |
1408 |
|
} |
1409 |
break; |
break; |
1410 |
default: |
default: |
1411 |
func = NULL; |
func = NULL; |
1412 |
break; |
break; |
1413 |
} |
} |
|
break; |
|
|
default: |
|
|
func = NULL; |
|
|
break; |
|
|
} |
|
1414 |
|
|
1415 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
1416 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
1417 |
|
|
1418 |
if (!func) { |
if (!func) { |
1419 |
gen_setcc_slow[jcc_op](); |
gen_setcc_slow[jcc_op](); |
1420 |
func = gen_op_jcc; |
func = gen_op_jcc; |
1421 |
} |
} |
1422 |
|
|
1423 |
tb = s->tb; |
tb = s->tb; |
1424 |
if (!inv) { |
if (!inv) { |
1425 |
func((long)tb, val, next_eip); |
func((long)tb, val, next_eip); |
1426 |
|
} else { |
1427 |
|
func((long)tb, next_eip, val); |
1428 |
|
} |
1429 |
|
s->is_jmp = 3; |
1430 |
} else { |
} else { |
1431 |
func((long)tb, next_eip, val); |
if (s->cc_op != CC_OP_DYNAMIC) { |
1432 |
|
gen_op_set_cc_op(s->cc_op); |
1433 |
|
s->cc_op = CC_OP_DYNAMIC; |
1434 |
|
} |
1435 |
|
gen_setcc_slow[jcc_op](); |
1436 |
|
if (!inv) { |
1437 |
|
gen_op_jcc_im(val, next_eip); |
1438 |
|
} else { |
1439 |
|
gen_op_jcc_im(next_eip, val); |
1440 |
|
} |
1441 |
|
gen_eob(s); |
1442 |
} |
} |
|
s->is_jmp = 3; |
|
1443 |
} |
} |
1444 |
|
|
1445 |
static void gen_setcc(DisasContext *s, int b) |
static void gen_setcc(DisasContext *s, int b) |
1512 |
stop as a special handling must be done to disable hardware |
stop as a special handling must be done to disable hardware |
1513 |
interrupts for the next instruction */ |
interrupts for the next instruction */ |
1514 |
if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) |
if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) |
1515 |
s->is_jmp = 2; |
s->is_jmp = 3; |
1516 |
} |
} |
1517 |
|
|
1518 |
/* generate a push. It depends on ss32, addseg and dflag */ |
/* generate a push. It depends on ss32, addseg and dflag */ |
1682 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
1683 |
gen_op_jmp_im(cur_eip); |
gen_op_jmp_im(cur_eip); |
1684 |
gen_op_raise_exception(trapno); |
gen_op_raise_exception(trapno); |
1685 |
s->is_jmp = 1; |
s->is_jmp = 3; |
1686 |
} |
} |
1687 |
|
|
1688 |
/* an interrupt is different from an exception because of the |
/* an interrupt is different from an exception because of the |
1694 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
1695 |
gen_op_jmp_im(cur_eip); |
gen_op_jmp_im(cur_eip); |
1696 |
gen_op_raise_interrupt(intno, next_eip); |
gen_op_raise_interrupt(intno, next_eip); |
1697 |
s->is_jmp = 1; |
s->is_jmp = 3; |
1698 |
} |
} |
1699 |
|
|
1700 |
static void gen_debug(DisasContext *s, unsigned int cur_eip) |
static void gen_debug(DisasContext *s, unsigned int cur_eip) |
1703 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
1704 |
gen_op_jmp_im(cur_eip); |
gen_op_jmp_im(cur_eip); |
1705 |
gen_op_debug(); |
gen_op_debug(); |
1706 |
s->is_jmp = 1; |
s->is_jmp = 3; |
1707 |
|
} |
1708 |
|
|
1709 |
|
/* generate a generic end of block. Trace exception is also generated |
1710 |
|
if needed */ |
1711 |
|
static void gen_eob(DisasContext *s) |
1712 |
|
{ |
1713 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
1714 |
|
gen_op_set_cc_op(s->cc_op); |
1715 |
|
if (s->tf) { |
1716 |
|
gen_op_raise_exception(EXCP01_SSTP); |
1717 |
|
} else { |
1718 |
|
gen_op_movl_T0_0(); |
1719 |
|
gen_op_exit_tb(); |
1720 |
|
} |
1721 |
|
s->is_jmp = 3; |
1722 |
} |
} |
1723 |
|
|
1724 |
/* generate a jump to eip. No segment change must happen before as a |
/* generate a jump to eip. No segment change must happen before as a |
1727 |
{ |
{ |
1728 |
TranslationBlock *tb = s->tb; |
TranslationBlock *tb = s->tb; |
1729 |
|
|
1730 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->jmp_opt) { |
1731 |
gen_op_set_cc_op(s->cc_op); |
if (s->cc_op != CC_OP_DYNAMIC) |
1732 |
gen_op_jmp_tb_next((long)tb, eip); |
gen_op_set_cc_op(s->cc_op); |
1733 |
s->is_jmp = 3; |
gen_op_jmp((long)tb, eip); |
1734 |
|
s->is_jmp = 3; |
1735 |
|
} else { |
1736 |
|
gen_op_jmp_im(eip); |
1737 |
|
gen_eob(s); |
1738 |
|
} |
1739 |
} |
} |
1740 |
|
|
1741 |
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr |
/* convert one instruction. s->is_jmp is set if the translation must |
1742 |
is set to true if the instruction sets the PC (last instruction of |
be stopped. Return the next pc value */ |
1743 |
a basic block) */ |
static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
|
long disas_insn(DisasContext *s, uint8_t *pc_start) |
|
1744 |
{ |
{ |
1745 |
int b, prefixes, aflag, dflag; |
int b, prefixes, aflag, dflag; |
1746 |
int shift, ot; |
int shift, ot; |
2080 |
next_eip = s->pc - s->cs_base; |
next_eip = s->pc - s->cs_base; |
2081 |
gen_op_movl_T0_im(next_eip); |
gen_op_movl_T0_im(next_eip); |
2082 |
gen_push_T0(s); |
gen_push_T0(s); |
2083 |
s->is_jmp = 1; |
gen_eob(s); |
2084 |
break; |
break; |
2085 |
case 3: /* lcall Ev */ |
case 3: /*< lcall Ev */ |
2086 |
gen_op_ld_T1_A0[ot + s->mem_index](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
2087 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
2088 |
gen_op_ld_T0_A0[OT_WORD + s->mem_index](); |
gen_op_ld_T0_A0[OT_WORD + s->mem_index](); |
2095 |
} else { |
} else { |
2096 |
gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); |
gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); |
2097 |
} |
} |
2098 |
s->is_jmp = 1; |
gen_eob(s); |
2099 |
break; |
break; |
2100 |
case 4: /* jmp Ev */ |
case 4: /* jmp Ev */ |
2101 |
if (s->dflag == 0) |
if (s->dflag == 0) |
2102 |
gen_op_andl_T0_ffff(); |
gen_op_andl_T0_ffff(); |
2103 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
2104 |
s->is_jmp = 1; |
gen_eob(s); |
2105 |
break; |
break; |
2106 |
case 5: /* ljmp Ev */ |
case 5: /* ljmp Ev */ |
2107 |
gen_op_ld_T1_A0[ot + s->mem_index](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
2118 |
gen_op_movl_T0_T1(); |
gen_op_movl_T0_T1(); |
2119 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
2120 |
} |
} |
2121 |
s->is_jmp = 1; |
gen_eob(s); |
2122 |
break; |
break; |
2123 |
case 6: /* push Ev */ |
case 6: /* push Ev */ |
2124 |
gen_push_T0(s); |
gen_push_T0(s); |
2340 |
if (reg == R_SS) { |
if (reg == R_SS) { |
2341 |
/* if reg == SS, inhibit interrupts/trace */ |
/* if reg == SS, inhibit interrupts/trace */ |
2342 |
gen_op_set_inhibit_irq(); |
gen_op_set_inhibit_irq(); |
2343 |
|
s->tf = 0; |
2344 |
|
} |
2345 |
|
if (s->is_jmp) { |
2346 |
|
gen_op_jmp_im(s->pc - s->cs_base); |
2347 |
|
gen_eob(s); |
2348 |
} |
} |
2349 |
break; |
break; |
2350 |
case 0x1a1: /* pop fs */ |
case 0x1a1: /* pop fs */ |
2352 |
gen_pop_T0(s); |
gen_pop_T0(s); |
2353 |
gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); |
gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); |
2354 |
gen_pop_update(s); |
gen_pop_update(s); |
2355 |
|
if (s->is_jmp) { |
2356 |
|
gen_op_jmp_im(s->pc - s->cs_base); |
2357 |
|
gen_eob(s); |
2358 |
|
} |
2359 |
break; |
break; |
2360 |
|
|
2361 |
/**************************/ |
/**************************/ |
2411 |
if (reg == R_SS) { |
if (reg == R_SS) { |
2412 |
/* if reg == SS, inhibit interrupts/trace */ |
/* if reg == SS, inhibit interrupts/trace */ |
2413 |
gen_op_set_inhibit_irq(); |
gen_op_set_inhibit_irq(); |
2414 |
|
s->tf = 0; |
2415 |
|
} |
2416 |
|
if (s->is_jmp) { |
2417 |
|
gen_op_jmp_im(s->pc - s->cs_base); |
2418 |
|
gen_eob(s); |
2419 |
} |
} |
2420 |
break; |
break; |
2421 |
case 0x8c: /* mov Gv, seg */ |
case 0x8c: /* mov Gv, seg */ |
2623 |
gen_movl_seg_T0(s, op, pc_start - s->cs_base); |
gen_movl_seg_T0(s, op, pc_start - s->cs_base); |
2624 |
/* then put the data */ |
/* then put the data */ |
2625 |
gen_op_mov_reg_T1[ot][reg](); |
gen_op_mov_reg_T1[ot][reg](); |
2626 |
|
if (s->is_jmp) { |
2627 |
|
gen_op_jmp_im(s->pc - s->cs_base); |
2628 |
|
gen_eob(s); |
2629 |
|
} |
2630 |
break; |
break; |
2631 |
|
|
2632 |
/************************/ |
/************************/ |
3183 |
else |
else |
3184 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
3185 |
if (prefixes & PREFIX_REPNZ) { |
if (prefixes & PREFIX_REPNZ) { |
3186 |
if (s->cc_op != CC_OP_DYNAMIC) |
gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); |
|
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 */ |
|
3187 |
} else if (prefixes & PREFIX_REPZ) { |
} else if (prefixes & PREFIX_REPZ) { |
3188 |
if (s->cc_op != CC_OP_DYNAMIC) |
gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); |
|
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 */ |
|
3189 |
} else { |
} else { |
3190 |
gen_scas(s, ot); |
gen_scas(s, ot); |
3191 |
s->cc_op = CC_OP_SUBB + ot; |
s->cc_op = CC_OP_SUBB + ot; |
3199 |
else |
else |
3200 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
3201 |
if (prefixes & PREFIX_REPNZ) { |
if (prefixes & PREFIX_REPNZ) { |
3202 |
if (s->cc_op != CC_OP_DYNAMIC) |
gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); |
|
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 */ |
|
3203 |
} else if (prefixes & PREFIX_REPZ) { |
} else if (prefixes & PREFIX_REPZ) { |
3204 |
if (s->cc_op != CC_OP_DYNAMIC) |
gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); |
|
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 */ |
|
3205 |
} else { |
} else { |
3206 |
gen_cmps(s, ot); |
gen_cmps(s, ot); |
3207 |
s->cc_op = CC_OP_SUBB + ot; |
s->cc_op = CC_OP_SUBB + ot; |
3313 |
if (s->dflag == 0) |
if (s->dflag == 0) |
3314 |
gen_op_andl_T0_ffff(); |
gen_op_andl_T0_ffff(); |
3315 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
3316 |
s->is_jmp = 1; |
gen_eob(s); |
3317 |
break; |
break; |
3318 |
case 0xc3: /* ret */ |
case 0xc3: /* ret */ |
3319 |
gen_pop_T0(s); |
gen_pop_T0(s); |
3321 |
if (s->dflag == 0) |
if (s->dflag == 0) |
3322 |
gen_op_andl_T0_ffff(); |
gen_op_andl_T0_ffff(); |
3323 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
3324 |
s->is_jmp = 1; |
gen_eob(s); |
3325 |
break; |
break; |
3326 |
case 0xca: /* lret im */ |
case 0xca: /* lret im */ |
3327 |
val = ldsw(s->pc); |
val = ldsw(s->pc); |
3348 |
/* add stack offset */ |
/* add stack offset */ |
3349 |
gen_stack_update(s, val + (4 << s->dflag)); |
gen_stack_update(s, val + (4 << s->dflag)); |
3350 |
} |
} |
3351 |
s->is_jmp = 1; |
gen_eob(s); |
3352 |
break; |
break; |
3353 |
case 0xcb: /* lret */ |
case 0xcb: /* lret */ |
3354 |
val = 0; |
val = 0; |
3367 |
gen_op_iret_protected(s->dflag); |
gen_op_iret_protected(s->dflag); |
3368 |
s->cc_op = CC_OP_EFLAGS; |
s->cc_op = CC_OP_EFLAGS; |
3369 |
} |
} |
3370 |
s->is_jmp = 1; |
gen_eob(s); |
3371 |
break; |
break; |
3372 |
case 0xe8: /* call im */ |
case 0xe8: /* call im */ |
3373 |
{ |
{ |
3492 |
} |
} |
3493 |
gen_pop_update(s); |
gen_pop_update(s); |
3494 |
s->cc_op = CC_OP_EFLAGS; |
s->cc_op = CC_OP_EFLAGS; |
3495 |
s->is_jmp = 2; /* abort translation because TF flag may change */ |
/* abort translation because TF flag may change */ |
3496 |
|
gen_op_jmp_im(s->pc - s->cs_base); |
3497 |
|
gen_eob(s); |
3498 |
} |
} |
3499 |
break; |
break; |
3500 |
case 0x9e: /* sahf */ |
case 0x9e: /* sahf */ |
3695 |
case 0xfb: /* sti */ |
case 0xfb: /* sti */ |
3696 |
if (!s->vm86) { |
if (!s->vm86) { |
3697 |
if (s->cpl <= s->iopl) { |
if (s->cpl <= s->iopl) { |
3698 |
|
gen_sti: |
3699 |
gen_op_sti(); |
gen_op_sti(); |
3700 |
/* interruptions are enabled only the first insn after sti */ |
/* interruptions are enabled only the first insn after sti */ |
3701 |
gen_op_set_inhibit_irq(); |
gen_op_set_inhibit_irq(); |
3702 |
s->is_jmp = 2; /* give a chance to handle pending irqs */ |
/* give a chance to handle pending irqs */ |
3703 |
|
gen_op_jmp_im(s->pc - s->cs_base); |
3704 |
|
gen_eob(s); |
3705 |
} else { |
} else { |
3706 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3707 |
} |
} |
3708 |
} else { |
} else { |
3709 |
if (s->iopl == 3) { |
if (s->iopl == 3) { |
3710 |
gen_op_sti(); |
goto gen_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 */ |
|
3711 |
} else { |
} else { |
3712 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3713 |
} |
} |
3751 |
if (s->dflag == 0) |
if (s->dflag == 0) |
3752 |
val &= 0xffff; |
val &= 0xffff; |
3753 |
gen_op_loop[s->aflag][b & 3](val, next_eip); |
gen_op_loop[s->aflag][b & 3](val, next_eip); |
3754 |
s->is_jmp = 1; |
gen_eob(s); |
3755 |
break; |
break; |
3756 |
case 0x130: /* wrmsr */ |
case 0x130: /* wrmsr */ |
3757 |
case 0x132: /* rdmsr */ |
case 0x132: /* rdmsr */ |
3778 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
3779 |
gen_op_jmp_im(s->pc - s->cs_base); |
gen_op_jmp_im(s->pc - s->cs_base); |
3780 |
gen_op_hlt(); |
gen_op_hlt(); |
3781 |
s->is_jmp = 1; |
s->is_jmp = 3; |
3782 |
} |
} |
3783 |
break; |
break; |
3784 |
case 0x100: |
case 0x100: |
3950 |
if (b & 2) { |
if (b & 2) { |
3951 |
gen_op_mov_TN_reg[OT_LONG][0][rm](); |
gen_op_mov_TN_reg[OT_LONG][0][rm](); |
3952 |
gen_op_movl_crN_T0(reg); |
gen_op_movl_crN_T0(reg); |
3953 |
s->is_jmp = 2; |
gen_op_jmp_im(s->pc - s->cs_base); |
3954 |
|
gen_eob(s); |
3955 |
} else { |
} else { |
3956 |
gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); |
gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); |
3957 |
gen_op_mov_reg_T0[OT_LONG][rm](); |
gen_op_mov_reg_T0[OT_LONG][rm](); |
3978 |
if (b & 2) { |
if (b & 2) { |
3979 |
gen_op_mov_TN_reg[OT_LONG][0][rm](); |
gen_op_mov_TN_reg[OT_LONG][0][rm](); |
3980 |
gen_op_movl_drN_T0(reg); |
gen_op_movl_drN_T0(reg); |
3981 |
s->is_jmp = 2; |
gen_op_jmp_im(s->pc - s->cs_base); |
3982 |
|
gen_eob(s); |
3983 |
} else { |
} else { |
3984 |
gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); |
gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); |
3985 |
gen_op_mov_reg_T0[OT_LONG][rm](); |
gen_op_mov_reg_T0[OT_LONG][rm](); |
3999 |
/* lock generation */ |
/* lock generation */ |
4000 |
if (s->prefix & PREFIX_LOCK) |
if (s->prefix & PREFIX_LOCK) |
4001 |
gen_op_unlock(); |
gen_op_unlock(); |
4002 |
return (long)s->pc; |
return s->pc; |
4003 |
illegal_op: |
illegal_op: |
4004 |
/* XXX: ensure that no lock was generated */ |
/* XXX: ensure that no lock was generated */ |
4005 |
return -1; |
gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); |
4006 |
|
return s->pc; |
4007 |
} |
} |
4008 |
|
|
4009 |
#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) |
#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) |
4250 |
[INDEX_op_bsrw_T0_cc] = CC_OSZAPC, |
[INDEX_op_bsrw_T0_cc] = CC_OSZAPC, |
4251 |
[INDEX_op_bsrl_T0_cc] = CC_OSZAPC, |
[INDEX_op_bsrl_T0_cc] = CC_OSZAPC, |
4252 |
|
|
|
#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) |
|
|
|
|
4253 |
[INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, |
[INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, |
4254 |
[INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, |
[INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, |
4255 |
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, |
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, |
4351 |
uint8_t *pc_ptr; |
uint8_t *pc_ptr; |
4352 |
uint16_t *gen_opc_end; |
uint16_t *gen_opc_end; |
4353 |
int flags, j, lj; |
int flags, j, lj; |
|
long ret; |
|
4354 |
uint8_t *pc_start; |
uint8_t *pc_start; |
4355 |
uint8_t *cs_base; |
uint8_t *cs_base; |
4356 |
|
|
4380 |
else |
else |
4381 |
dc->mem_index = 3; |
dc->mem_index = 3; |
4382 |
} |
} |
4383 |
|
dc->jmp_opt = !(dc->tf || env->singlestep_enabled |
4384 |
|
#ifndef CONFIG_SOFT_MMU |
4385 |
|
|| (flags & HF_SOFTMMU_MASK) |
4386 |
|
#endif |
4387 |
|
); |
4388 |
gen_opc_ptr = gen_opc_buf; |
gen_opc_ptr = gen_opc_buf; |
4389 |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
4390 |
gen_opparam_ptr = gen_opparam_buf; |
gen_opparam_ptr = gen_opparam_buf; |
4399 |
if (flags & HF_INHIBIT_IRQ_MASK) { |
if (flags & HF_INHIBIT_IRQ_MASK) { |
4400 |
gen_op_reset_inhibit_irq(); |
gen_op_reset_inhibit_irq(); |
4401 |
} |
} |
4402 |
do { |
for(;;) { |
4403 |
if (env->nb_breakpoints > 0) { |
if (env->nb_breakpoints > 0) { |
4404 |
for(j = 0; j < env->nb_breakpoints; j++) { |
for(j = 0; j < env->nb_breakpoints; j++) { |
4405 |
if (env->breakpoints[j] == (unsigned long)pc_ptr) { |
if (env->breakpoints[j] == (unsigned long)pc_ptr) { |
4406 |
gen_debug(dc, pc_ptr - dc->cs_base); |
gen_debug(dc, pc_ptr - dc->cs_base); |
4407 |
goto the_end; |
break; |
4408 |
} |
} |
4409 |
} |
} |
4410 |
} |
} |
4419 |
gen_opc_cc_op[lj] = dc->cc_op; |
gen_opc_cc_op[lj] = dc->cc_op; |
4420 |
gen_opc_instr_start[lj] = 1; |
gen_opc_instr_start[lj] = 1; |
4421 |
} |
} |
4422 |
ret = disas_insn(dc, pc_ptr); |
pc_ptr = disas_insn(dc, pc_ptr); |
4423 |
if (ret == -1) { |
/* stop translation if indicated */ |
4424 |
/* we trigger an illegal instruction operation only if it |
if (dc->is_jmp) |
4425 |
is the first instruction. Otherwise, we simply stop |
break; |
|
generating the code just before it */ |
|
|
if (pc_ptr == pc_start) |
|
|
return -1; |
|
|
else |
|
|
break; |
|
|
} |
|
|
pc_ptr = (void *)ret; |
|
4426 |
/* if single step mode, we generate only one instruction and |
/* if single step mode, we generate only one instruction and |
4427 |
generate an exception */ |
generate an exception */ |
4428 |
if (dc->tf) |
if (dc->tf) { |
4429 |
|
gen_op_jmp_im(pc_ptr - dc->cs_base); |
4430 |
|
gen_eob(dc); |
4431 |
|
break; |
4432 |
|
} |
4433 |
|
/* if too long translation, stop generation too */ |
4434 |
|
if (gen_opc_ptr >= gen_opc_end || |
4435 |
|
(pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { |
4436 |
|
gen_op_jmp_im(pc_ptr - dc->cs_base); |
4437 |
|
gen_eob(dc); |
4438 |
break; |
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); |
|
4439 |
} |
} |
|
} |
|
|
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(); |
|
4440 |
} |
} |
4441 |
*gen_opc_ptr = INDEX_op_end; |
*gen_opc_ptr = INDEX_op_end; |
4442 |
/* we don't forget to fill the last values */ |
/* we don't forget to fill the last values */ |