]> git.proxmox.com Git - mirror_qemu.git/commitdiff
ring 0 ops
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 21 Jun 2003 13:13:13 +0000 (13:13 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 21 Jun 2003 13:13:13 +0000 (13:13 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162

exec-i386.h
helper-i386.c
op-i386.c
translate-i386.c

index a490f266e6a8041c1d02c8af95041999d54c7d27..20bc8a25c0a01f2cbc706b3d4ee065e31bd5e5c1 100644 (file)
@@ -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, 
index 1182be8ce729695fa62264b919e7ae76b42e9741..66121ff9667ce7e3f78e40fa1a8e0eae7b0ed86e 100644 (file)
@@ -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;
index c2f92638bdc8791ab7c3c139700f4f4a55b4b37e..5836b1a1c30b10398fcba4791097b6d06699124c 100644 (file)
--- 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
index eb31c6d10f2ced84bd8ca3ecd5b9f7a19b8f3287..cfff1debeb5513b2056cbc30b91c81ac7810933d 100644 (file)
@@ -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]);