Revision dbc5594c translate-i386.c
b/translate-i386.c | ||
---|---|---|
60 | 60 |
int cpl; |
61 | 61 |
int iopl; |
62 | 62 |
int tf; /* TF cpu flag */ |
63 |
int jmp_opt; /* use direct block chaining for direct jumps */ |
|
63 | 64 |
int mem_index; /* select memory access functions */ |
64 | 65 |
struct TranslationBlock *tb; |
65 | 66 |
int popl_esp_hack; /* for correct popl with esp base handling */ |
66 | 67 |
} DisasContext; |
67 | 68 |
|
69 |
static void gen_eob(DisasContext *s); |
|
70 |
static void gen_jmp(DisasContext *s, unsigned int eip); |
|
71 |
|
|
68 | 72 |
/* i386 arith/logic operations */ |
69 | 73 |
enum { |
70 | 74 |
OP_ADDL, |
... | ... | |
635 | 639 |
gen_op_stl_user_T0_A0, |
636 | 640 |
}; |
637 | 641 |
|
638 |
/* the _a32 and _a16 string operations use A0 as the base register. */ |
|
639 |
|
|
640 |
#define STRINGOP_NB 9 |
|
641 |
|
|
642 |
#define STRINGOP(x) \ |
|
643 |
gen_op_ ## x ## b_fast, \ |
|
644 |
gen_op_ ## x ## w_fast, \ |
|
645 |
gen_op_ ## x ## l_fast, \ |
|
646 |
gen_op_ ## x ## b_a32, \ |
|
647 |
gen_op_ ## x ## w_a32, \ |
|
648 |
gen_op_ ## x ## l_a32, \ |
|
649 |
gen_op_ ## x ## b_a16, \ |
|
650 |
gen_op_ ## x ## w_a16, \ |
|
651 |
gen_op_ ## x ## l_a16, |
|
652 |
|
|
653 |
static GenOpFunc *gen_op_scas[STRINGOP_NB * 3] = { |
|
654 |
STRINGOP(repz_scas) |
|
655 |
STRINGOP(repnz_scas) |
|
656 |
}; |
|
657 |
|
|
658 |
static GenOpFunc *gen_op_cmps[STRINGOP_NB * 3] = { |
|
659 |
STRINGOP(repz_cmps) |
|
660 |
STRINGOP(repnz_cmps) |
|
661 |
}; |
|
662 |
|
|
663 | 642 |
static inline void gen_string_movl_A0_ESI(DisasContext *s) |
664 | 643 |
{ |
665 | 644 |
int override; |
... | ... | |
712 | 691 |
gen_op_jz_ecxl, |
713 | 692 |
}; |
714 | 693 |
|
694 |
static GenOpFunc1 *gen_op_jz_ecx_im[2] = { |
|
695 |
gen_op_jz_ecxw_im, |
|
696 |
gen_op_jz_ecxl_im, |
|
697 |
}; |
|
698 |
|
|
715 | 699 |
static GenOpFunc *gen_op_dec_ECX[2] = { |
716 | 700 |
gen_op_decw_ECX, |
717 | 701 |
gen_op_decl_ECX, |
718 | 702 |
}; |
719 | 703 |
|
720 |
static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = {
|
|
704 |
static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = {
|
|
721 | 705 |
{ |
722 | 706 |
gen_op_string_jnz_subb, |
723 | 707 |
gen_op_string_jnz_subw, |
... | ... | |
730 | 714 |
}, |
731 | 715 |
}; |
732 | 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 |
|
|
733 | 730 |
static GenOpFunc *gen_op_in_DX_T0[3] = { |
734 | 731 |
gen_op_inb_DX_T0, |
735 | 732 |
gen_op_inw_DX_T0, |
... | ... | |
758 | 755 |
} |
759 | 756 |
} |
760 | 757 |
|
761 |
/* same method as Valgrind : we generate jumps to current or next |
|
762 |
instruction */ |
|
763 |
static inline void gen_repz_movs(DisasContext *s, int ot, |
|
764 |
unsigned int cur_eip, unsigned int next_eip) |
|
758 |
static inline void gen_update_cc_op(DisasContext *s) |
|
765 | 759 |
{ |
766 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
760 |
if (s->cc_op != CC_OP_DYNAMIC) {
|
|
767 | 761 |
gen_op_set_cc_op(s->cc_op); |
768 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
769 |
gen_movs(s, ot); |
|
770 |
gen_op_dec_ECX[s->aflag](); |
|
771 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
772 |
s->is_jmp = 3; |
|
762 |
s->cc_op = CC_OP_DYNAMIC; |
|
763 |
} |
|
764 |
} |
|
765 |
|
|
766 |
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 |
} |
|
773 | 775 |
} |
774 | 776 |
|
775 | 777 |
static inline void gen_stos(DisasContext *s, int ot) |
... | ... | |
785 | 787 |
} |
786 | 788 |
} |
787 | 789 |
|
788 |
static inline void gen_repz_stos(DisasContext *s, int ot, |
|
789 |
unsigned int cur_eip, unsigned int next_eip) |
|
790 |
{ |
|
791 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
792 |
gen_op_set_cc_op(s->cc_op); |
|
793 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
794 |
gen_stos(s, ot); |
|
795 |
gen_op_dec_ECX[s->aflag](); |
|
796 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
797 |
s->is_jmp = 3; |
|
798 |
} |
|
799 |
|
|
800 | 790 |
static inline void gen_lods(DisasContext *s, int ot) |
801 | 791 |
{ |
802 | 792 |
gen_string_movl_A0_ESI(s); |
... | ... | |
810 | 800 |
} |
811 | 801 |
} |
812 | 802 |
|
813 |
static inline void gen_repz_lods(DisasContext *s, int ot, |
|
814 |
unsigned int cur_eip, unsigned int next_eip) |
|
815 |
{ |
|
816 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
817 |
gen_op_set_cc_op(s->cc_op); |
|
818 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
819 |
gen_lods(s, ot); |
|
820 |
gen_op_dec_ECX[s->aflag](); |
|
821 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
822 |
s->is_jmp = 3; |
|
823 |
} |
|
824 |
|
|
825 | 803 |
static inline void gen_scas(DisasContext *s, int ot) |
826 | 804 |
{ |
827 | 805 |
gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); |
... | ... | |
836 | 814 |
} |
837 | 815 |
} |
838 | 816 |
|
839 |
#if 0 |
|
840 |
static inline void gen_repz_scas(DisasContext *s, int ot, |
|
841 |
unsigned int cur_eip, unsigned int next_eip, |
|
842 |
int nz) |
|
843 |
{ |
|
844 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
845 |
gen_op_set_cc_op(s->cc_op); |
|
846 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
847 |
gen_scas(s, ot); |
|
848 |
gen_op_set_cc_op(CC_OP_SUBB + ot); |
|
849 |
gen_op_string_jnz_sub[nz][ot]((long)s->tb, next_eip); |
|
850 |
gen_op_dec_ECX[s->aflag](); |
|
851 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
852 |
s->is_jmp = 3; |
|
853 |
} |
|
854 |
#endif |
|
855 |
|
|
856 | 817 |
static inline void gen_cmps(DisasContext *s, int ot) |
857 | 818 |
{ |
858 | 819 |
gen_string_movl_A0_ESI(s); |
... | ... | |
883 | 844 |
} |
884 | 845 |
} |
885 | 846 |
|
886 |
static inline void gen_repz_ins(DisasContext *s, int ot, |
|
887 |
unsigned int cur_eip, unsigned int next_eip) |
|
888 |
{ |
|
889 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
890 |
gen_op_set_cc_op(s->cc_op); |
|
891 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
892 |
gen_ins(s, ot); |
|
893 |
gen_op_dec_ECX[s->aflag](); |
|
894 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
895 |
s->is_jmp = 3; |
|
896 |
} |
|
897 |
|
|
898 | 847 |
static inline void gen_outs(DisasContext *s, int ot) |
899 | 848 |
{ |
900 | 849 |
gen_string_movl_A0_ESI(s); |
... | ... | |
908 | 857 |
} |
909 | 858 |
} |
910 | 859 |
|
911 |
static inline void gen_repz_outs(DisasContext *s, int ot, |
|
912 |
unsigned int cur_eip, unsigned int next_eip) |
|
913 |
{ |
|
914 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
915 |
gen_op_set_cc_op(s->cc_op); |
|
916 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
917 |
gen_outs(s, ot); |
|
918 |
gen_op_dec_ECX[s->aflag](); |
|
919 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
920 |
s->is_jmp = 3; |
|
860 |
/* same method as Valgrind : we generate jumps to current or next |
|
861 |
instruction */ |
|
862 |
#define GEN_REPZ(op) \ |
|
863 |
static inline void gen_repz_ ## op(DisasContext *s, int ot, \ |
|
864 |
unsigned int cur_eip, unsigned int next_eip) \ |
|
865 |
{ \ |
|
866 |
gen_update_cc_op(s); \ |
|
867 |
gen_jz_ecx_string(s, next_eip); \ |
|
868 |
gen_ ## op(s, ot); \ |
|
869 |
gen_op_dec_ECX[s->aflag](); \ |
|
870 |
/* a loop would cause two single step exceptions if ECX = 1 \ |
|
871 |
before rep string_insn */ \ |
|
872 |
if (!s->jmp_opt) \ |
|
873 |
gen_op_jz_ecx_im[s->aflag](next_eip); \ |
|
874 |
gen_jmp(s, cur_eip); \ |
|
921 | 875 |
} |
922 | 876 |
|
923 |
static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) |
|
924 |
{ |
|
925 |
int index, override; |
|
926 |
|
|
927 |
override = s->override; |
|
928 |
if (s->aflag) { |
|
929 |
/* 32 bit address */ |
|
930 |
if (s->addseg && override < 0) |
|
931 |
override = R_DS; |
|
932 |
if (override >= 0) { |
|
933 |
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
|
934 |
index = 3 + ot; |
|
935 |
} else { |
|
936 |
index = ot; |
|
937 |
} |
|
938 |
} else { |
|
939 |
if (override < 0) |
|
940 |
override = R_DS; |
|
941 |
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
|
942 |
/* 16 address, always override */ |
|
943 |
index = 6 + ot; |
|
944 |
} |
|
945 |
func[index](); |
|
946 |
} |
|
947 |
|
|
948 |
static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func) |
|
949 |
{ |
|
950 |
int index; |
|
951 |
|
|
952 |
if (s->aflag) { |
|
953 |
if (s->addseg) { |
|
954 |
index = 3 + ot; |
|
955 |
} else { |
|
956 |
index = ot; |
|
957 |
} |
|
958 |
} else { |
|
959 |
index = 6 + ot; |
|
960 |
} |
|
961 |
func[index](); |
|
877 |
#define GEN_REPZ2(op) \ |
|
878 |
static inline void gen_repz_ ## op(DisasContext *s, int ot, \ |
|
879 |
unsigned int cur_eip, \ |
|
880 |
unsigned int next_eip, \ |
|
881 |
int nz) \ |
|
882 |
{ \ |
|
883 |
gen_update_cc_op(s); \ |
|
884 |
gen_jz_ecx_string(s, next_eip); \ |
|
885 |
gen_ ## op(s, ot); \ |
|
886 |
gen_op_dec_ECX[s->aflag](); \ |
|
887 |
gen_op_set_cc_op(CC_OP_SUBB + ot); \ |
|
888 |
if (!s->jmp_opt) \ |
|
889 |
gen_op_string_jnz_sub_im[nz][ot](next_eip); \ |
|
890 |
else \ |
|
891 |
gen_op_string_jnz_sub[nz][ot]((long)s->tb); \ |
|
892 |
if (!s->jmp_opt) \ |
|
893 |
gen_op_jz_ecx_im[s->aflag](next_eip); \ |
|
894 |
gen_jmp(s, cur_eip); \ |
|
962 | 895 |
} |
963 | 896 |
|
897 |
GEN_REPZ(movs) |
|
898 |
GEN_REPZ(stos) |
|
899 |
GEN_REPZ(lods) |
|
900 |
GEN_REPZ(ins) |
|
901 |
GEN_REPZ(outs) |
|
902 |
GEN_REPZ2(scas) |
|
903 |
GEN_REPZ2(cmps) |
|
964 | 904 |
|
965 | 905 |
static GenOpFunc *gen_op_in[3] = { |
966 | 906 |
gen_op_inb_T0_T1, |
... | ... | |
1420 | 1360 |
|
1421 | 1361 |
inv = b & 1; |
1422 | 1362 |
jcc_op = (b >> 1) & 7; |
1423 |
switch(s->cc_op) { |
|
1424 |
/* we optimize the cmp/jcc case */ |
|
1425 |
case CC_OP_SUBB: |
|
1426 |
case CC_OP_SUBW: |
|
1427 |
case CC_OP_SUBL: |
|
1428 |
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; |
|
1429 |
break; |
|
1430 |
|
|
1431 |
/* some jumps are easy to compute */ |
|
1432 |
case CC_OP_ADDB: |
|
1433 |
case CC_OP_ADDW: |
|
1434 |
case CC_OP_ADDL: |
|
1435 |
case CC_OP_ADCB: |
|
1436 |
case CC_OP_ADCW: |
|
1437 |
case CC_OP_ADCL: |
|
1438 |
case CC_OP_SBBB: |
|
1439 |
case CC_OP_SBBW: |
|
1440 |
case CC_OP_SBBL: |
|
1441 |
case CC_OP_LOGICB: |
|
1442 |
case CC_OP_LOGICW: |
|
1443 |
case CC_OP_LOGICL: |
|
1444 |
case CC_OP_INCB: |
|
1445 |
case CC_OP_INCW: |
|
1446 |
case CC_OP_INCL: |
|
1447 |
case CC_OP_DECB: |
|
1448 |
case CC_OP_DECW: |
|
1449 |
case CC_OP_DECL: |
|
1450 |
case CC_OP_SHLB: |
|
1451 |
case CC_OP_SHLW: |
|
1452 |
case CC_OP_SHLL: |
|
1453 |
case CC_OP_SARB: |
|
1454 |
case CC_OP_SARW: |
|
1455 |
case CC_OP_SARL: |
|
1456 |
switch(jcc_op) { |
|
1457 |
case JCC_Z: |
|
1458 |
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
|
1363 |
|
|
1364 |
if (s->jmp_opt) { |
|
1365 |
switch(s->cc_op) { |
|
1366 |
/* we optimize the cmp/jcc case */ |
|
1367 |
case CC_OP_SUBB: |
|
1368 |
case CC_OP_SUBW: |
|
1369 |
case CC_OP_SUBL: |
|
1370 |
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; |
|
1459 | 1371 |
break; |
1460 |
case JCC_S: |
|
1461 |
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
|
1372 |
|
|
1373 |
/* 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 |
} |
|
1462 | 1409 |
break; |
1463 | 1410 |
default: |
1464 | 1411 |
func = NULL; |
1465 | 1412 |
break; |
1466 | 1413 |
} |
1467 |
break; |
|
1468 |
default: |
|
1469 |
func = NULL; |
|
1470 |
break; |
|
1471 |
} |
|
1472 | 1414 |
|
1473 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
1474 |
gen_op_set_cc_op(s->cc_op); |
|
1415 |
if (s->cc_op != CC_OP_DYNAMIC)
|
|
1416 |
gen_op_set_cc_op(s->cc_op);
|
|
1475 | 1417 |
|
1476 |
if (!func) { |
|
1477 |
gen_setcc_slow[jcc_op](); |
|
1478 |
func = gen_op_jcc; |
|
1479 |
} |
|
1418 |
if (!func) {
|
|
1419 |
gen_setcc_slow[jcc_op]();
|
|
1420 |
func = gen_op_jcc;
|
|
1421 |
}
|
|
1480 | 1422 |
|
1481 |
tb = s->tb; |
|
1482 |
if (!inv) { |
|
1483 |
func((long)tb, val, next_eip); |
|
1423 |
tb = s->tb; |
|
1424 |
if (!inv) { |
|
1425 |
func((long)tb, val, next_eip); |
|
1426 |
} else { |
|
1427 |
func((long)tb, next_eip, val); |
|
1428 |
} |
|
1429 |
s->is_jmp = 3; |
|
1484 | 1430 |
} else { |
1485 |
func((long)tb, next_eip, val); |
|
1431 |
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); |
|
1486 | 1442 |
} |
1487 |
s->is_jmp = 3; |
|
1488 | 1443 |
} |
1489 | 1444 |
|
1490 | 1445 |
static void gen_setcc(DisasContext *s, int b) |
... | ... | |
1557 | 1512 |
stop as a special handling must be done to disable hardware |
1558 | 1513 |
interrupts for the next instruction */ |
1559 | 1514 |
if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) |
1560 |
s->is_jmp = 2;
|
|
1515 |
s->is_jmp = 3;
|
|
1561 | 1516 |
} |
1562 | 1517 |
|
1563 | 1518 |
/* generate a push. It depends on ss32, addseg and dflag */ |
... | ... | |
1727 | 1682 |
gen_op_set_cc_op(s->cc_op); |
1728 | 1683 |
gen_op_jmp_im(cur_eip); |
1729 | 1684 |
gen_op_raise_exception(trapno); |
1730 |
s->is_jmp = 1;
|
|
1685 |
s->is_jmp = 3;
|
|
1731 | 1686 |
} |
1732 | 1687 |
|
1733 | 1688 |
/* an interrupt is different from an exception because of the |
... | ... | |
1739 | 1694 |
gen_op_set_cc_op(s->cc_op); |
1740 | 1695 |
gen_op_jmp_im(cur_eip); |
1741 | 1696 |
gen_op_raise_interrupt(intno, next_eip); |
1742 |
s->is_jmp = 1;
|
|
1697 |
s->is_jmp = 3;
|
|
1743 | 1698 |
} |
1744 | 1699 |
|
1745 | 1700 |
static void gen_debug(DisasContext *s, unsigned int cur_eip) |
... | ... | |
1748 | 1703 |
gen_op_set_cc_op(s->cc_op); |
1749 | 1704 |
gen_op_jmp_im(cur_eip); |
1750 | 1705 |
gen_op_debug(); |
1751 |
s->is_jmp = 1; |
|
1706 |
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; |
|
1752 | 1722 |
} |
1753 | 1723 |
|
1754 | 1724 |
/* generate a jump to eip. No segment change must happen before as a |
... | ... | |
1757 | 1727 |
{ |
1758 | 1728 |
TranslationBlock *tb = s->tb; |
1759 | 1729 |
|
1760 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
1761 |
gen_op_set_cc_op(s->cc_op); |
|
1762 |
gen_op_jmp_tb_next((long)tb, eip); |
|
1763 |
s->is_jmp = 3; |
|
1730 |
if (s->jmp_opt) { |
|
1731 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
1732 |
gen_op_set_cc_op(s->cc_op); |
|
1733 |
gen_op_jmp((long)tb, eip); |
|
1734 |
s->is_jmp = 3; |
|
1735 |
} else { |
|
1736 |
gen_op_jmp_im(eip); |
|
1737 |
gen_eob(s); |
|
1738 |
} |
|
1764 | 1739 |
} |
1765 | 1740 |
|
1766 |
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr |
|
1767 |
is set to true if the instruction sets the PC (last instruction of |
|
1768 |
a basic block) */ |
|
1769 |
long disas_insn(DisasContext *s, uint8_t *pc_start) |
|
1741 |
/* convert one instruction. s->is_jmp is set if the translation must |
|
1742 |
be stopped. Return the next pc value */ |
|
1743 |
static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) |
|
1770 | 1744 |
{ |
1771 | 1745 |
int b, prefixes, aflag, dflag; |
1772 | 1746 |
int shift, ot; |
... | ... | |
2106 | 2080 |
next_eip = s->pc - s->cs_base; |
2107 | 2081 |
gen_op_movl_T0_im(next_eip); |
2108 | 2082 |
gen_push_T0(s); |
2109 |
s->is_jmp = 1;
|
|
2083 |
gen_eob(s);
|
|
2110 | 2084 |
break; |
2111 |
case 3: /* lcall Ev */ |
|
2085 |
case 3: /*< lcall Ev */
|
|
2112 | 2086 |
gen_op_ld_T1_A0[ot + s->mem_index](); |
2113 | 2087 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
2114 | 2088 |
gen_op_ld_T0_A0[OT_WORD + s->mem_index](); |
... | ... | |
2121 | 2095 |
} else { |
2122 | 2096 |
gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); |
2123 | 2097 |
} |
2124 |
s->is_jmp = 1;
|
|
2098 |
gen_eob(s);
|
|
2125 | 2099 |
break; |
2126 | 2100 |
case 4: /* jmp Ev */ |
2127 | 2101 |
if (s->dflag == 0) |
2128 | 2102 |
gen_op_andl_T0_ffff(); |
2129 | 2103 |
gen_op_jmp_T0(); |
2130 |
s->is_jmp = 1;
|
|
2104 |
gen_eob(s);
|
|
2131 | 2105 |
break; |
2132 | 2106 |
case 5: /* ljmp Ev */ |
2133 | 2107 |
gen_op_ld_T1_A0[ot + s->mem_index](); |
... | ... | |
2144 | 2118 |
gen_op_movl_T0_T1(); |
2145 | 2119 |
gen_op_jmp_T0(); |
2146 | 2120 |
} |
2147 |
s->is_jmp = 1;
|
|
2121 |
gen_eob(s);
|
|
2148 | 2122 |
break; |
2149 | 2123 |
case 6: /* push Ev */ |
2150 | 2124 |
gen_push_T0(s); |
... | ... | |
2366 | 2340 |
if (reg == R_SS) { |
2367 | 2341 |
/* if reg == SS, inhibit interrupts/trace */ |
2368 | 2342 |
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); |
|
2369 | 2348 |
} |
2370 | 2349 |
break; |
2371 | 2350 |
case 0x1a1: /* pop fs */ |
... | ... | |
2373 | 2352 |
gen_pop_T0(s); |
2374 | 2353 |
gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); |
2375 | 2354 |
gen_pop_update(s); |
2355 |
if (s->is_jmp) { |
|
2356 |
gen_op_jmp_im(s->pc - s->cs_base); |
|
2357 |
gen_eob(s); |
|
2358 |
} |
|
2376 | 2359 |
break; |
2377 | 2360 |
|
2378 | 2361 |
/**************************/ |
... | ... | |
2428 | 2411 |
if (reg == R_SS) { |
2429 | 2412 |
/* if reg == SS, inhibit interrupts/trace */ |
2430 | 2413 |
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); |
|
2431 | 2419 |
} |
2432 | 2420 |
break; |
2433 | 2421 |
case 0x8c: /* mov Gv, seg */ |
... | ... | |
2635 | 2623 |
gen_movl_seg_T0(s, op, pc_start - s->cs_base); |
2636 | 2624 |
/* then put the data */ |
2637 | 2625 |
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 |
} |
|
2638 | 2630 |
break; |
2639 | 2631 |
|
2640 | 2632 |
/************************/ |
... | ... | |
3191 | 3183 |
else |
3192 | 3184 |
ot = dflag ? OT_LONG : OT_WORD; |
3193 | 3185 |
if (prefixes & PREFIX_REPNZ) { |
3194 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
3195 |
gen_op_set_cc_op(s->cc_op); |
|
3196 |
gen_string_es(s, ot, gen_op_scas + STRINGOP_NB); |
|
3197 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
|
3186 |
gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); |
|
3198 | 3187 |
} else if (prefixes & PREFIX_REPZ) { |
3199 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
3200 |
gen_op_set_cc_op(s->cc_op); |
|
3201 |
gen_string_es(s, ot, gen_op_scas); |
|
3202 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
|
3188 |
gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); |
|
3203 | 3189 |
} else { |
3204 | 3190 |
gen_scas(s, ot); |
3205 | 3191 |
s->cc_op = CC_OP_SUBB + ot; |
... | ... | |
3213 | 3199 |
else |
3214 | 3200 |
ot = dflag ? OT_LONG : OT_WORD; |
3215 | 3201 |
if (prefixes & PREFIX_REPNZ) { |
3216 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
3217 |
gen_op_set_cc_op(s->cc_op); |
|
3218 |
gen_string_ds(s, ot, gen_op_cmps + STRINGOP_NB); |
|
3219 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
|
3202 |
gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); |
|
3220 | 3203 |
} else if (prefixes & PREFIX_REPZ) { |
3221 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
3222 |
gen_op_set_cc_op(s->cc_op); |
|
3223 |
gen_string_ds(s, ot, gen_op_cmps); |
|
3224 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
|
3204 |
gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); |
|
3225 | 3205 |
} else { |
3226 | 3206 |
gen_cmps(s, ot); |
3227 | 3207 |
s->cc_op = CC_OP_SUBB + ot; |
... | ... | |
3333 | 3313 |
if (s->dflag == 0) |
3334 | 3314 |
gen_op_andl_T0_ffff(); |
3335 | 3315 |
gen_op_jmp_T0(); |
3336 |
s->is_jmp = 1;
|
|
3316 |
gen_eob(s);
|
|
3337 | 3317 |
break; |
3338 | 3318 |
case 0xc3: /* ret */ |
3339 | 3319 |
gen_pop_T0(s); |
... | ... | |
3341 | 3321 |
if (s->dflag == 0) |
3342 | 3322 |
gen_op_andl_T0_ffff(); |
3343 | 3323 |
gen_op_jmp_T0(); |
3344 |
s->is_jmp = 1;
|
|
3324 |
gen_eob(s);
|
|
3345 | 3325 |
break; |
3346 | 3326 |
case 0xca: /* lret im */ |
3347 | 3327 |
val = ldsw(s->pc); |
... | ... | |
3368 | 3348 |
/* add stack offset */ |
3369 | 3349 |
gen_stack_update(s, val + (4 << s->dflag)); |
3370 | 3350 |
} |
3371 |
s->is_jmp = 1;
|
|
3351 |
gen_eob(s);
|
|
3372 | 3352 |
break; |
3373 | 3353 |
case 0xcb: /* lret */ |
3374 | 3354 |
val = 0; |
... | ... | |
3387 | 3367 |
gen_op_iret_protected(s->dflag); |
3388 | 3368 |
s->cc_op = CC_OP_EFLAGS; |
3389 | 3369 |
} |
3390 |
s->is_jmp = 1;
|
|
3370 |
gen_eob(s);
|
|
3391 | 3371 |
break; |
3392 | 3372 |
case 0xe8: /* call im */ |
3393 | 3373 |
{ |
... | ... | |
3512 | 3492 |
} |
3513 | 3493 |
gen_pop_update(s); |
3514 | 3494 |
s->cc_op = CC_OP_EFLAGS; |
3515 |
s->is_jmp = 2; /* abort translation because TF flag may change */ |
|
3495 |
/* abort translation because TF flag may change */ |
|
3496 |
gen_op_jmp_im(s->pc - s->cs_base); |
|
3497 |
gen_eob(s); |
|
3516 | 3498 |
} |
3517 | 3499 |
break; |
3518 | 3500 |
case 0x9e: /* sahf */ |
... | ... | |
3713 | 3695 |
case 0xfb: /* sti */ |
3714 | 3696 |
if (!s->vm86) { |
3715 | 3697 |
if (s->cpl <= s->iopl) { |
3698 |
gen_sti: |
|
3716 | 3699 |
gen_op_sti(); |
3717 | 3700 |
/* interruptions are enabled only the first insn after sti */ |
3718 | 3701 |
gen_op_set_inhibit_irq(); |
3719 |
s->is_jmp = 2; /* give a chance to handle pending irqs */ |
|
3702 |
/* give a chance to handle pending irqs */ |
|
3703 |
gen_op_jmp_im(s->pc - s->cs_base); |
|
3704 |
gen_eob(s); |
|
3720 | 3705 |
} else { |
3721 | 3706 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3722 | 3707 |
} |
3723 | 3708 |
} else { |
3724 | 3709 |
if (s->iopl == 3) { |
3725 |
gen_op_sti(); |
|
3726 |
/* interruptions are enabled only the first insn after sti */ |
|
3727 |
gen_op_set_inhibit_irq(); |
|
3728 |
s->is_jmp = 2; /* give a chance to handle pending irqs */ |
|
3710 |
goto gen_sti; |
|
3729 | 3711 |
} else { |
3730 | 3712 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3731 | 3713 |
} |
... | ... | |
3769 | 3751 |
if (s->dflag == 0) |
3770 | 3752 |
val &= 0xffff; |
3771 | 3753 |
gen_op_loop[s->aflag][b & 3](val, next_eip); |
3772 |
s->is_jmp = 1;
|
|
3754 |
gen_eob(s);
|
|
3773 | 3755 |
break; |
3774 | 3756 |
case 0x130: /* wrmsr */ |
3775 | 3757 |
case 0x132: /* rdmsr */ |
... | ... | |
3796 | 3778 |
gen_op_set_cc_op(s->cc_op); |
3797 | 3779 |
gen_op_jmp_im(s->pc - s->cs_base); |
3798 | 3780 |
gen_op_hlt(); |
3799 |
s->is_jmp = 1;
|
|
3781 |
s->is_jmp = 3;
|
|
3800 | 3782 |
} |
3801 | 3783 |
break; |
3802 | 3784 |
case 0x100: |
... | ... | |
3968 | 3950 |
if (b & 2) { |
3969 | 3951 |
gen_op_mov_TN_reg[OT_LONG][0][rm](); |
3970 | 3952 |
gen_op_movl_crN_T0(reg); |
3971 |
s->is_jmp = 2; |
|
3953 |
gen_op_jmp_im(s->pc - s->cs_base); |
|
3954 |
gen_eob(s); |
|
3972 | 3955 |
} else { |
3973 | 3956 |
gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); |
3974 | 3957 |
gen_op_mov_reg_T0[OT_LONG][rm](); |
... | ... | |
3995 | 3978 |
if (b & 2) { |
3996 | 3979 |
gen_op_mov_TN_reg[OT_LONG][0][rm](); |
3997 | 3980 |
gen_op_movl_drN_T0(reg); |
3998 |
s->is_jmp = 2; |
|
3981 |
gen_op_jmp_im(s->pc - s->cs_base); |
|
3982 |
gen_eob(s); |
|
3999 | 3983 |
} else { |
4000 | 3984 |
gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); |
4001 | 3985 |
gen_op_mov_reg_T0[OT_LONG][rm](); |
... | ... | |
4015 | 3999 |
/* lock generation */ |
4016 | 4000 |
if (s->prefix & PREFIX_LOCK) |
4017 | 4001 |
gen_op_unlock(); |
4018 |
return (long)s->pc;
|
|
4002 |
return s->pc; |
|
4019 | 4003 |
illegal_op: |
4020 | 4004 |
/* XXX: ensure that no lock was generated */ |
4021 |
return -1; |
|
4005 |
gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); |
|
4006 |
return s->pc; |
|
4022 | 4007 |
} |
4023 | 4008 |
|
4024 | 4009 |
#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) |
... | ... | |
4265 | 4250 |
[INDEX_op_bsrw_T0_cc] = CC_OSZAPC, |
4266 | 4251 |
[INDEX_op_bsrl_T0_cc] = CC_OSZAPC, |
4267 | 4252 |
|
4268 |
#undef STRINGOP |
|
4269 |
#define STRINGOP(x) \ |
|
4270 |
[INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \ |
|
4271 |
[INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \ |
|
4272 |
[INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \ |
|
4273 |
[INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \ |
|
4274 |
[INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \ |
|
4275 |
[INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \ |
|
4276 |
[INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \ |
|
4277 |
[INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ |
|
4278 |
[INDEX_op_ ## x ## l_a16] = CC_OSZAPC, |
|
4279 |
|
|
4280 |
STRINGOP(repz_scas) |
|
4281 |
STRINGOP(repnz_scas) |
|
4282 |
STRINGOP(repz_cmps) |
|
4283 |
STRINGOP(repnz_cmps) |
|
4284 |
|
|
4285 | 4253 |
[INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, |
4286 | 4254 |
[INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, |
4287 | 4255 |
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, |
... | ... | |
4383 | 4351 |
uint8_t *pc_ptr; |
4384 | 4352 |
uint16_t *gen_opc_end; |
4385 | 4353 |
int flags, j, lj; |
4386 |
long ret; |
|
4387 | 4354 |
uint8_t *pc_start; |
4388 | 4355 |
uint8_t *cs_base; |
4389 | 4356 |
|
... | ... | |
4413 | 4380 |
else |
4414 | 4381 |
dc->mem_index = 3; |
4415 | 4382 |
} |
4416 |
|
|
4383 |
dc->jmp_opt = !(dc->tf || env->singlestep_enabled |
|
4384 |
#ifndef CONFIG_SOFT_MMU |
|
4385 |
|| (flags & HF_SOFTMMU_MASK) |
|
4386 |
#endif |
|
4387 |
); |
|
4417 | 4388 |
gen_opc_ptr = gen_opc_buf; |
4418 | 4389 |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
4419 | 4390 |
gen_opparam_ptr = gen_opparam_buf; |
... | ... | |
4428 | 4399 |
if (flags & HF_INHIBIT_IRQ_MASK) { |
4429 | 4400 |
gen_op_reset_inhibit_irq(); |
4430 | 4401 |
} |
4431 |
do {
|
|
4402 |
for(;;) {
|
|
4432 | 4403 |
if (env->nb_breakpoints > 0) { |
4433 | 4404 |
for(j = 0; j < env->nb_breakpoints; j++) { |
4434 | 4405 |
if (env->breakpoints[j] == (unsigned long)pc_ptr) { |
4435 | 4406 |
gen_debug(dc, pc_ptr - dc->cs_base); |
4436 |
goto the_end;
|
|
4407 |
break;
|
|
4437 | 4408 |
} |
4438 | 4409 |
} |
4439 | 4410 |
} |
... | ... | |
4448 | 4419 |
gen_opc_cc_op[lj] = dc->cc_op; |
4449 | 4420 |
gen_opc_instr_start[lj] = 1; |
4450 | 4421 |
} |
4451 |
ret = disas_insn(dc, pc_ptr); |
|
4452 |
if (ret == -1) { |
|
4453 |
/* we trigger an illegal instruction operation only if it |
|
4454 |
is the first instruction. Otherwise, we simply stop |
|
4455 |
generating the code just before it */ |
|
4456 |
if (pc_ptr == pc_start) |
|
4457 |
return -1; |
|
4458 |
else |
|
4459 |
break; |
|
4460 |
} |
|
4461 |
pc_ptr = (void *)ret; |
|
4422 |
pc_ptr = disas_insn(dc, pc_ptr); |
|
4423 |
/* stop translation if indicated */ |
|
4424 |
if (dc->is_jmp) |
|
4425 |
break; |
|
4462 | 4426 |
/* if single step mode, we generate only one instruction and |
4463 | 4427 |
generate an exception */ |
4464 |
if (dc->tf) |
|
4428 |
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); |
|
4465 | 4438 |
break; |
4466 |
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
|
4467 |
(pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); |
|
4468 |
if (!dc->tf && dc->is_jmp == DISAS_NEXT) { |
|
4469 |
gen_jmp(dc, ret - (unsigned long)dc->cs_base); |
|
4470 |
} |
|
4471 |
|
|
4472 |
/* we must store the eflags state if it is not already done */ |
|
4473 |
if (dc->is_jmp != DISAS_TB_JUMP) { |
|
4474 |
if (dc->cc_op != CC_OP_DYNAMIC) |
|
4475 |
gen_op_set_cc_op(dc->cc_op); |
|
4476 |
if (dc->is_jmp != DISAS_JUMP) { |
|
4477 |
/* we add an additionnal jmp to update the simulated PC */ |
|
4478 |
gen_op_jmp_im(ret - (unsigned long)dc->cs_base); |
|
4479 | 4439 |
} |
4480 |
} |
|
4481 |
if (dc->tf) { |
|
4482 |
gen_op_raise_exception(EXCP01_SSTP); |
|
4483 |
} |
|
4484 |
the_end: |
|
4485 |
if (dc->is_jmp != DISAS_TB_JUMP) { |
|
4486 |
/* indicate that the hash table must be used to find the next TB */ |
|
4487 |
gen_op_movl_T0_0(); |
|
4488 |
gen_op_exit_tb(); |
|
4489 | 4440 |
} |
4490 | 4441 |
*gen_opc_ptr = INDEX_op_end; |
4491 | 4442 |
/* we don't forget to fill the last values */ |
Also available in: Unified diff