Commit 9c605cb1 authored by bellard's avatar bellard
Browse files

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
parent 24f9e90b
......@@ -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, &reg_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, &reg_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, &reg_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, &reg_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,