diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-29 16:51:35 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-29 16:51:35 +0000 |
commit | 9c605cb13547a5faa5cb1092e3e44ac8b0d0b841 (patch) | |
tree | e55a62e6dc55298b1d1c5dca2042fa49cca89232 /translate-i386.c | |
parent | 24f9e90b0e183d501ff77c6851cbe11e7d7254a1 (diff) |
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
Diffstat (limited to 'translate-i386.c')
-rw-r--r-- | translate-i386.c | 388 |
1 files changed, 206 insertions, 182 deletions
diff --git a/translate-i386.c b/translate-i386.c index d7f6520e8f..730398e971 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -76,21 +76,16 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) extern FILE *logfile; extern int loglevel; -#define PREFIX_REPZ 1 -#define PREFIX_REPNZ 2 -#define PREFIX_LOCK 4 -#define PREFIX_CS 8 -#define PREFIX_SS 0x10 -#define PREFIX_DS 0x20 -#define PREFIX_ES 0x40 -#define PREFIX_FS 0x80 -#define PREFIX_GS 0x100 -#define PREFIX_DATA 0x200 -#define PREFIX_ADR 0x400 -#define PREFIX_FWAIT 0x800 +#define PREFIX_REPZ 0x01 +#define PREFIX_REPNZ 0x02 +#define PREFIX_LOCK 0x04 +#define PREFIX_DATA 0x08 +#define PREFIX_ADR 0x10 +#define PREFIX_FWAIT 0x20 typedef struct DisasContext { /* current insn context */ + int override; /* -1 if no override */ int prefix; int aflag, dflag; uint8_t *pc; /* pc = eip + cs_base */ @@ -103,6 +98,7 @@ typedef struct DisasContext { int cc_op; /* current CC operation */ int addseg; /* non zero if either DS/ES/SS have a non zero base */ int f_st; /* currently unused */ + int vm86; /* vm86 mode */ } DisasContext; /* i386 arith/logic operations */ @@ -130,7 +126,7 @@ enum { }; enum { -#define DEF(s) INDEX_op_ ## s, +#define DEF(s, n) INDEX_op_ ## s, #include "opc-i386.h" #undef DEF NB_OPS, @@ -556,76 +552,100 @@ static GenOpFunc *gen_op_st_T0_A0[3] = { gen_op_stl_T0_A0, }; -static GenOpFunc *gen_op_movs[6] = { - gen_op_movsb, - gen_op_movsw, - gen_op_movsl, - gen_op_rep_movsb, - gen_op_rep_movsw, - gen_op_rep_movsl, +/* the _a32 and _a16 string operations use A0 as the base register. */ + +#define STRINGOP(x) \ + gen_op_ ## x ## b_fast, \ + gen_op_ ## x ## w_fast, \ + gen_op_ ## x ## l_fast, \ + gen_op_ ## x ## b_a32, \ + gen_op_ ## x ## w_a32, \ + gen_op_ ## x ## l_a32, \ + gen_op_ ## x ## b_a16, \ + gen_op_ ## x ## w_a16, \ + gen_op_ ## x ## l_a16, + +static GenOpFunc *gen_op_movs[9 * 2] = { + STRINGOP(movs) + STRINGOP(rep_movs) }; -static GenOpFunc *gen_op_stos[6] = { - gen_op_stosb, - gen_op_stosw, - gen_op_stosl, - gen_op_rep_stosb, - gen_op_rep_stosw, - gen_op_rep_stosl, +static GenOpFunc *gen_op_stos[9 * 2] = { + STRINGOP(stos) + STRINGOP(rep_stos) }; -static GenOpFunc *gen_op_lods[6] = { - gen_op_lodsb, - gen_op_lodsw, - gen_op_lodsl, - gen_op_rep_lodsb, - gen_op_rep_lodsw, - gen_op_rep_lodsl, +static GenOpFunc *gen_op_lods[9 * 2] = { + STRINGOP(lods) + STRINGOP(rep_lods) }; -static GenOpFunc *gen_op_scas[9] = { - gen_op_scasb, - gen_op_scasw, - gen_op_scasl, - gen_op_repz_scasb, - gen_op_repz_scasw, - gen_op_repz_scasl, - gen_op_repnz_scasb, - gen_op_repnz_scasw, - gen_op_repnz_scasl, +static GenOpFunc *gen_op_scas[9 * 3] = { + STRINGOP(scas) + STRINGOP(repz_scas) + STRINGOP(repnz_scas) }; -static GenOpFunc *gen_op_cmps[9] = { - gen_op_cmpsb, - gen_op_cmpsw, - gen_op_cmpsl, - gen_op_repz_cmpsb, - gen_op_repz_cmpsw, - gen_op_repz_cmpsl, - gen_op_repnz_cmpsb, - gen_op_repnz_cmpsw, - gen_op_repnz_cmpsl, +static GenOpFunc *gen_op_cmps[9 * 3] = { + STRINGOP(cmps) + STRINGOP(repz_cmps) + STRINGOP(repnz_cmps) }; -static GenOpFunc *gen_op_ins[6] = { - gen_op_insb, - gen_op_insw, - gen_op_insl, - gen_op_rep_insb, - gen_op_rep_insw, - gen_op_rep_insl, +static GenOpFunc *gen_op_ins[9 * 2] = { + STRINGOP(ins) + STRINGOP(rep_ins) }; -static GenOpFunc *gen_op_outs[6] = { - gen_op_outsb, - gen_op_outsw, - gen_op_outsl, - gen_op_rep_outsb, - gen_op_rep_outsw, - gen_op_rep_outsl, +static GenOpFunc *gen_op_outs[9 * 2] = { + STRINGOP(outs) + STRINGOP(rep_outs) }; + +static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) +{ + int index, override; + + override = s->override; + if (s->aflag) { + /* 32 bit address */ + if (s->addseg && override < 0) + override = R_DS; + if (override >= 0) { + gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + index = 3 + ot; + } else { + index = ot; + } + } else { + if (override < 0) + override = R_DS; + gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + /* 16 address, always override */ + index = 6 + ot; + } + func[index](); +} + +static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func) +{ + int index; + + if (s->aflag) { + if (s->addseg) { + index = 3 + ot; + } else { + index = ot; + } + } else { + index = 6 + ot; + } + func[index](); +} + + static GenOpFunc *gen_op_in[3] = { gen_op_inb_T0_T1, gen_op_inw_T0_T1, @@ -849,26 +869,10 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ int opreg; int mod, rm, code, override, must_add_seg; - /* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */ - override = -1; + override = s->override; must_add_seg = s->addseg; - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { - if (s->prefix & PREFIX_ES) - override = R_ES; - else if (s->prefix & PREFIX_CS) - override = R_CS; - else if (s->prefix & PREFIX_SS) - override = R_SS; - else if (s->prefix & PREFIX_DS) - override = R_DS; - else if (s->prefix & PREFIX_FS) - override = R_FS; - else - override = R_GS; + if (override >= 0) must_add_seg = 1; - } - mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -1343,7 +1347,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) prefixes = 0; aflag = s->code32; dflag = s->code32; - // cur_pc = s->pc; /* for insn generation */ + s->override = -1; next_byte: b = ldub(s->pc); s->pc++; @@ -1359,22 +1363,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) prefixes |= PREFIX_LOCK; goto next_byte; case 0x2e: - prefixes |= PREFIX_CS; + s->override = R_CS; goto next_byte; case 0x36: - prefixes |= PREFIX_SS; + s->override = R_SS; goto next_byte; case 0x3e: - prefixes |= PREFIX_DS; + s->override = R_DS; goto next_byte; case 0x26: - prefixes |= PREFIX_ES; + s->override = R_ES; goto next_byte; case 0x64: - prefixes |= PREFIX_FS; + s->override = R_FS; goto next_byte; case 0x65: - prefixes |= PREFIX_GS; + s->override = R_GS; goto next_byte; case 0x66: prefixes |= PREFIX_DATA; @@ -1830,6 +1834,17 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } s->cc_op = CC_OP_SUBB + ot; break; + case 0x1c7: /* cmpxchg8b */ + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_cmpxchg8b(); + s->cc_op = CC_OP_EFLAGS; + break; /**************************/ /* push/pop */ @@ -2027,8 +2042,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) modrm = ldub(s->pc++); reg = (modrm >> 3) & 7; /* we must ensure that no segment is added */ - s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS | - PREFIX_ES | PREFIX_FS | PREFIX_GS); + s->override = -1; val = s->addseg; s->addseg = 0; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); @@ -2050,26 +2064,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) offset_addr = insn_get(s, OT_WORD); gen_op_movl_A0_im(offset_addr); /* handle override */ - /* XXX: factorize that */ { int override, must_add_seg; - override = R_DS; must_add_seg = s->addseg; - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { - if (s->prefix & PREFIX_ES) - override = R_ES; - else if (s->prefix & PREFIX_CS) - override = R_CS; - else if (s->prefix & PREFIX_SS) - override = R_SS; - else if (s->prefix & PREFIX_DS) - override = R_DS; - else if (s->prefix & PREFIX_FS) - override = R_FS; - else - override = R_GS; + if (s->override >= 0) { + override = s->override; must_add_seg = 1; + } else { + override = R_DS; } if (must_add_seg) { gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); @@ -2084,31 +2086,20 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0xd7: /* xlat */ - /* handle override */ gen_op_movl_A0_reg[R_EBX](); gen_op_addl_A0_AL(); if (s->aflag == 0) gen_op_andl_A0_ffff(); - /* XXX: factorize that */ + /* handle override */ { int override, must_add_seg; - override = R_DS; must_add_seg = s->addseg; - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { - if (s->prefix & PREFIX_ES) - override = R_ES; - else if (s->prefix & PREFIX_CS) - override = R_CS; - else if (s->prefix & PREFIX_SS) - override = R_SS; - else if (s->prefix & PREFIX_DS) - override = R_DS; - else if (s->prefix & PREFIX_FS) - override = R_FS; - else - override = R_GS; + override = R_DS; + if (s->override >= 0) { + override = s->override; must_add_seg = 1; + } else { + override = R_DS; } if (must_add_seg) { gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); @@ -2185,6 +2176,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[ot](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ @@ -2658,16 +2650,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; /************************/ /* string ops */ + case 0xa4: /* movsS */ case 0xa5: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { - gen_op_movs[3 + ot](); + gen_string_ds(s, ot, gen_op_movs + 9); } else { - gen_op_movs[ot](); + gen_string_ds(s, ot, gen_op_movs); } break; @@ -2677,10 +2671,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { - gen_op_stos[3 + ot](); + gen_string_es(s, ot, gen_op_stos + 9); } else { - gen_op_stos[ot](); + gen_string_es(s, ot, gen_op_stos); } break; case 0xac: /* lodsS */ @@ -2690,9 +2685,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPZ) { - gen_op_lods[3 + ot](); + gen_string_ds(s, ot, gen_op_lods + 9); } else { - gen_op_lods[ot](); + gen_string_ds(s, ot, gen_op_lods); } break; case 0xae: /* scasS */ @@ -2700,19 +2695,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPNZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_scas[6 + ot](); + gen_string_es(s, ot, gen_op_scas + 9 * 2); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_scas[3 + ot](); + gen_string_es(s, ot, gen_op_scas + 9); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { - gen_op_scas[ot](); + gen_string_es(s, ot, gen_op_scas); s->cc_op = CC_OP_SUBB + ot; } break; @@ -2726,21 +2721,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (prefixes & PREFIX_REPNZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_cmps[6 + ot](); + gen_string_ds(s, ot, gen_op_cmps + 9 * 2); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_cmps[3 + ot](); + gen_string_ds(s, ot, gen_op_cmps + 9); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { - gen_op_cmps[ot](); + gen_string_ds(s, ot, gen_op_cmps); s->cc_op = CC_OP_SUBB + ot; } break; - - /************************/ - /* port I/O */ case 0x6c: /* insS */ case 0x6d: if ((b & 1) == 0) @@ -2748,9 +2740,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPZ) { - gen_op_ins[3 + ot](); + gen_string_es(s, ot, gen_op_ins + 9); } else { - gen_op_ins[ot](); + gen_string_es(s, ot, gen_op_ins); } break; case 0x6e: /* outsS */ @@ -2760,11 +2752,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPZ) { - gen_op_outs[3 + ot](); + gen_string_ds(s, ot, gen_op_outs + 9); } else { - gen_op_outs[ot](); + gen_string_ds(s, ot, gen_op_outs); } break; + + /************************/ + /* port I/O */ case 0xe4: case 0xe5: if ((b & 1) == 0) @@ -3150,14 +3145,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xcd: /* int N */ val = ldub(s->pc++); /* XXX: currently we ignore the interrupt number */ - gen_op_int_im((long)pc_start); + gen_op_int_im(pc_start - s->cs_base); s->is_jmp = 1; break; case 0xce: /* into */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_into((long)pc_start, (long)s->pc); - s->is_jmp = 1; + gen_op_into(); + break; + case 0x62: /* bound */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + gen_op_mov_reg_T0[ot][reg](); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (ot == OT_WORD) + gen_op_boundw(); + else + gen_op_boundl(); break; case 0x1c8 ... 0x1cf: /* bswap reg */ reg = b & 7; @@ -3188,11 +3196,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x131: /* rdtsc */ gen_op_rdtsc(); break; -#if 0 case 0x1a2: /* cpuid */ - gen_insn0(OP_ASM); + gen_op_cpuid(); break; -#endif default: goto illegal_op; } @@ -3399,28 +3405,30 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, - [INDEX_op_scasb] = CC_OSZAPC, - [INDEX_op_scasw] = CC_OSZAPC, - [INDEX_op_scasl] = CC_OSZAPC, - [INDEX_op_repz_scasb] = CC_OSZAPC, - [INDEX_op_repz_scasw] = CC_OSZAPC, - [INDEX_op_repz_scasl] = CC_OSZAPC, - [INDEX_op_repnz_scasb] = CC_OSZAPC, - [INDEX_op_repnz_scasw] = CC_OSZAPC, - [INDEX_op_repnz_scasl] = CC_OSZAPC, - - [INDEX_op_cmpsb] = CC_OSZAPC, - [INDEX_op_cmpsw] = CC_OSZAPC, - [INDEX_op_cmpsl] = CC_OSZAPC, - [INDEX_op_repz_cmpsb] = CC_OSZAPC, - [INDEX_op_repz_cmpsw] = CC_OSZAPC, - [INDEX_op_repz_cmpsl] = CC_OSZAPC, - [INDEX_op_repnz_cmpsb] = CC_OSZAPC, - [INDEX_op_repnz_cmpsw] = CC_OSZAPC, - [INDEX_op_repnz_cmpsl] = CC_OSZAPC, - +#undef STRINGOP +#define STRINGOP(x) \ + [INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \ + [INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \ + [INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \ + [INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \ + [INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \ + [INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \ + [INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \ + [INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ + [INDEX_op_ ## x ## l_a16] = CC_OSZAPC, + + STRINGOP(scas) + STRINGOP(repz_scas) + STRINGOP(repnz_scas) + STRINGOP(cmps) + STRINGOP(repz_cmps) + STRINGOP(repnz_cmps) + + [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, + + [INDEX_op_cmpxchg8b] = CC_Z, }; /* 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) #ifdef DEBUG_DISAS static const char *op_str[] = { -#define DEF(s) #s, +#define DEF(s, n) #s, +#include "opc-i386.h" +#undef DEF +}; + +static uint8_t op_nb_args[] = { +#define DEF(s, n) n, #include "opc-i386.h" #undef DEF }; -static void dump_ops(const uint16_t *opc_buf) +static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) { const uint16_t *opc_ptr; - int c; + const uint32_t *opparam_ptr; + int c, n, i; + opc_ptr = opc_buf; + opparam_ptr = opparam_buf; for(;;) { c = *opc_ptr++; - fprintf(logfile, "0x%04x: %s\n", opc_ptr - opc_buf - 1, op_str[c]); + n = op_nb_args[c]; + fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]); + for(i = 0; i < n; i++) { + fprintf(logfile, " 0x%x", opparam_ptr[i]); + } + fprintf(logfile, "\n"); if (c == INDEX_op_end) break; + opparam_ptr += n; } } @@ -3547,6 +3570,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; + dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; @@ -3610,7 +3634,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, fprintf(logfile, "\n"); fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf); + dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); } #endif @@ -3621,7 +3645,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "AFTER FLAGS OPT:\n"); - dump_ops(gen_opc_buf); + dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); } #endif @@ -3683,8 +3707,8 @@ CPUX86State *cpu_x86_init(void) for(i = 0;i < 8; i++) env->fptags[i] = 1; env->fpuc = 0x37f; - /* flags setup */ - env->eflags = 0; + /* flags setup : we activate the IRQs by default as in user mode */ + env->eflags = 0x2 | IF_MASK; /* init various static tables */ if (!inited) { |