Commit dbc5594cb6294f34c257df11bef484e45493f85e
1 parent
4cbb86e1
finished simplifying string operations - correct TF flag handling for string ope…
…rations 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
Showing
1 changed file
with
247 additions
and
296 deletions
translate-i386.c
... | ... | @@ -60,11 +60,15 @@ typedef struct DisasContext { |
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,31 +639,6 @@ static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { |
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,12 +691,17 @@ static GenOpFunc2 *gen_op_jz_ecx[2] = { |
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,6 +714,19 @@ static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = { |
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,18 +755,23 @@ static inline void gen_movs(DisasContext *s, int ot) |
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,18 +787,6 @@ 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,18 +800,6 @@ static inline void gen_lods(DisasContext *s, int ot) |
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,23 +814,6 @@ static inline void gen_scas(DisasContext *s, int ot) |
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,18 +844,6 @@ static inline void gen_ins(DisasContext *s, int ot) |
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,59 +857,50 @@ static inline void gen_outs(DisasContext *s, int ot) |
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,71 +1360,86 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) |
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,7 +1512,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) |
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,7 +1682,7 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) |
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,7 +1694,7 @@ static void gen_interrupt(DisasContext *s, int intno, |
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,7 +1703,22 @@ 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,16 +1727,20 @@ static void gen_jmp(DisasContext *s, unsigned int eip) |
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,9 +2080,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,13 +2095,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +2118,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,6 +2340,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,6 +2352,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,6 +2411,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,6 +2623,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,15 +3183,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,15 +3199,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3313,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3321,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3348,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3367,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3492,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,19 +3695,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3751,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3778,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3950,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +3978,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,10 +3999,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
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,23 +4250,6 @@ static uint16_t opc_write_flags[NB_OPS] = { |
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,7 +4351,6 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
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,7 +4380,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
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,12 +4399,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
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,44 +4419,24 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
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 */ | ... | ... |