aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-06-21 13:13:13 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-06-21 13:13:13 +0000
commitd8bc1fd0aeb0423074b5063c8dc94dddd7285321 (patch)
tree8189ddc4d41910ff7e16191183fb4a909ddf41ed
parent7501267e2210788f548edd8adf1704731b235d3f (diff)
ring 0 ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--exec-i386.h5
-rw-r--r--helper-i386.c184
-rw-r--r--op-i386.c85
-rw-r--r--translate-i386.c246
4 files changed, 469 insertions, 51 deletions
diff --git a/exec-i386.h b/exec-i386.h
index a490f266e6..20bc8a25c0 100644
--- a/exec-i386.h
+++ b/exec-i386.h
@@ -123,6 +123,11 @@ typedef struct CCTable {
extern CCTable cc_table[];
void load_seg(int seg_reg, int selector, unsigned cur_eip);
+void jmp_seg(int selector, unsigned int new_eip);
+void helper_lldt_T0(void);
+void helper_ltr_T0(void);
+void helper_movl_crN_T0(int reg);
+void helper_movl_drN_T0(int reg);
void __hidden cpu_lock(void);
void __hidden cpu_unlock(void);
void raise_interrupt(int intno, int is_int, int error_code,
diff --git a/helper-i386.c b/helper-i386.c
index 1182be8ce7..66121ff966 100644
--- a/helper-i386.c
+++ b/helper-i386.c
@@ -157,7 +157,7 @@ void raise_interrupt(int intno, int is_int, int error_code,
break;
}
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->segs[R_CS] & 3;
+ cpl = env->segs[R_CS].selector & 3;
/* check privledge if software int */
if (is_int && dpl < cpl)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
@@ -176,7 +176,7 @@ void raise_interrupt(int intno, int is_int, int error_code,
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
{
- SegmentDescriptorTable *dt;
+ SegmentCache *dt;
uint8_t *ptr;
int dpl, cpl;
uint32_t e2;
@@ -331,21 +331,98 @@ void helper_cpuid(void)
}
}
+static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2)
+{
+ sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
+ sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
+ if (e2 & (1 << 23))
+ sc->limit = (sc->limit << 12) | 0xfff;
+ sc->seg_32bit = (e2 >> 22) & 1;
+}
+
+void helper_lldt_T0(void)
+{
+ int selector;
+ SegmentCache *dt;
+ uint32_t e1, e2;
+ int index;
+ uint8_t *ptr;
+
+ selector = T0 & 0xffff;
+ if ((selector & 0xfffc) == 0) {
+ /* XXX: NULL selector case: invalid LDT */
+ env->ldt.base = NULL;
+ env->ldt.limit = 0;
+ } else {
+ if (selector & 0x4)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ dt = &env->gdt;
+ index = selector & ~7;
+ if ((index + 7) > dt->limit)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ ptr = dt->base + index;
+ e1 = ldl(ptr);
+ e2 = ldl(ptr + 4);
+ if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+ load_seg_cache(&env->ldt, e1, e2);
+ }
+ env->ldt.selector = selector;
+}
+
+void helper_ltr_T0(void)
+{
+ int selector;
+ SegmentCache *dt;
+ uint32_t e1, e2;
+ int index, type;
+ uint8_t *ptr;
+
+ selector = T0 & 0xffff;
+ if ((selector & 0xfffc) == 0) {
+ /* XXX: NULL selector case: invalid LDT */
+ env->tr.base = NULL;
+ env->tr.limit = 0;
+ } else {
+ if (selector & 0x4)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ dt = &env->gdt;
+ index = selector & ~7;
+ if ((index + 7) > dt->limit)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ ptr = dt->base + index;
+ e1 = ldl(ptr);
+ e2 = ldl(ptr + 4);
+ type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+ if ((e2 & DESC_S_MASK) ||
+ (type != 2 && type != 9))
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+ load_seg_cache(&env->tr, e1, e2);
+ e2 |= 0x00000200; /* set the busy bit */
+ stl(ptr + 4, e2);
+ }
+ env->tr.selector = selector;
+}
+
/* only works if protected mode and not VM86 */
-void load_seg(int seg_reg, int selector, unsigned cur_eip)
+void load_seg(int seg_reg, int selector, unsigned int cur_eip)
{
SegmentCache *sc;
- SegmentDescriptorTable *dt;
+ SegmentCache *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
-
- sc = &env->seg_cache[seg_reg];
+
+ sc = &env->segs[seg_reg];
if ((selector & 0xfffc) == 0) {
/* null selector case */
if (seg_reg == R_SS) {
EIP = cur_eip;
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ raise_exception_err(EXCP0D_GPF, 0);
} else {
/* XXX: each access should trigger an exception */
sc->base = NULL;
@@ -390,18 +467,93 @@ void load_seg(int seg_reg, int selector, unsigned cur_eip)
else
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
}
-
- sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
- sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
- if (e2 & (1 << 23))
- sc->limit = (sc->limit << 12) | 0xfff;
- sc->seg_32bit = (e2 >> 22) & 1;
+ load_seg_cache(sc, e1, e2);
#if 0
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n",
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
#endif
}
- env->segs[seg_reg] = selector;
+ sc->selector = selector;
+}
+
+/* protected mode jump */
+void jmp_seg(int selector, unsigned int new_eip)
+{
+ SegmentCache sc1;
+ SegmentCache *dt;
+ int index;
+ uint32_t e1, e2, cpl, dpl, rpl;
+ uint8_t *ptr;
+
+ if ((selector & 0xfffc) == 0) {
+ raise_exception_err(EXCP0D_GPF, 0);
+ }
+
+ if (selector & 0x4)
+ dt = &env->ldt;
+ else
+ dt = &env->gdt;
+ index = selector & ~7;
+ if ((index + 7) > dt->limit)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ ptr = dt->base + index;
+ e1 = ldl(ptr);
+ e2 = ldl(ptr + 4);
+ cpl = env->segs[R_CS].selector & 3;
+ if (e2 & DESC_S_MASK) {
+ if (!(e2 & DESC_CS_MASK))
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ if (e2 & DESC_CS_MASK) {
+ /* conforming code segment */
+ if (dpl > cpl)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ } else {
+ /* non conforming code segment */
+ rpl = selector & 3;
+ if (rpl > cpl)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (dpl != cpl)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ }
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+ load_seg_cache(&sc1, e1, e2);
+ if (new_eip > sc1.limit)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ env->segs[R_CS] = sc1;
+ env->segs[R_CS].selector = (selector & 0xfffc) | cpl;
+ EIP = new_eip;
+ } else {
+ cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x",
+ selector, new_eip);
+ }
+}
+
+/* XXX: do more */
+void helper_movl_crN_T0(int reg)
+{
+ switch(reg) {
+ case 0:
+ default:
+ env->cr[0] = reg;
+ break;
+ case 2:
+ env->cr[2] = reg;
+ break;
+ case 3:
+ env->cr[3] = reg;
+ break;
+ case 4:
+ env->cr[4] = reg;
+ break;
+ }
+}
+
+/* XXX: do more */
+void helper_movl_drN_T0(int reg)
+{
+ env->dr[reg] = T0;
}
/* rdtsc */
@@ -425,7 +577,7 @@ void helper_rdtsc(void)
void helper_lsl(void)
{
unsigned int selector, limit;
- SegmentDescriptorTable *dt;
+ SegmentCache *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
@@ -452,7 +604,7 @@ void helper_lsl(void)
void helper_lar(void)
{
unsigned int selector;
- SegmentDescriptorTable *dt;
+ SegmentCache *dt;
int index;
uint32_t e2;
uint8_t *ptr;
diff --git a/op-i386.c b/op-i386.c
index c2f92638bd..5836b1a1c3 100644
--- a/op-i386.c
+++ b/op-i386.c
@@ -357,6 +357,11 @@ void OPPROTO op_andl_T0_ffff(void)
T0 = T0 & 0xffff;
}
+void OPPROTO op_andl_T0_im(void)
+{
+ T0 = T0 & PARAM1;
+}
+
void OPPROTO op_movl_T0_T1(void)
{
T0 = T1;
@@ -665,7 +670,7 @@ void op_pushl_ss32_T0(void)
{
uint32_t offset;
offset = ESP - 4;
- stl(env->seg_cache[R_SS].base + offset, T0);
+ stl(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = offset;
}
@@ -674,7 +679,7 @@ void op_pushw_ss32_T0(void)
{
uint32_t offset;
offset = ESP - 2;
- stw(env->seg_cache[R_SS].base + offset, T0);
+ stw(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = offset;
}
@@ -683,7 +688,7 @@ void op_pushl_ss16_T0(void)
{
uint32_t offset;
offset = (ESP - 4) & 0xffff;
- stl(env->seg_cache[R_SS].base + offset, T0);
+ stl(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = (ESP & ~0xffff) | offset;
}
@@ -692,7 +697,7 @@ void op_pushw_ss16_T0(void)
{
uint32_t offset;
offset = (ESP - 2) & 0xffff;
- stw(env->seg_cache[R_SS].base + offset, T0);
+ stw(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = (ESP & ~0xffff) | offset;
}
@@ -710,22 +715,22 @@ void op_popw_T0(void)
void op_popl_ss32_T0(void)
{
- T0 = ldl(env->seg_cache[R_SS].base + ESP);
+ T0 = ldl(env->segs[R_SS].base + ESP);
}
void op_popw_ss32_T0(void)
{
- T0 = lduw(env->seg_cache[R_SS].base + ESP);
+ T0 = lduw(env->segs[R_SS].base + ESP);
}
void op_popl_ss16_T0(void)
{
- T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff));
+ T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff));
}
void op_popw_ss16_T0(void)
{
- T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff));
+ T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff));
}
void op_addl_ESP_4(void)
@@ -909,17 +914,18 @@ void OPPROTO op_movl_seg_T0(void)
void OPPROTO op_movl_seg_T0_vm(void)
{
int selector;
+ SegmentCache *sc;
selector = T0 & 0xffff;
/* env->segs[] access */
- *(uint32_t *)((char *)env + PARAM1) = selector;
- /* env->seg_cache[] access */
- ((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4);
+ sc = (SegmentCache *)((char *)env + PARAM1);
+ sc->selector = selector;
+ sc->base = (void *)(selector << 4);
}
void OPPROTO op_movl_T0_seg(void)
{
- T0 = env->segs[PARAM1];
+ T0 = env->segs[PARAM1].selector;
}
void OPPROTO op_movl_A0_seg(void)
@@ -942,6 +948,61 @@ void OPPROTO op_lar(void)
helper_lar();
}
+/* T0: segment, T1:eip */
+void OPPROTO op_ljmp_T0_T1(void)
+{
+ jmp_seg(T0 & 0xffff, T1);
+}
+
+void OPPROTO op_lldt_T0(void)
+{
+ helper_lldt_T0();
+}
+
+void OPPROTO op_ltr_T0(void)
+{
+ helper_ltr_T0();
+}
+
+/* CR registers access */
+void OPPROTO op_movl_crN_T0(void)
+{
+ helper_movl_crN_T0(PARAM1);
+}
+
+/* DR registers access */
+void OPPROTO op_movl_drN_T0(void)
+{
+ helper_movl_drN_T0(PARAM1);
+}
+
+void OPPROTO op_lmsw_T0(void)
+{
+ /* only 4 lower bits of CR0 are modified */
+ T0 = (env->cr[0] & ~0xf) | (T0 & 0xf);
+ helper_movl_crN_T0(0);
+}
+
+void OPPROTO op_movl_T0_env(void)
+{
+ T0 = *(uint32_t *)((char *)env + PARAM1);
+}
+
+void OPPROTO op_movl_env_T0(void)
+{
+ *(uint32_t *)((char *)env + PARAM1) = T0;
+}
+
+void OPPROTO op_movl_env_T1(void)
+{
+ *(uint32_t *)((char *)env + PARAM1) = T1;
+}
+
+void OPPROTO op_clts(void)
+{
+ env->cr[0] &= ~CR0_TS_MASK;
+}
+
/* flags handling */
/* slow jumps cases : in order to avoid calling a function with a
diff --git a/translate-i386.c b/translate-i386.c
index eb31c6d10f..cfff1debeb 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -575,7 +575,7 @@ static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
if (s->addseg && override < 0)
override = R_DS;
if (override >= 0) {
- gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
+ gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
index = 3 + ot;
} else {
index = ot;
@@ -583,7 +583,7 @@ static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
} else {
if (override < 0)
override = R_DS;
- gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
+ gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
/* 16 address, always override */
index = 6 + ot;
}
@@ -878,7 +878,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
else
override = R_DS;
}
- gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
+ gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
} else {
switch (mod) {
@@ -944,7 +944,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
else
override = R_DS;
}
- gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
+ gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
}
@@ -1146,8 +1146,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
if (!s->vm86)
gen_op_movl_seg_T0(seg_reg, cur_eip);
else
- gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]),
- offsetof(CPUX86State,seg_cache[seg_reg].base));
+ gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]));
if (!s->addseg && seg_reg < R_FS)
s->is_jmp = 2; /* abort translation because the register may
have a non zero base */
@@ -1230,7 +1229,7 @@ static void gen_stack_A0(DisasContext *s)
gen_op_andl_A0_ffff();
gen_op_movl_T1_A0();
if (s->addseg)
- gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
+ gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
}
/* NOTE: wrap around in 16 bit not fully handled */
@@ -1243,7 +1242,7 @@ static void gen_pusha(DisasContext *s)
gen_op_andl_A0_ffff();
gen_op_movl_T1_A0();
if (s->addseg)
- gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
+ gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
for(i = 0;i < 8; i++) {
gen_op_mov_TN_reg[OT_LONG][0][7 - i]();
gen_op_st_T0_A0[OT_WORD + s->dflag]();
@@ -1262,7 +1261,7 @@ static void gen_popa(DisasContext *s)
gen_op_movl_T1_A0();
gen_op_addl_T1_im(16 << s->dflag);
if (s->addseg)
- gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
+ gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
for(i = 0;i < 8; i++) {
/* ESP is not reloaded */
if (i != 3) {
@@ -1291,7 +1290,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
gen_op_andl_A0_ffff();
gen_op_movl_T1_A0();
if (s->addseg)
- gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
+ gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
/* push bp */
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
gen_op_st_T0_A0[ot]();
@@ -1714,9 +1713,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_ld_T1_A0[ot]();
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
gen_op_lduw_T0_A0();
- gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
- gen_op_movl_T0_T1();
- gen_op_jmp_T0();
+ if (!s->vm86) {
+ /* we compute EIP to handle the exception case */
+ gen_op_jmp_im(pc_start - s->cs_base);
+ gen_op_ljmp_T0_T1();
+ } else {
+ gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
+ gen_op_movl_T0_T1();
+ gen_op_jmp_T0();
+ }
s->is_jmp = 1;
break;
case 6: /* push Ev */
@@ -2085,7 +2090,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
override = R_DS;
}
if (must_add_seg) {
- gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
+ gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
}
if ((b & 2) == 0) {
@@ -2113,7 +2118,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
override = R_DS;
}
if (must_add_seg) {
- gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
+ gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
}
gen_op_ldub_T0_A0();
@@ -2619,12 +2624,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
break;
case 0x1c:
switch(rm) {
+ case 0: /* feni (287 only, just do nop here) */
+ break;
+ case 1: /* fdisi (287 only, just do nop here) */
+ break;
case 2: /* fclex */
gen_op_fclex();
break;
case 3: /* fninit */
gen_op_fninit();
break;
+ case 4: /* fsetpm (287 only, just do nop here) */
+ break;
default:
goto illegal_op;
}
@@ -3011,8 +3022,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
/* change cs and pc */
gen_op_movl_T0_im(selector);
- gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
- gen_op_jmp_im((unsigned long)offset);
+ if (!s->vm86) {
+ /* we compute EIP to handle the exception case */
+ gen_op_jmp_im(pc_start - s->cs_base);
+ gen_op_movl_T1_im(offset);
+ gen_op_ljmp_T0_T1();
+ } else {
+ gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
+ gen_op_jmp_im((unsigned long)offset);
+ }
s->is_jmp = 1;
}
break;
@@ -3343,6 +3361,111 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
/* XXX: if cpl == 0, then should do something else */
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break;
+ case 0x100:
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ op = (modrm >> 3) & 7;
+ switch(op) {
+ case 0: /* sldt */
+ gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
+ ot = OT_WORD;
+ if (mod == 3)
+ ot += s->dflag;
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+ break;
+ case 2: /* lldt */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+ gen_op_jmp_im(pc_start - s->cs_base);
+ gen_op_lldt_T0();
+ }
+ break;
+ case 1: /* str */
+ gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
+ ot = OT_WORD;
+ if (mod == 3)
+ ot += s->dflag;
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+ break;
+ case 3: /* ltr */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+ gen_op_jmp_im(pc_start - s->cs_base);
+ gen_op_ltr_T0();
+ }
+ break;
+ case 4: /* verr */
+ case 5: /* verw */
+ default:
+ goto illegal_op;
+ }
+ break;
+ case 0x101:
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ op = (modrm >> 3) & 7;
+ switch(op) {
+ case 0: /* sgdt */
+ case 1: /* sidt */
+ if (mod == 3)
+ goto illegal_op;
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ if (op == 0)
+ gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit));
+ else
+ gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit));
+ gen_op_stw_T0_A0();
+ gen_op_addl_A0_im(2);
+ if (op == 0)
+ gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base));
+ else
+ gen_op_movl_T0_env(offsetof(CPUX86State,idt.base));
+ if (!s->dflag)
+ gen_op_andl_T0_im(0xffffff);
+ gen_op_stl_T0_A0();
+ break;
+ case 2: /* lgdt */
+ case 3: /* lidt */
+ if (mod == 3)
+ goto illegal_op;
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_lduw_T1_A0();
+ gen_op_addl_A0_im(2);
+ gen_op_ldl_T0_A0();
+ if (!s->dflag)
+ gen_op_andl_T0_im(0xffffff);
+ if (op == 2) {
+ gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base));
+ gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit));
+ } else {
+ gen_op_movl_env_T0(offsetof(CPUX86State,idt.base));
+ gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit));
+ }
+ }
+ break;
+ case 4: /* smsw */
+ gen_op_movl_T0_env(offsetof(CPUX86State,cr[0]));
+ gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1);
+ break;
+ case 6: /* lmsw */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+ gen_op_lmsw_T0();
+ }
+ break;
+ default:
+ goto illegal_op;
+ }
+ break;
case 0x102: /* lar */
case 0x103: /* lsl */
if (s->vm86)
@@ -3361,6 +3484,83 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
s->cc_op = CC_OP_EFLAGS;
gen_op_mov_reg_T1[ot][reg]();
break;
+ case 0x118:
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ op = (modrm >> 3) & 7;
+ switch(op) {
+ case 0: /* prefetchnta */
+ case 1: /* prefetchnt0 */
+ case 2: /* prefetchnt0 */
+ case 3: /* prefetchnt0 */
+ if (mod == 3)
+ goto illegal_op;
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ /* nothing more to do */
+ break;
+ default:
+ goto illegal_op;
+ }
+ break;
+ case 0x120: /* mov reg, crN */
+ case 0x122: /* mov crN, reg */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ modrm = ldub(s->pc++);
+ if ((modrm & 0xc0) != 0xc0)
+ goto illegal_op;
+ rm = modrm & 7;
+ reg = (modrm >> 3) & 7;
+ switch(reg) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ if (b & 2) {
+ gen_op_mov_TN_reg[OT_LONG][0][rm]();
+ gen_op_movl_crN_T0(reg);
+ s->is_jmp = 2;
+ } else {
+ gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg]));
+ gen_op_mov_reg_T0[OT_LONG][rm]();
+ }
+ break;
+ default:
+ goto illegal_op;
+ }
+ }
+ break;
+ case 0x121: /* mov reg, drN */
+ case 0x123: /* mov drN, reg */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ modrm = ldub(s->pc++);
+ if ((modrm & 0xc0) != 0xc0)
+ goto illegal_op;
+ rm = modrm & 7;
+ reg = (modrm >> 3) & 7;
+ /* XXX: do it dynamically with CR4.DE bit */
+ if (reg == 4 || reg == 5)
+ goto illegal_op;
+ if (b & 2) {
+ gen_op_mov_TN_reg[OT_LONG][0][rm]();
+ gen_op_movl_drN_T0(reg);
+ s->is_jmp = 2;
+ } else {
+ gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg]));
+ gen_op_mov_reg_T0[OT_LONG][rm]();
+ }
+ }
+ break;
+ case 0x106: /* clts */
+ if (s->cpl != 0) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ gen_op_clts();
+ }
+ break;
default:
goto illegal_op;
}
@@ -3859,12 +4059,12 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
eflags & CC_P ? 'P' : '-',
eflags & CC_C ? 'C' : '-');
fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
- env->segs[R_CS],
- env->segs[R_SS],
- env->segs[R_DS],
- env->segs[R_ES],
- env->segs[R_FS],
- env->segs[R_GS]);
+ env->segs[R_CS].selector,
+ env->segs[R_SS].selector,
+ env->segs[R_DS].selector,
+ env->segs[R_ES].selector,
+ env->segs[R_FS].selector,
+ env->segs[R_GS].selector);
if (flags & X86_DUMP_CCOP) {
if ((unsigned)env->cc_op < CC_OP_NB)
strcpy(cc_op_name, cc_op_str[env->cc_op]);