From d8bc1fd0aeb0423074b5063c8dc94dddd7285321 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Jun 2003 13:13:13 +0000 Subject: [PATCH] ring 0 ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.h | 5 + helper-i386.c | 184 ++++++++++++++++++++++++++++++++--- op-i386.c | 85 +++++++++++++--- translate-i386.c | 246 ++++++++++++++++++++++++++++++++++++++++++----- 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, ®_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, ®_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, ®_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]);