Commit 9c605cb13547a5faa5cb1092e3e44ac8b0d0b841
1 parent
24f9e90b
added cmpxchg8b, cpuid, bound, eflags support, vm86 mode, 16bit/override string ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@55 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
206 additions
and
182 deletions
translate-i386.c
@@ -76,21 +76,16 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) | @@ -76,21 +76,16 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) | ||
76 | extern FILE *logfile; | 76 | extern FILE *logfile; |
77 | extern int loglevel; | 77 | extern int loglevel; |
78 | 78 | ||
79 | -#define PREFIX_REPZ 1 | ||
80 | -#define PREFIX_REPNZ 2 | ||
81 | -#define PREFIX_LOCK 4 | ||
82 | -#define PREFIX_CS 8 | ||
83 | -#define PREFIX_SS 0x10 | ||
84 | -#define PREFIX_DS 0x20 | ||
85 | -#define PREFIX_ES 0x40 | ||
86 | -#define PREFIX_FS 0x80 | ||
87 | -#define PREFIX_GS 0x100 | ||
88 | -#define PREFIX_DATA 0x200 | ||
89 | -#define PREFIX_ADR 0x400 | ||
90 | -#define PREFIX_FWAIT 0x800 | 79 | +#define PREFIX_REPZ 0x01 |
80 | +#define PREFIX_REPNZ 0x02 | ||
81 | +#define PREFIX_LOCK 0x04 | ||
82 | +#define PREFIX_DATA 0x08 | ||
83 | +#define PREFIX_ADR 0x10 | ||
84 | +#define PREFIX_FWAIT 0x20 | ||
91 | 85 | ||
92 | typedef struct DisasContext { | 86 | typedef struct DisasContext { |
93 | /* current insn context */ | 87 | /* current insn context */ |
88 | + int override; /* -1 if no override */ | ||
94 | int prefix; | 89 | int prefix; |
95 | int aflag, dflag; | 90 | int aflag, dflag; |
96 | uint8_t *pc; /* pc = eip + cs_base */ | 91 | uint8_t *pc; /* pc = eip + cs_base */ |
@@ -103,6 +98,7 @@ typedef struct DisasContext { | @@ -103,6 +98,7 @@ typedef struct DisasContext { | ||
103 | int cc_op; /* current CC operation */ | 98 | int cc_op; /* current CC operation */ |
104 | int addseg; /* non zero if either DS/ES/SS have a non zero base */ | 99 | int addseg; /* non zero if either DS/ES/SS have a non zero base */ |
105 | int f_st; /* currently unused */ | 100 | int f_st; /* currently unused */ |
101 | + int vm86; /* vm86 mode */ | ||
106 | } DisasContext; | 102 | } DisasContext; |
107 | 103 | ||
108 | /* i386 arith/logic operations */ | 104 | /* i386 arith/logic operations */ |
@@ -130,7 +126,7 @@ enum { | @@ -130,7 +126,7 @@ enum { | ||
130 | }; | 126 | }; |
131 | 127 | ||
132 | enum { | 128 | enum { |
133 | -#define DEF(s) INDEX_op_ ## s, | 129 | +#define DEF(s, n) INDEX_op_ ## s, |
134 | #include "opc-i386.h" | 130 | #include "opc-i386.h" |
135 | #undef DEF | 131 | #undef DEF |
136 | NB_OPS, | 132 | NB_OPS, |
@@ -556,76 +552,100 @@ static GenOpFunc *gen_op_st_T0_A0[3] = { | @@ -556,76 +552,100 @@ static GenOpFunc *gen_op_st_T0_A0[3] = { | ||
556 | gen_op_stl_T0_A0, | 552 | gen_op_stl_T0_A0, |
557 | }; | 553 | }; |
558 | 554 | ||
559 | -static GenOpFunc *gen_op_movs[6] = { | ||
560 | - gen_op_movsb, | ||
561 | - gen_op_movsw, | ||
562 | - gen_op_movsl, | ||
563 | - gen_op_rep_movsb, | ||
564 | - gen_op_rep_movsw, | ||
565 | - gen_op_rep_movsl, | 555 | +/* the _a32 and _a16 string operations use A0 as the base register. */ |
556 | + | ||
557 | +#define STRINGOP(x) \ | ||
558 | + gen_op_ ## x ## b_fast, \ | ||
559 | + gen_op_ ## x ## w_fast, \ | ||
560 | + gen_op_ ## x ## l_fast, \ | ||
561 | + gen_op_ ## x ## b_a32, \ | ||
562 | + gen_op_ ## x ## w_a32, \ | ||
563 | + gen_op_ ## x ## l_a32, \ | ||
564 | + gen_op_ ## x ## b_a16, \ | ||
565 | + gen_op_ ## x ## w_a16, \ | ||
566 | + gen_op_ ## x ## l_a16, | ||
567 | + | ||
568 | +static GenOpFunc *gen_op_movs[9 * 2] = { | ||
569 | + STRINGOP(movs) | ||
570 | + STRINGOP(rep_movs) | ||
566 | }; | 571 | }; |
567 | 572 | ||
568 | -static GenOpFunc *gen_op_stos[6] = { | ||
569 | - gen_op_stosb, | ||
570 | - gen_op_stosw, | ||
571 | - gen_op_stosl, | ||
572 | - gen_op_rep_stosb, | ||
573 | - gen_op_rep_stosw, | ||
574 | - gen_op_rep_stosl, | 573 | +static GenOpFunc *gen_op_stos[9 * 2] = { |
574 | + STRINGOP(stos) | ||
575 | + STRINGOP(rep_stos) | ||
575 | }; | 576 | }; |
576 | 577 | ||
577 | -static GenOpFunc *gen_op_lods[6] = { | ||
578 | - gen_op_lodsb, | ||
579 | - gen_op_lodsw, | ||
580 | - gen_op_lodsl, | ||
581 | - gen_op_rep_lodsb, | ||
582 | - gen_op_rep_lodsw, | ||
583 | - gen_op_rep_lodsl, | 578 | +static GenOpFunc *gen_op_lods[9 * 2] = { |
579 | + STRINGOP(lods) | ||
580 | + STRINGOP(rep_lods) | ||
584 | }; | 581 | }; |
585 | 582 | ||
586 | -static GenOpFunc *gen_op_scas[9] = { | ||
587 | - gen_op_scasb, | ||
588 | - gen_op_scasw, | ||
589 | - gen_op_scasl, | ||
590 | - gen_op_repz_scasb, | ||
591 | - gen_op_repz_scasw, | ||
592 | - gen_op_repz_scasl, | ||
593 | - gen_op_repnz_scasb, | ||
594 | - gen_op_repnz_scasw, | ||
595 | - gen_op_repnz_scasl, | 583 | +static GenOpFunc *gen_op_scas[9 * 3] = { |
584 | + STRINGOP(scas) | ||
585 | + STRINGOP(repz_scas) | ||
586 | + STRINGOP(repnz_scas) | ||
596 | }; | 587 | }; |
597 | 588 | ||
598 | -static GenOpFunc *gen_op_cmps[9] = { | ||
599 | - gen_op_cmpsb, | ||
600 | - gen_op_cmpsw, | ||
601 | - gen_op_cmpsl, | ||
602 | - gen_op_repz_cmpsb, | ||
603 | - gen_op_repz_cmpsw, | ||
604 | - gen_op_repz_cmpsl, | ||
605 | - gen_op_repnz_cmpsb, | ||
606 | - gen_op_repnz_cmpsw, | ||
607 | - gen_op_repnz_cmpsl, | 589 | +static GenOpFunc *gen_op_cmps[9 * 3] = { |
590 | + STRINGOP(cmps) | ||
591 | + STRINGOP(repz_cmps) | ||
592 | + STRINGOP(repnz_cmps) | ||
608 | }; | 593 | }; |
609 | 594 | ||
610 | -static GenOpFunc *gen_op_ins[6] = { | ||
611 | - gen_op_insb, | ||
612 | - gen_op_insw, | ||
613 | - gen_op_insl, | ||
614 | - gen_op_rep_insb, | ||
615 | - gen_op_rep_insw, | ||
616 | - gen_op_rep_insl, | 595 | +static GenOpFunc *gen_op_ins[9 * 2] = { |
596 | + STRINGOP(ins) | ||
597 | + STRINGOP(rep_ins) | ||
617 | }; | 598 | }; |
618 | 599 | ||
619 | 600 | ||
620 | -static GenOpFunc *gen_op_outs[6] = { | ||
621 | - gen_op_outsb, | ||
622 | - gen_op_outsw, | ||
623 | - gen_op_outsl, | ||
624 | - gen_op_rep_outsb, | ||
625 | - gen_op_rep_outsw, | ||
626 | - gen_op_rep_outsl, | 601 | +static GenOpFunc *gen_op_outs[9 * 2] = { |
602 | + STRINGOP(outs) | ||
603 | + STRINGOP(rep_outs) | ||
627 | }; | 604 | }; |
628 | 605 | ||
606 | + | ||
607 | +static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) | ||
608 | +{ | ||
609 | + int index, override; | ||
610 | + | ||
611 | + override = s->override; | ||
612 | + if (s->aflag) { | ||
613 | + /* 32 bit address */ | ||
614 | + if (s->addseg && override < 0) | ||
615 | + override = R_DS; | ||
616 | + if (override >= 0) { | ||
617 | + gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | ||
618 | + index = 3 + ot; | ||
619 | + } else { | ||
620 | + index = ot; | ||
621 | + } | ||
622 | + } else { | ||
623 | + if (override < 0) | ||
624 | + override = R_DS; | ||
625 | + gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | ||
626 | + /* 16 address, always override */ | ||
627 | + index = 6 + ot; | ||
628 | + } | ||
629 | + func[index](); | ||
630 | +} | ||
631 | + | ||
632 | +static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func) | ||
633 | +{ | ||
634 | + int index; | ||
635 | + | ||
636 | + if (s->aflag) { | ||
637 | + if (s->addseg) { | ||
638 | + index = 3 + ot; | ||
639 | + } else { | ||
640 | + index = ot; | ||
641 | + } | ||
642 | + } else { | ||
643 | + index = 6 + ot; | ||
644 | + } | ||
645 | + func[index](); | ||
646 | +} | ||
647 | + | ||
648 | + | ||
629 | static GenOpFunc *gen_op_in[3] = { | 649 | static GenOpFunc *gen_op_in[3] = { |
630 | gen_op_inb_T0_T1, | 650 | gen_op_inb_T0_T1, |
631 | gen_op_inw_T0_T1, | 651 | gen_op_inw_T0_T1, |
@@ -849,26 +869,10 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ | @@ -849,26 +869,10 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ | ||
849 | int opreg; | 869 | int opreg; |
850 | int mod, rm, code, override, must_add_seg; | 870 | int mod, rm, code, override, must_add_seg; |
851 | 871 | ||
852 | - /* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */ | ||
853 | - override = -1; | 872 | + override = s->override; |
854 | must_add_seg = s->addseg; | 873 | must_add_seg = s->addseg; |
855 | - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | | ||
856 | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { | ||
857 | - if (s->prefix & PREFIX_ES) | ||
858 | - override = R_ES; | ||
859 | - else if (s->prefix & PREFIX_CS) | ||
860 | - override = R_CS; | ||
861 | - else if (s->prefix & PREFIX_SS) | ||
862 | - override = R_SS; | ||
863 | - else if (s->prefix & PREFIX_DS) | ||
864 | - override = R_DS; | ||
865 | - else if (s->prefix & PREFIX_FS) | ||
866 | - override = R_FS; | ||
867 | - else | ||
868 | - override = R_GS; | 874 | + if (override >= 0) |
869 | must_add_seg = 1; | 875 | must_add_seg = 1; |
870 | - } | ||
871 | - | ||
872 | mod = (modrm >> 6) & 3; | 876 | mod = (modrm >> 6) & 3; |
873 | rm = modrm & 7; | 877 | rm = modrm & 7; |
874 | 878 | ||
@@ -1343,7 +1347,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1343,7 +1347,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
1343 | prefixes = 0; | 1347 | prefixes = 0; |
1344 | aflag = s->code32; | 1348 | aflag = s->code32; |
1345 | dflag = s->code32; | 1349 | dflag = s->code32; |
1346 | - // cur_pc = s->pc; /* for insn generation */ | 1350 | + s->override = -1; |
1347 | next_byte: | 1351 | next_byte: |
1348 | b = ldub(s->pc); | 1352 | b = ldub(s->pc); |
1349 | s->pc++; | 1353 | s->pc++; |
@@ -1359,22 +1363,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1359,22 +1363,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
1359 | prefixes |= PREFIX_LOCK; | 1363 | prefixes |= PREFIX_LOCK; |
1360 | goto next_byte; | 1364 | goto next_byte; |
1361 | case 0x2e: | 1365 | case 0x2e: |
1362 | - prefixes |= PREFIX_CS; | 1366 | + s->override = R_CS; |
1363 | goto next_byte; | 1367 | goto next_byte; |
1364 | case 0x36: | 1368 | case 0x36: |
1365 | - prefixes |= PREFIX_SS; | 1369 | + s->override = R_SS; |
1366 | goto next_byte; | 1370 | goto next_byte; |
1367 | case 0x3e: | 1371 | case 0x3e: |
1368 | - prefixes |= PREFIX_DS; | 1372 | + s->override = R_DS; |
1369 | goto next_byte; | 1373 | goto next_byte; |
1370 | case 0x26: | 1374 | case 0x26: |
1371 | - prefixes |= PREFIX_ES; | 1375 | + s->override = R_ES; |
1372 | goto next_byte; | 1376 | goto next_byte; |
1373 | case 0x64: | 1377 | case 0x64: |
1374 | - prefixes |= PREFIX_FS; | 1378 | + s->override = R_FS; |
1375 | goto next_byte; | 1379 | goto next_byte; |
1376 | case 0x65: | 1380 | case 0x65: |
1377 | - prefixes |= PREFIX_GS; | 1381 | + s->override = R_GS; |
1378 | goto next_byte; | 1382 | goto next_byte; |
1379 | case 0x66: | 1383 | case 0x66: |
1380 | prefixes |= PREFIX_DATA; | 1384 | prefixes |= PREFIX_DATA; |
@@ -1830,6 +1834,17 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1830,6 +1834,17 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
1830 | } | 1834 | } |
1831 | s->cc_op = CC_OP_SUBB + ot; | 1835 | s->cc_op = CC_OP_SUBB + ot; |
1832 | break; | 1836 | break; |
1837 | + case 0x1c7: /* cmpxchg8b */ | ||
1838 | + modrm = ldub(s->pc++); | ||
1839 | + mod = (modrm >> 6) & 3; | ||
1840 | + if (mod == 3) | ||
1841 | + goto illegal_op; | ||
1842 | + if (s->cc_op != CC_OP_DYNAMIC) | ||
1843 | + gen_op_set_cc_op(s->cc_op); | ||
1844 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | ||
1845 | + gen_op_cmpxchg8b(); | ||
1846 | + s->cc_op = CC_OP_EFLAGS; | ||
1847 | + break; | ||
1833 | 1848 | ||
1834 | /**************************/ | 1849 | /**************************/ |
1835 | /* push/pop */ | 1850 | /* push/pop */ |
@@ -2027,8 +2042,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2027,8 +2042,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2027 | modrm = ldub(s->pc++); | 2042 | modrm = ldub(s->pc++); |
2028 | reg = (modrm >> 3) & 7; | 2043 | reg = (modrm >> 3) & 7; |
2029 | /* we must ensure that no segment is added */ | 2044 | /* we must ensure that no segment is added */ |
2030 | - s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS | | ||
2031 | - PREFIX_ES | PREFIX_FS | PREFIX_GS); | 2045 | + s->override = -1; |
2032 | val = s->addseg; | 2046 | val = s->addseg; |
2033 | s->addseg = 0; | 2047 | s->addseg = 0; |
2034 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | 2048 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
@@ -2050,26 +2064,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2050,26 +2064,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2050 | offset_addr = insn_get(s, OT_WORD); | 2064 | offset_addr = insn_get(s, OT_WORD); |
2051 | gen_op_movl_A0_im(offset_addr); | 2065 | gen_op_movl_A0_im(offset_addr); |
2052 | /* handle override */ | 2066 | /* handle override */ |
2053 | - /* XXX: factorize that */ | ||
2054 | { | 2067 | { |
2055 | int override, must_add_seg; | 2068 | int override, must_add_seg; |
2056 | - override = R_DS; | ||
2057 | must_add_seg = s->addseg; | 2069 | must_add_seg = s->addseg; |
2058 | - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | | ||
2059 | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { | ||
2060 | - if (s->prefix & PREFIX_ES) | ||
2061 | - override = R_ES; | ||
2062 | - else if (s->prefix & PREFIX_CS) | ||
2063 | - override = R_CS; | ||
2064 | - else if (s->prefix & PREFIX_SS) | ||
2065 | - override = R_SS; | ||
2066 | - else if (s->prefix & PREFIX_DS) | ||
2067 | - override = R_DS; | ||
2068 | - else if (s->prefix & PREFIX_FS) | ||
2069 | - override = R_FS; | ||
2070 | - else | ||
2071 | - override = R_GS; | 2070 | + if (s->override >= 0) { |
2071 | + override = s->override; | ||
2072 | must_add_seg = 1; | 2072 | must_add_seg = 1; |
2073 | + } else { | ||
2074 | + override = R_DS; | ||
2073 | } | 2075 | } |
2074 | if (must_add_seg) { | 2076 | if (must_add_seg) { |
2075 | gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | 2077 | gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); |
@@ -2084,31 +2086,20 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2084,31 +2086,20 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2084 | } | 2086 | } |
2085 | break; | 2087 | break; |
2086 | case 0xd7: /* xlat */ | 2088 | case 0xd7: /* xlat */ |
2087 | - /* handle override */ | ||
2088 | gen_op_movl_A0_reg[R_EBX](); | 2089 | gen_op_movl_A0_reg[R_EBX](); |
2089 | gen_op_addl_A0_AL(); | 2090 | gen_op_addl_A0_AL(); |
2090 | if (s->aflag == 0) | 2091 | if (s->aflag == 0) |
2091 | gen_op_andl_A0_ffff(); | 2092 | gen_op_andl_A0_ffff(); |
2092 | - /* XXX: factorize that */ | 2093 | + /* handle override */ |
2093 | { | 2094 | { |
2094 | int override, must_add_seg; | 2095 | int override, must_add_seg; |
2095 | - override = R_DS; | ||
2096 | must_add_seg = s->addseg; | 2096 | must_add_seg = s->addseg; |
2097 | - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | | ||
2098 | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { | ||
2099 | - if (s->prefix & PREFIX_ES) | ||
2100 | - override = R_ES; | ||
2101 | - else if (s->prefix & PREFIX_CS) | ||
2102 | - override = R_CS; | ||
2103 | - else if (s->prefix & PREFIX_SS) | ||
2104 | - override = R_SS; | ||
2105 | - else if (s->prefix & PREFIX_DS) | ||
2106 | - override = R_DS; | ||
2107 | - else if (s->prefix & PREFIX_FS) | ||
2108 | - override = R_FS; | ||
2109 | - else | ||
2110 | - override = R_GS; | 2097 | + override = R_DS; |
2098 | + if (s->override >= 0) { | ||
2099 | + override = s->override; | ||
2111 | must_add_seg = 1; | 2100 | must_add_seg = 1; |
2101 | + } else { | ||
2102 | + override = R_DS; | ||
2112 | } | 2103 | } |
2113 | if (must_add_seg) { | 2104 | if (must_add_seg) { |
2114 | gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); | 2105 | gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); |
@@ -2185,6 +2176,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2185,6 +2176,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2185 | mod = (modrm >> 6) & 3; | 2176 | mod = (modrm >> 6) & 3; |
2186 | if (mod == 3) | 2177 | if (mod == 3) |
2187 | goto illegal_op; | 2178 | goto illegal_op; |
2179 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | ||
2188 | gen_op_ld_T1_A0[ot](); | 2180 | gen_op_ld_T1_A0[ot](); |
2189 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); | 2181 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
2190 | /* load the segment first to handle exceptions properly */ | 2182 | /* load the segment first to handle exceptions properly */ |
@@ -2658,16 +2650,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2658,16 +2650,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2658 | break; | 2650 | break; |
2659 | /************************/ | 2651 | /************************/ |
2660 | /* string ops */ | 2652 | /* string ops */ |
2653 | + | ||
2661 | case 0xa4: /* movsS */ | 2654 | case 0xa4: /* movsS */ |
2662 | case 0xa5: | 2655 | case 0xa5: |
2663 | if ((b & 1) == 0) | 2656 | if ((b & 1) == 0) |
2664 | ot = OT_BYTE; | 2657 | ot = OT_BYTE; |
2665 | else | 2658 | else |
2666 | ot = dflag ? OT_LONG : OT_WORD; | 2659 | ot = dflag ? OT_LONG : OT_WORD; |
2660 | + | ||
2667 | if (prefixes & PREFIX_REPZ) { | 2661 | if (prefixes & PREFIX_REPZ) { |
2668 | - gen_op_movs[3 + ot](); | 2662 | + gen_string_ds(s, ot, gen_op_movs + 9); |
2669 | } else { | 2663 | } else { |
2670 | - gen_op_movs[ot](); | 2664 | + gen_string_ds(s, ot, gen_op_movs); |
2671 | } | 2665 | } |
2672 | break; | 2666 | break; |
2673 | 2667 | ||
@@ -2677,10 +2671,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2677,10 +2671,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2677 | ot = OT_BYTE; | 2671 | ot = OT_BYTE; |
2678 | else | 2672 | else |
2679 | ot = dflag ? OT_LONG : OT_WORD; | 2673 | ot = dflag ? OT_LONG : OT_WORD; |
2674 | + | ||
2680 | if (prefixes & PREFIX_REPZ) { | 2675 | if (prefixes & PREFIX_REPZ) { |
2681 | - gen_op_stos[3 + ot](); | 2676 | + gen_string_es(s, ot, gen_op_stos + 9); |
2682 | } else { | 2677 | } else { |
2683 | - gen_op_stos[ot](); | 2678 | + gen_string_es(s, ot, gen_op_stos); |
2684 | } | 2679 | } |
2685 | break; | 2680 | break; |
2686 | case 0xac: /* lodsS */ | 2681 | case 0xac: /* lodsS */ |
@@ -2690,9 +2685,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2690,9 +2685,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2690 | else | 2685 | else |
2691 | ot = dflag ? OT_LONG : OT_WORD; | 2686 | ot = dflag ? OT_LONG : OT_WORD; |
2692 | if (prefixes & PREFIX_REPZ) { | 2687 | if (prefixes & PREFIX_REPZ) { |
2693 | - gen_op_lods[3 + ot](); | 2688 | + gen_string_ds(s, ot, gen_op_lods + 9); |
2694 | } else { | 2689 | } else { |
2695 | - gen_op_lods[ot](); | 2690 | + gen_string_ds(s, ot, gen_op_lods); |
2696 | } | 2691 | } |
2697 | break; | 2692 | break; |
2698 | case 0xae: /* scasS */ | 2693 | case 0xae: /* scasS */ |
@@ -2700,19 +2695,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2700,19 +2695,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2700 | if ((b & 1) == 0) | 2695 | if ((b & 1) == 0) |
2701 | ot = OT_BYTE; | 2696 | ot = OT_BYTE; |
2702 | else | 2697 | else |
2703 | - ot = dflag ? OT_LONG : OT_WORD; | 2698 | + ot = dflag ? OT_LONG : OT_WORD; |
2704 | if (prefixes & PREFIX_REPNZ) { | 2699 | if (prefixes & PREFIX_REPNZ) { |
2705 | if (s->cc_op != CC_OP_DYNAMIC) | 2700 | if (s->cc_op != CC_OP_DYNAMIC) |
2706 | gen_op_set_cc_op(s->cc_op); | 2701 | gen_op_set_cc_op(s->cc_op); |
2707 | - gen_op_scas[6 + ot](); | 2702 | + gen_string_es(s, ot, gen_op_scas + 9 * 2); |
2708 | s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ | 2703 | s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
2709 | } else if (prefixes & PREFIX_REPZ) { | 2704 | } else if (prefixes & PREFIX_REPZ) { |
2710 | if (s->cc_op != CC_OP_DYNAMIC) | 2705 | if (s->cc_op != CC_OP_DYNAMIC) |
2711 | gen_op_set_cc_op(s->cc_op); | 2706 | gen_op_set_cc_op(s->cc_op); |
2712 | - gen_op_scas[3 + ot](); | 2707 | + gen_string_es(s, ot, gen_op_scas + 9); |
2713 | s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ | 2708 | s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
2714 | } else { | 2709 | } else { |
2715 | - gen_op_scas[ot](); | 2710 | + gen_string_es(s, ot, gen_op_scas); |
2716 | s->cc_op = CC_OP_SUBB + ot; | 2711 | s->cc_op = CC_OP_SUBB + ot; |
2717 | } | 2712 | } |
2718 | break; | 2713 | break; |
@@ -2726,21 +2721,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2726,21 +2721,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2726 | if (prefixes & PREFIX_REPNZ) { | 2721 | if (prefixes & PREFIX_REPNZ) { |
2727 | if (s->cc_op != CC_OP_DYNAMIC) | 2722 | if (s->cc_op != CC_OP_DYNAMIC) |
2728 | gen_op_set_cc_op(s->cc_op); | 2723 | gen_op_set_cc_op(s->cc_op); |
2729 | - gen_op_cmps[6 + ot](); | 2724 | + gen_string_ds(s, ot, gen_op_cmps + 9 * 2); |
2730 | s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ | 2725 | s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
2731 | } else if (prefixes & PREFIX_REPZ) { | 2726 | } else if (prefixes & PREFIX_REPZ) { |
2732 | if (s->cc_op != CC_OP_DYNAMIC) | 2727 | if (s->cc_op != CC_OP_DYNAMIC) |
2733 | gen_op_set_cc_op(s->cc_op); | 2728 | gen_op_set_cc_op(s->cc_op); |
2734 | - gen_op_cmps[3 + ot](); | 2729 | + gen_string_ds(s, ot, gen_op_cmps + 9); |
2735 | s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ | 2730 | s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
2736 | } else { | 2731 | } else { |
2737 | - gen_op_cmps[ot](); | 2732 | + gen_string_ds(s, ot, gen_op_cmps); |
2738 | s->cc_op = CC_OP_SUBB + ot; | 2733 | s->cc_op = CC_OP_SUBB + ot; |
2739 | } | 2734 | } |
2740 | break; | 2735 | break; |
2741 | - | ||
2742 | - /************************/ | ||
2743 | - /* port I/O */ | ||
2744 | case 0x6c: /* insS */ | 2736 | case 0x6c: /* insS */ |
2745 | case 0x6d: | 2737 | case 0x6d: |
2746 | if ((b & 1) == 0) | 2738 | if ((b & 1) == 0) |
@@ -2748,9 +2740,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2748,9 +2740,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2748 | else | 2740 | else |
2749 | ot = dflag ? OT_LONG : OT_WORD; | 2741 | ot = dflag ? OT_LONG : OT_WORD; |
2750 | if (prefixes & PREFIX_REPZ) { | 2742 | if (prefixes & PREFIX_REPZ) { |
2751 | - gen_op_ins[3 + ot](); | 2743 | + gen_string_es(s, ot, gen_op_ins + 9); |
2752 | } else { | 2744 | } else { |
2753 | - gen_op_ins[ot](); | 2745 | + gen_string_es(s, ot, gen_op_ins); |
2754 | } | 2746 | } |
2755 | break; | 2747 | break; |
2756 | case 0x6e: /* outsS */ | 2748 | case 0x6e: /* outsS */ |
@@ -2760,11 +2752,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2760,11 +2752,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2760 | else | 2752 | else |
2761 | ot = dflag ? OT_LONG : OT_WORD; | 2753 | ot = dflag ? OT_LONG : OT_WORD; |
2762 | if (prefixes & PREFIX_REPZ) { | 2754 | if (prefixes & PREFIX_REPZ) { |
2763 | - gen_op_outs[3 + ot](); | 2755 | + gen_string_ds(s, ot, gen_op_outs + 9); |
2764 | } else { | 2756 | } else { |
2765 | - gen_op_outs[ot](); | 2757 | + gen_string_ds(s, ot, gen_op_outs); |
2766 | } | 2758 | } |
2767 | break; | 2759 | break; |
2760 | + | ||
2761 | + /************************/ | ||
2762 | + /* port I/O */ | ||
2768 | case 0xe4: | 2763 | case 0xe4: |
2769 | case 0xe5: | 2764 | case 0xe5: |
2770 | if ((b & 1) == 0) | 2765 | if ((b & 1) == 0) |
@@ -3150,14 +3145,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3150,14 +3145,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3150 | case 0xcd: /* int N */ | 3145 | case 0xcd: /* int N */ |
3151 | val = ldub(s->pc++); | 3146 | val = ldub(s->pc++); |
3152 | /* XXX: currently we ignore the interrupt number */ | 3147 | /* XXX: currently we ignore the interrupt number */ |
3153 | - gen_op_int_im((long)pc_start); | 3148 | + gen_op_int_im(pc_start - s->cs_base); |
3154 | s->is_jmp = 1; | 3149 | s->is_jmp = 1; |
3155 | break; | 3150 | break; |
3156 | case 0xce: /* into */ | 3151 | case 0xce: /* into */ |
3157 | if (s->cc_op != CC_OP_DYNAMIC) | 3152 | if (s->cc_op != CC_OP_DYNAMIC) |
3158 | gen_op_set_cc_op(s->cc_op); | 3153 | gen_op_set_cc_op(s->cc_op); |
3159 | - gen_op_into((long)pc_start, (long)s->pc); | ||
3160 | - s->is_jmp = 1; | 3154 | + gen_op_into(); |
3155 | + break; | ||
3156 | + case 0x62: /* bound */ | ||
3157 | + ot = dflag ? OT_LONG : OT_WORD; | ||
3158 | + modrm = ldub(s->pc++); | ||
3159 | + reg = (modrm >> 3) & 7; | ||
3160 | + mod = (modrm >> 6) & 3; | ||
3161 | + if (mod == 3) | ||
3162 | + goto illegal_op; | ||
3163 | + gen_op_mov_reg_T0[ot][reg](); | ||
3164 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | ||
3165 | + if (ot == OT_WORD) | ||
3166 | + gen_op_boundw(); | ||
3167 | + else | ||
3168 | + gen_op_boundl(); | ||
3161 | break; | 3169 | break; |
3162 | case 0x1c8 ... 0x1cf: /* bswap reg */ | 3170 | case 0x1c8 ... 0x1cf: /* bswap reg */ |
3163 | reg = b & 7; | 3171 | reg = b & 7; |
@@ -3188,11 +3196,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3188,11 +3196,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3188 | case 0x131: /* rdtsc */ | 3196 | case 0x131: /* rdtsc */ |
3189 | gen_op_rdtsc(); | 3197 | gen_op_rdtsc(); |
3190 | break; | 3198 | break; |
3191 | -#if 0 | ||
3192 | case 0x1a2: /* cpuid */ | 3199 | case 0x1a2: /* cpuid */ |
3193 | - gen_insn0(OP_ASM); | 3200 | + gen_op_cpuid(); |
3194 | break; | 3201 | break; |
3195 | -#endif | ||
3196 | default: | 3202 | default: |
3197 | goto illegal_op; | 3203 | goto illegal_op; |
3198 | } | 3204 | } |
@@ -3399,28 +3405,30 @@ static uint16_t opc_write_flags[NB_OPS] = { | @@ -3399,28 +3405,30 @@ static uint16_t opc_write_flags[NB_OPS] = { | ||
3399 | [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, | 3405 | [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, |
3400 | [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, | 3406 | [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, |
3401 | 3407 | ||
3402 | - [INDEX_op_scasb] = CC_OSZAPC, | ||
3403 | - [INDEX_op_scasw] = CC_OSZAPC, | ||
3404 | - [INDEX_op_scasl] = CC_OSZAPC, | ||
3405 | - [INDEX_op_repz_scasb] = CC_OSZAPC, | ||
3406 | - [INDEX_op_repz_scasw] = CC_OSZAPC, | ||
3407 | - [INDEX_op_repz_scasl] = CC_OSZAPC, | ||
3408 | - [INDEX_op_repnz_scasb] = CC_OSZAPC, | ||
3409 | - [INDEX_op_repnz_scasw] = CC_OSZAPC, | ||
3410 | - [INDEX_op_repnz_scasl] = CC_OSZAPC, | ||
3411 | - | ||
3412 | - [INDEX_op_cmpsb] = CC_OSZAPC, | ||
3413 | - [INDEX_op_cmpsw] = CC_OSZAPC, | ||
3414 | - [INDEX_op_cmpsl] = CC_OSZAPC, | ||
3415 | - [INDEX_op_repz_cmpsb] = CC_OSZAPC, | ||
3416 | - [INDEX_op_repz_cmpsw] = CC_OSZAPC, | ||
3417 | - [INDEX_op_repz_cmpsl] = CC_OSZAPC, | ||
3418 | - [INDEX_op_repnz_cmpsb] = CC_OSZAPC, | ||
3419 | - [INDEX_op_repnz_cmpsw] = CC_OSZAPC, | ||
3420 | - [INDEX_op_repnz_cmpsl] = CC_OSZAPC, | ||
3421 | - | 3408 | +#undef STRINGOP |
3409 | +#define STRINGOP(x) \ | ||
3410 | + [INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \ | ||
3411 | + [INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \ | ||
3412 | + [INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \ | ||
3413 | + [INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \ | ||
3414 | + [INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \ | ||
3415 | + [INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \ | ||
3416 | + [INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \ | ||
3417 | + [INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ | ||
3418 | + [INDEX_op_ ## x ## l_a16] = CC_OSZAPC, | ||
3419 | + | ||
3420 | + STRINGOP(scas) | ||
3421 | + STRINGOP(repz_scas) | ||
3422 | + STRINGOP(repnz_scas) | ||
3423 | + STRINGOP(cmps) | ||
3424 | + STRINGOP(repz_cmps) | ||
3425 | + STRINGOP(repnz_cmps) | ||
3426 | + | ||
3427 | + [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, | ||
3422 | [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, | 3428 | [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, |
3423 | [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, | 3429 | [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, |
3430 | + | ||
3431 | + [INDEX_op_cmpxchg8b] = CC_Z, | ||
3424 | }; | 3432 | }; |
3425 | 3433 | ||
3426 | /* simpler form of an operation if no flags need to be generated */ | 3434 | /* simpler form of an operation if no flags need to be generated */ |
@@ -3495,21 +3503,36 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) | @@ -3495,21 +3503,36 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) | ||
3495 | 3503 | ||
3496 | #ifdef DEBUG_DISAS | 3504 | #ifdef DEBUG_DISAS |
3497 | static const char *op_str[] = { | 3505 | static const char *op_str[] = { |
3498 | -#define DEF(s) #s, | 3506 | +#define DEF(s, n) #s, |
3507 | +#include "opc-i386.h" | ||
3508 | +#undef DEF | ||
3509 | +}; | ||
3510 | + | ||
3511 | +static uint8_t op_nb_args[] = { | ||
3512 | +#define DEF(s, n) n, | ||
3499 | #include "opc-i386.h" | 3513 | #include "opc-i386.h" |
3500 | #undef DEF | 3514 | #undef DEF |
3501 | }; | 3515 | }; |
3502 | 3516 | ||
3503 | -static void dump_ops(const uint16_t *opc_buf) | 3517 | +static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) |
3504 | { | 3518 | { |
3505 | const uint16_t *opc_ptr; | 3519 | const uint16_t *opc_ptr; |
3506 | - int c; | 3520 | + const uint32_t *opparam_ptr; |
3521 | + int c, n, i; | ||
3522 | + | ||
3507 | opc_ptr = opc_buf; | 3523 | opc_ptr = opc_buf; |
3524 | + opparam_ptr = opparam_buf; | ||
3508 | for(;;) { | 3525 | for(;;) { |
3509 | c = *opc_ptr++; | 3526 | c = *opc_ptr++; |
3510 | - fprintf(logfile, "0x%04x: %s\n", opc_ptr - opc_buf - 1, op_str[c]); | 3527 | + n = op_nb_args[c]; |
3528 | + fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]); | ||
3529 | + for(i = 0; i < n; i++) { | ||
3530 | + fprintf(logfile, " 0x%x", opparam_ptr[i]); | ||
3531 | + } | ||
3532 | + fprintf(logfile, "\n"); | ||
3511 | if (c == INDEX_op_end) | 3533 | if (c == INDEX_op_end) |
3512 | break; | 3534 | break; |
3535 | + opparam_ptr += n; | ||
3513 | } | 3536 | } |
3514 | } | 3537 | } |
3515 | 3538 | ||
@@ -3547,6 +3570,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | @@ -3547,6 +3570,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
3547 | dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; | 3570 | dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; |
3548 | dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; | 3571 | dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; |
3549 | dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; | 3572 | dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; |
3573 | + dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; | ||
3550 | dc->cc_op = CC_OP_DYNAMIC; | 3574 | dc->cc_op = CC_OP_DYNAMIC; |
3551 | dc->cs_base = cs_base; | 3575 | dc->cs_base = cs_base; |
3552 | 3576 | ||
@@ -3610,7 +3634,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | @@ -3610,7 +3634,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
3610 | fprintf(logfile, "\n"); | 3634 | fprintf(logfile, "\n"); |
3611 | 3635 | ||
3612 | fprintf(logfile, "OP:\n"); | 3636 | fprintf(logfile, "OP:\n"); |
3613 | - dump_ops(gen_opc_buf); | 3637 | + dump_ops(gen_opc_buf, gen_opparam_buf); |
3614 | fprintf(logfile, "\n"); | 3638 | fprintf(logfile, "\n"); |
3615 | } | 3639 | } |
3616 | #endif | 3640 | #endif |
@@ -3621,7 +3645,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | @@ -3621,7 +3645,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
3621 | #ifdef DEBUG_DISAS | 3645 | #ifdef DEBUG_DISAS |
3622 | if (loglevel) { | 3646 | if (loglevel) { |
3623 | fprintf(logfile, "AFTER FLAGS OPT:\n"); | 3647 | fprintf(logfile, "AFTER FLAGS OPT:\n"); |
3624 | - dump_ops(gen_opc_buf); | 3648 | + dump_ops(gen_opc_buf, gen_opparam_buf); |
3625 | fprintf(logfile, "\n"); | 3649 | fprintf(logfile, "\n"); |
3626 | } | 3650 | } |
3627 | #endif | 3651 | #endif |
@@ -3683,8 +3707,8 @@ CPUX86State *cpu_x86_init(void) | @@ -3683,8 +3707,8 @@ CPUX86State *cpu_x86_init(void) | ||
3683 | for(i = 0;i < 8; i++) | 3707 | for(i = 0;i < 8; i++) |
3684 | env->fptags[i] = 1; | 3708 | env->fptags[i] = 1; |
3685 | env->fpuc = 0x37f; | 3709 | env->fpuc = 0x37f; |
3686 | - /* flags setup */ | ||
3687 | - env->eflags = 0; | 3710 | + /* flags setup : we activate the IRQs by default as in user mode */ |
3711 | + env->eflags = 0x2 | IF_MASK; | ||
3688 | 3712 | ||
3689 | /* init various static tables */ | 3713 | /* init various static tables */ |
3690 | if (!inited) { | 3714 | if (!inited) { |