]> git.proxmox.com Git - qemu.git/blobdiff - target-i386/translate.c
monitor fixes
[qemu.git] / target-i386 / translate.c
index 7ce8f4bdee8c32986c761c8992e27ba5e6619461..bd2a61b0e57a2d9f94d7866df1941556bb932835 100644 (file)
@@ -24,7 +24,6 @@
 #include <inttypes.h>
 #include <signal.h>
 #include <assert.h>
-#include <sys/mman.h>
 
 #include "cpu.h"
 #include "exec-all.h"
@@ -63,6 +62,7 @@ typedef struct DisasContext {
     int singlestep_enabled; /* "hardware" single step enabled */
     int jmp_opt; /* use direct block chaining for direct jumps */
     int mem_index; /* select memory access functions */
+    int flags; /* all execution flags */
     struct TranslationBlock *tb;
     int popl_esp_hack; /* for correct popl with esp base handling */
 } DisasContext;
@@ -128,11 +128,6 @@ enum {
     NB_OREGS,
 };
 
-typedef void (GenOpFunc)(void);
-typedef void (GenOpFunc1)(long);
-typedef void (GenOpFunc2)(long, long);
-typedef void (GenOpFunc3)(long, long, long);
-                    
 static GenOpFunc *gen_op_mov_reg_T0[3][8] = {
     [OT_BYTE] = {
         gen_op_movb_EAX_T0,
@@ -380,34 +375,30 @@ static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
     NULL,
 };
 
-static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
-    [OT_BYTE] = {
-        gen_op_adcb_T0_T1_cc,
-        gen_op_sbbb_T0_T1_cc,
-    },
-    [OT_WORD] = {
-        gen_op_adcw_T0_T1_cc,
-        gen_op_sbbw_T0_T1_cc,
-    },
-    [OT_LONG] = {
-        gen_op_adcl_T0_T1_cc,
-        gen_op_sbbl_T0_T1_cc,
+#define DEF_ARITHC(SUFFIX)\
+    {\
+        gen_op_adcb ## SUFFIX ## _T0_T1_cc,\
+        gen_op_sbbb ## SUFFIX ## _T0_T1_cc,\
+    },\
+    {\
+        gen_op_adcw ## SUFFIX ## _T0_T1_cc,\
+        gen_op_sbbw ## SUFFIX ## _T0_T1_cc,\
+    },\
+    {\
+        gen_op_adcl ## SUFFIX ## _T0_T1_cc,\
+        gen_op_sbbl ## SUFFIX ## _T0_T1_cc,\
     },
+
+static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
+    DEF_ARITHC( )
 };
 
-static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = {
-    [OT_BYTE] = {
-        gen_op_adcb_mem_T0_T1_cc,
-        gen_op_sbbb_mem_T0_T1_cc,
-    },
-    [OT_WORD] = {
-        gen_op_adcw_mem_T0_T1_cc,
-        gen_op_sbbw_mem_T0_T1_cc,
-    },
-    [OT_LONG] = {
-        gen_op_adcl_mem_T0_T1_cc,
-        gen_op_sbbl_mem_T0_T1_cc,
-    },
+static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[9][2] = {
+    DEF_ARITHC(_raw)
+#ifndef CONFIG_USER_ONLY
+    DEF_ARITHC(_kernel)
+    DEF_ARITHC(_user)
+#endif
 };
 
 static const int cc_op_arithb[8] = {
@@ -421,126 +412,105 @@ static const int cc_op_arithb[8] = {
     CC_OP_SUBB,
 };
 
+#define DEF_CMPXCHG(SUFFIX)\
+    gen_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc,\
+    gen_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc,\
+    gen_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc,
+
+
 static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = {
-    gen_op_cmpxchgb_T0_T1_EAX_cc,
-    gen_op_cmpxchgw_T0_T1_EAX_cc,
-    gen_op_cmpxchgl_T0_T1_EAX_cc,
+    DEF_CMPXCHG( )
 };
 
-static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = {
-    gen_op_cmpxchgb_mem_T0_T1_EAX_cc,
-    gen_op_cmpxchgw_mem_T0_T1_EAX_cc,
-    gen_op_cmpxchgl_mem_T0_T1_EAX_cc,
+static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = {
+    DEF_CMPXCHG(_raw)
+#ifndef CONFIG_USER_ONLY
+    DEF_CMPXCHG(_kernel)
+    DEF_CMPXCHG(_user)
+#endif
 };
 
-static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
-    [OT_BYTE] = {
-        gen_op_rolb_T0_T1_cc,
-        gen_op_rorb_T0_T1_cc,
-        gen_op_rclb_T0_T1_cc,
-        gen_op_rcrb_T0_T1_cc,
-        gen_op_shlb_T0_T1_cc,
-        gen_op_shrb_T0_T1_cc,
-        gen_op_shlb_T0_T1_cc,
-        gen_op_sarb_T0_T1_cc,
-    },
-    [OT_WORD] = {
-        gen_op_rolw_T0_T1_cc,
-        gen_op_rorw_T0_T1_cc,
-        gen_op_rclw_T0_T1_cc,
-        gen_op_rcrw_T0_T1_cc,
-        gen_op_shlw_T0_T1_cc,
-        gen_op_shrw_T0_T1_cc,
-        gen_op_shlw_T0_T1_cc,
-        gen_op_sarw_T0_T1_cc,
-    },
-    [OT_LONG] = {
-        gen_op_roll_T0_T1_cc,
-        gen_op_rorl_T0_T1_cc,
-        gen_op_rcll_T0_T1_cc,
-        gen_op_rcrl_T0_T1_cc,
-        gen_op_shll_T0_T1_cc,
-        gen_op_shrl_T0_T1_cc,
-        gen_op_shll_T0_T1_cc,
-        gen_op_sarl_T0_T1_cc,
+#define DEF_SHIFT(SUFFIX)\
+    {\
+        gen_op_rolb ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rorb ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rclb ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rcrb ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shlb ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shrb ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shlb ## SUFFIX ## _T0_T1_cc,\
+        gen_op_sarb ## SUFFIX ## _T0_T1_cc,\
+    },\
+    {\
+        gen_op_rolw ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rorw ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rclw ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rcrw ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shlw ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shrw ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shlw ## SUFFIX ## _T0_T1_cc,\
+        gen_op_sarw ## SUFFIX ## _T0_T1_cc,\
+    },\
+    {\
+        gen_op_roll ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rorl ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rcll ## SUFFIX ## _T0_T1_cc,\
+        gen_op_rcrl ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shll ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shrl ## SUFFIX ## _T0_T1_cc,\
+        gen_op_shll ## SUFFIX ## _T0_T1_cc,\
+        gen_op_sarl ## SUFFIX ## _T0_T1_cc,\
     },
+
+static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
+    DEF_SHIFT( )
 };
 
-static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = {
-    [OT_BYTE] = {
-        gen_op_rolb_mem_T0_T1_cc,
-        gen_op_rorb_mem_T0_T1_cc,
-        gen_op_rclb_mem_T0_T1_cc,
-        gen_op_rcrb_mem_T0_T1_cc,
-        gen_op_shlb_mem_T0_T1_cc,
-        gen_op_shrb_mem_T0_T1_cc,
-        gen_op_shlb_mem_T0_T1_cc,
-        gen_op_sarb_mem_T0_T1_cc,
-    },
-    [OT_WORD] = {
-        gen_op_rolw_mem_T0_T1_cc,
-        gen_op_rorw_mem_T0_T1_cc,
-        gen_op_rclw_mem_T0_T1_cc,
-        gen_op_rcrw_mem_T0_T1_cc,
-        gen_op_shlw_mem_T0_T1_cc,
-        gen_op_shrw_mem_T0_T1_cc,
-        gen_op_shlw_mem_T0_T1_cc,
-        gen_op_sarw_mem_T0_T1_cc,
-    },
-    [OT_LONG] = {
-        gen_op_roll_mem_T0_T1_cc,
-        gen_op_rorl_mem_T0_T1_cc,
-        gen_op_rcll_mem_T0_T1_cc,
-        gen_op_rcrl_mem_T0_T1_cc,
-        gen_op_shll_mem_T0_T1_cc,
-        gen_op_shrl_mem_T0_T1_cc,
-        gen_op_shll_mem_T0_T1_cc,
-        gen_op_sarl_mem_T0_T1_cc,
-    },
+static GenOpFunc *gen_op_shift_mem_T0_T1_cc[9][8] = {
+    DEF_SHIFT(_raw)
+#ifndef CONFIG_USER_ONLY
+    DEF_SHIFT(_kernel)
+    DEF_SHIFT(_user)
+#endif
 };
 
-static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = {
-    [0] = {
-        gen_op_shldw_T0_T1_im_cc,
-        gen_op_shrdw_T0_T1_im_cc,
-    },
-    [1] = {
-        gen_op_shldl_T0_T1_im_cc,
-        gen_op_shrdl_T0_T1_im_cc,
+#define DEF_SHIFTD(SUFFIX, op)\
+    {\
+        NULL,\
+        NULL,\
+    },\
+    {\
+        gen_op_shldw ## SUFFIX ## _T0_T1_ ## op ## _cc,\
+        gen_op_shrdw ## SUFFIX ## _T0_T1_ ## op ## _cc,\
+    },\
+    {\
+        gen_op_shldl ## SUFFIX ## _T0_T1_ ## op ## _cc,\
+        gen_op_shrdl ## SUFFIX ## _T0_T1_ ## op ## _cc,\
     },
+
+
+static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[3][2] = {
+    DEF_SHIFTD(, im)
 };
 
-static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = {
-    [0] = {
-        gen_op_shldw_T0_T1_ECX_cc,
-        gen_op_shrdw_T0_T1_ECX_cc,
-    },
-    [1] = {
-        gen_op_shldl_T0_T1_ECX_cc,
-        gen_op_shrdl_T0_T1_ECX_cc,
-    },
+static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[3][2] = {
+    DEF_SHIFTD(, ECX)
 };
 
-static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = {
-    [0] = {
-        gen_op_shldw_mem_T0_T1_im_cc,
-        gen_op_shrdw_mem_T0_T1_im_cc,
-    },
-    [1] = {
-        gen_op_shldl_mem_T0_T1_im_cc,
-        gen_op_shrdl_mem_T0_T1_im_cc,
-    },
+static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[9][2] = {
+    DEF_SHIFTD(_raw, im)
+#ifndef CONFIG_USER_ONLY
+    DEF_SHIFTD(_kernel, im)
+    DEF_SHIFTD(_user, im)
+#endif
 };
 
-static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = {
-    [0] = {
-        gen_op_shldw_mem_T0_T1_ECX_cc,
-        gen_op_shrdw_mem_T0_T1_ECX_cc,
-    },
-    [1] = {
-        gen_op_shldl_mem_T0_T1_ECX_cc,
-        gen_op_shrdl_mem_T0_T1_ECX_cc,
-    },
+static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[9][2] = {
+    DEF_SHIFTD(_raw, ECX)
+#ifndef CONFIG_USER_ONLY
+    DEF_SHIFTD(_kernel, ECX)
+    DEF_SHIFTD(_user, ECX)
+#endif
 };
 
 static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = {
@@ -649,6 +619,22 @@ static GenOpFunc *gen_op_st_T0_A0[3 * 3] = {
 #endif
 };
 
+static GenOpFunc *gen_op_st_T1_A0[3 * 3] = {
+    NULL,
+    gen_op_stw_raw_T1_A0,
+    gen_op_stl_raw_T1_A0,
+
+#ifndef CONFIG_USER_ONLY
+    NULL,
+    gen_op_stw_kernel_T1_A0,
+    gen_op_stl_kernel_T1_A0,
+
+    NULL,
+    gen_op_stw_user_T1_A0,
+    gen_op_stl_user_T1_A0,
+#endif
+};
+
 static inline void gen_string_movl_A0_ESI(DisasContext *s)
 {
     int override;
@@ -711,7 +697,15 @@ static GenOpFunc *gen_op_dec_ECX[2] = {
     gen_op_decl_ECX,
 };
 
-static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = {
+#ifdef USE_DIRECT_JUMP
+typedef GenOpFunc GenOpFuncTB2;
+#define gen_op_string_jnz_sub(nz, ot, tb) gen_op_string_jnz_sub2[nz][ot]()
+#else
+typedef GenOpFunc1 GenOpFuncTB2;
+#define gen_op_string_jnz_sub(nz, ot, tb) gen_op_string_jnz_sub2[nz][ot](tb)
+#endif
+
+static GenOpFuncTB2 *gen_op_string_jnz_sub2[2][3] = {
     {
         gen_op_string_jnz_subb,
         gen_op_string_jnz_subw,
@@ -935,7 +929,7 @@ static inline void gen_repz_ ## op(DisasContext *s, int ot,                   \
     if (!s->jmp_opt)                                                          \
         gen_op_string_jnz_sub_im[nz][ot](next_eip);                           \
     else                                                                      \
-        gen_op_string_jnz_sub[nz][ot]((long)s->tb);                           \
+        gen_op_string_jnz_sub(nz, ot, (long)s->tb);                           \
     if (!s->jmp_opt)                                                          \
         gen_op_jz_ecx_im[s->aflag](next_eip);                                 \
     gen_jmp(s, cur_eip);                                                      \
@@ -1093,7 +1087,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d)
             gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
             gen_op_mov_reg_T0[ot][d]();
         } else {
-            gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL]();
+            gen_op_arithc_mem_T0_T1_cc[ot + s1->mem_index][op - OP_ADCL]();
         }
         s1->cc_op = CC_OP_DYNAMIC;
         goto the_end;
@@ -1172,7 +1166,7 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
     if (d != OR_TMP0)
         gen_op_shift_T0_T1_cc[ot][op]();
     else
-        gen_op_shift_mem_T0_T1_cc[ot][op]();
+        gen_op_shift_mem_T0_T1_cc[ot + s1->mem_index][op]();
     if (d != OR_TMP0)
         gen_op_mov_reg_T0[ot][d]();
     s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
@@ -1538,81 +1532,106 @@ static void gen_setcc(DisasContext *s, int b)
    call this function with seg_reg == R_CS */
 static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
 {
-    if (s->pe && !s->vm86)
-        gen_op_movl_seg_T0(seg_reg, cur_eip);
-    else
+    if (s->pe && !s->vm86) {
+        /* XXX: optimize by finding processor state dynamically */
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_op_jmp_im(cur_eip);
+        gen_op_movl_seg_T0(seg_reg);
+        /* abort translation because the addseg value may change or
+           because ss32 may change. For R_SS, translation must always
+           stop as a special handling must be done to disable hardware
+           interrupts for the next instruction */
+        if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
+            s->is_jmp = 3;
+    } else {
         gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]));
-    /* abort translation because the register may have a non zero base
-       or because ss32 may change. For R_SS, translation must always
-       stop as a special handling must be done to disable hardware
-       interrupts for the next instruction */
-    if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS))
-        s->is_jmp = 3;
+        if (seg_reg == R_SS)
+            s->is_jmp = 3;
+    }
+}
+
+static inline void gen_stack_update(DisasContext *s, int addend)
+{
+    if (s->ss32) {
+        if (addend == 2)
+            gen_op_addl_ESP_2();
+        else if (addend == 4)
+            gen_op_addl_ESP_4();
+        else 
+            gen_op_addl_ESP_im(addend);
+    } else {
+        if (addend == 2)
+            gen_op_addw_ESP_2();
+        else if (addend == 4)
+            gen_op_addw_ESP_4();
+        else
+            gen_op_addw_ESP_im(addend);
+    }
 }
 
 /* generate a push. It depends on ss32, addseg and dflag */
 static void gen_push_T0(DisasContext *s)
 {
+    gen_op_movl_A0_reg[R_ESP]();
+    if (!s->dflag)
+        gen_op_subl_A0_2();
+    else
+        gen_op_subl_A0_4();
     if (s->ss32) {
-        if (!s->addseg) {
-            if (s->dflag)
-                gen_op_pushl_T0();
-            else
-                gen_op_pushw_T0();
-        } else {
-            if (s->dflag)
-                gen_op_pushl_ss32_T0();
-            else
-                gen_op_pushw_ss32_T0();
+        if (s->addseg) {
+            gen_op_movl_T1_A0();
+            gen_op_addl_A0_SS();
         }
     } else {
-        if (s->dflag)
-            gen_op_pushl_ss16_T0();
-        else
-            gen_op_pushw_ss16_T0();
+        gen_op_andl_A0_ffff();
+        gen_op_movl_T1_A0();
+        gen_op_addl_A0_SS();
     }
+    gen_op_st_T0_A0[s->dflag + 1 + s->mem_index]();
+    if (s->ss32 && !s->addseg)
+        gen_op_movl_ESP_A0();
+    else
+        gen_op_mov_reg_T1[s->ss32 + 1][R_ESP]();
 }
 
-/* two step pop is necessary for precise exceptions */
-static void gen_pop_T0(DisasContext *s)
+/* generate a push. It depends on ss32, addseg and dflag */
+/* slower version for T1, only used for call Ev */
+static void gen_push_T1(DisasContext *s)
 {
+    gen_op_movl_A0_reg[R_ESP]();
+    if (!s->dflag)
+        gen_op_subl_A0_2();
+    else
+        gen_op_subl_A0_4();
     if (s->ss32) {
-        if (!s->addseg) {
-            if (s->dflag)
-                gen_op_popl_T0();
-            else
-                gen_op_popw_T0();
-        } else {
-            if (s->dflag)
-                gen_op_popl_ss32_T0();
-            else
-                gen_op_popw_ss32_T0();
+        if (s->addseg) {
+            gen_op_addl_A0_SS();
         }
     } else {
-        if (s->dflag)
-            gen_op_popl_ss16_T0();
-        else
-            gen_op_popw_ss16_T0();
+        gen_op_andl_A0_ffff();
+        gen_op_addl_A0_SS();
     }
+    gen_op_st_T1_A0[s->dflag + 1 + s->mem_index]();
+    
+    if (s->ss32 && !s->addseg)
+        gen_op_movl_ESP_A0();
+    else
+        gen_stack_update(s, (-2) << s->dflag);
 }
 
-static inline void gen_stack_update(DisasContext *s, int addend)
+/* two step pop is necessary for precise exceptions */
+static void gen_pop_T0(DisasContext *s)
 {
+    gen_op_movl_A0_reg[R_ESP]();
     if (s->ss32) {
-        if (addend == 2)
-            gen_op_addl_ESP_2();
-        else if (addend == 4)
-            gen_op_addl_ESP_4();
-        else 
-            gen_op_addl_ESP_im(addend);
+        if (s->addseg)
+            gen_op_addl_A0_SS();
     } else {
-        if (addend == 2)
-            gen_op_addw_ESP_2();
-        else if (addend == 4)
-            gen_op_addw_ESP_4();
-        else
-            gen_op_addw_ESP_im(addend);
+        gen_op_andl_A0_ffff();
+        gen_op_addl_A0_SS();
     }
+    gen_op_ld_T0_A0[s->dflag + 1 + s->mem_index]();
 }
 
 static void gen_pop_update(DisasContext *s)
@@ -1699,9 +1718,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
             gen_op_st_T0_A0[ot + s->mem_index]();
         }
         gen_op_addl_A0_im(-opsize);
-        /* XXX: add st_T1_A0 ? */
-        gen_op_movl_T0_T1();
-        gen_op_st_T0_A0[ot + s->mem_index]();
+        gen_op_st_T1_A0[ot + s->mem_index]();
     }
     gen_op_mov_reg_T1[ot][R_EBP]();
     addend = -esp_addend;
@@ -1747,6 +1764,9 @@ static void gen_eob(DisasContext *s)
 {
     if (s->cc_op != CC_OP_DYNAMIC)
         gen_op_set_cc_op(s->cc_op);
+    if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
+        gen_op_reset_inhibit_irq();
+    }
     if (s->singlestep_enabled) {
         gen_op_debug();
     } else if (s->tf) {
@@ -1920,6 +1940,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
 
     case 0x80: /* GRP1 */
     case 0x81:
+    case 0x82:
     case 0x83:
         {
             int val;
@@ -1945,6 +1966,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             default:
             case 0x80:
             case 0x81:
+            case 0x82:
                 val = insn_get(s, ot);
                 break;
             case 0x83:
@@ -2013,31 +2035,35 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             switch(ot) {
             case OT_BYTE:
                 gen_op_mulb_AL_T0();
+                s->cc_op = CC_OP_MULB;
                 break;
             case OT_WORD:
                 gen_op_mulw_AX_T0();
+                s->cc_op = CC_OP_MULW;
                 break;
             default:
             case OT_LONG:
                 gen_op_mull_EAX_T0();
+                s->cc_op = CC_OP_MULL;
                 break;
             }
-            s->cc_op = CC_OP_MUL;
             break;
         case 5: /* imul */
             switch(ot) {
             case OT_BYTE:
                 gen_op_imulb_AL_T0();
+                s->cc_op = CC_OP_MULB;
                 break;
             case OT_WORD:
                 gen_op_imulw_AX_T0();
+                s->cc_op = CC_OP_MULW;
                 break;
             default:
             case OT_LONG:
                 gen_op_imull_EAX_T0();
+                s->cc_op = CC_OP_MULL;
                 break;
             }
-            s->cc_op = CC_OP_MUL;
             break;
         case 6: /* div */
             switch(ot) {
@@ -2110,13 +2136,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             gen_inc(s, ot, opreg, -1);
             break;
         case 2: /* call Ev */
-            /* XXX: optimize if memory (no and is necessary) */
+            /* XXX: optimize if memory (no 'and' is necessary) */
             if (s->dflag == 0)
                 gen_op_andl_T0_ffff();
-            gen_op_jmp_T0();
             next_eip = s->pc - s->cs_base;
-            gen_op_movl_T0_im(next_eip);
-            gen_push_T0(s);
+            gen_op_movl_T1_im(next_eip);
+            gen_push_T1(s);
+            gen_op_jmp_T0();
             gen_eob(s);
             break;
         case 3: /* lcall Ev */
@@ -2149,7 +2175,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
                 if (s->cc_op != CC_OP_DYNAMIC)
                     gen_op_set_cc_op(s->cc_op);
                 gen_op_jmp_im(pc_start - s->cs_base);
-                gen_op_ljmp_protected_T0_T1();
+                gen_op_ljmp_protected_T0_T1(s->pc - s->cs_base);
             } else {
                 gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
                 gen_op_movl_T0_T1();
@@ -2220,7 +2246,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             val = insn_get(s, ot);
             gen_op_movl_T1_im(val);
         } else if (b == 0x6b) {
-            val = insn_get(s, OT_BYTE);
+            val = (int8_t)insn_get(s, OT_BYTE);
             gen_op_movl_T1_im(val);
         } else {
             gen_op_mov_TN_reg[ot][1][reg]();
@@ -2232,7 +2258,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             gen_op_imulw_T0_T1();
         }
         gen_op_mov_reg_T0[ot][reg]();
-        s->cc_op = CC_OP_MUL;
+        s->cc_op = CC_OP_MULB + ot;
         break;
     case 0x1c0:
     case 0x1c1: /* xadd Ev, Gv */
@@ -2248,8 +2274,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             gen_op_mov_TN_reg[ot][0][reg]();
             gen_op_mov_TN_reg[ot][1][rm]();
             gen_op_addl_T0_T1();
-            gen_op_mov_reg_T0[ot][rm]();
             gen_op_mov_reg_T1[ot][reg]();
+            gen_op_mov_reg_T0[ot][rm]();
         } else {
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
             gen_op_mov_TN_reg[ot][0][reg]();
@@ -2279,7 +2305,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         } else {
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
             gen_op_ld_T0_A0[ot + s->mem_index]();
-            gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot]();
+            gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot + s->mem_index]();
         }
         s->cc_op = CC_OP_SUBB + ot;
         break;
@@ -2304,8 +2330,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0x58 ... 0x5f: /* pop */
         ot = dflag ? OT_LONG : OT_WORD;
         gen_pop_T0(s);
-        gen_op_mov_reg_T0[ot][b & 7]();
+        /* NOTE: order is important for pop %sp */
         gen_pop_update(s);
+        gen_op_mov_reg_T0[ot][b & 7]();
         break;
     case 0x60: /* pusha */
         gen_pusha(s);
@@ -2326,11 +2353,20 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0x8f: /* pop Ev */
         ot = dflag ? OT_LONG : OT_WORD;
         modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
         gen_pop_T0(s);
-        s->popl_esp_hack = 2 << dflag;
-        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
-        s->popl_esp_hack = 0;
-        gen_pop_update(s);
+        if (mod == 3) {
+            /* NOTE: order is important for pop %sp */
+            gen_pop_update(s);
+            rm = modrm & 7;
+            gen_op_mov_reg_T0[ot][rm]();
+        } else {
+            /* NOTE: order is important too for MMU exceptions */
+            s->popl_esp_hack = 2 << dflag;
+            gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+            s->popl_esp_hack = 0;
+            gen_pop_update(s);
+        }
         break;
     case 0xc8: /* enter */
         {
@@ -2375,8 +2411,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
         gen_pop_update(s);
         if (reg == R_SS) {
-            /* if reg == SS, inhibit interrupts/trace */
-            gen_op_set_inhibit_irq();
+            /* if reg == SS, inhibit interrupts/trace. */
+            /* If several instructions disable interrupts, only the
+               _first_ does it */
+            if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
+                gen_op_set_inhibit_irq();
             s->tf = 0;
         }
         if (s->is_jmp) {
@@ -2447,7 +2486,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
         if (reg == R_SS) {
             /* if reg == SS, inhibit interrupts/trace */
-            gen_op_set_inhibit_irq();
+            /* If several instructions disable interrupts, only the
+               _first_ does it */
+            if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
+                gen_op_set_inhibit_irq();
             s->tf = 0;
         }
         if (s->is_jmp) {
@@ -2516,6 +2558,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0x8d: /* lea */
         ot = dflag ? OT_LONG : OT_WORD;
         modrm = ldub_code(s->pc++);
+        mod = (modrm >> 6) & 3;
+        if (mod == 3)
+            goto illegal_op;
         reg = (modrm >> 3) & 7;
         /* we must ensure that no segment is added */
         s->override = -1;
@@ -2748,9 +2793,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             val &= 0x1f;
             if (val) {
                 if (mod == 3)
-                    gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val);
+                    gen_op_shiftd_T0_T1_im_cc[ot][op](val);
                 else
-                    gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val);
+                    gen_op_shiftd_mem_T0_T1_im_cc[ot + s->mem_index][op](val);
                 if (op == 0 && ot != OT_WORD)
                     s->cc_op = CC_OP_SHLB + ot;
                 else
@@ -2760,9 +2805,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             if (s->cc_op != CC_OP_DYNAMIC)
                 gen_op_set_cc_op(s->cc_op);
             if (mod == 3)
-                gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op]();
+                gen_op_shiftd_T0_T1_ECX_cc[ot][op]();
             else
-                gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op]();
+                gen_op_shiftd_mem_T0_T1_ECX_cc[ot + s->mem_index][op]();
             s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
         }
         if (mod == 3) {
@@ -2773,11 +2818,16 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         /************************/
         /* floats */
     case 0xd8 ... 0xdf: 
+        if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
+            /* if CR0.EM or CR0.TS are set, generate an FPU exception */
+            /* XXX: what to do if illegal op ? */
+            gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+            break;
+        }
         modrm = ldub_code(s->pc++);
         mod = (modrm >> 6) & 3;
         rm = modrm & 7;
         op = ((b & 7) << 3) | ((modrm >> 3) & 7);
-        
         if (mod != 3) {
             /* memory op */
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
@@ -2925,6 +2975,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             case 0x0a: /* grp d9/2 */
                 switch(rm) {
                 case 0: /* fnop */
+                    /* check exceptions (FreeBSD FPU probe) */
+                    if (s->cc_op != CC_OP_DYNAMIC)
+                        gen_op_set_cc_op(s->cc_op);
+                    gen_op_jmp_im(pc_start - s->cs_base);
+                    gen_op_fwait();
                     break;
                 default:
                     goto illegal_op;
@@ -3113,6 +3168,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
                 gen_op_fcomi_ST0_FT0();
                 s->cc_op = CC_OP_EFLAGS;
                 break;
+            case 0x28: /* ffree sti */
+                gen_op_ffree_STN(opreg);
+                break; 
             case 0x2a: /* fst sti */
                 gen_op_fmov_STN_ST0(opreg);
                 break;
@@ -3166,10 +3224,28 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
                 gen_op_fpop();
                 s->cc_op = CC_OP_EFLAGS;
                 break;
+            case 0x10 ... 0x13: /* fcmovxx */
+            case 0x18 ... 0x1b:
+                {
+                    int op1;
+                    const static uint8_t fcmov_cc[8] = {
+                        (JCC_B << 1),
+                        (JCC_Z << 1),
+                        (JCC_BE << 1),
+                        (JCC_P << 1),
+                    };
+                    op1 = fcmov_cc[op & 3] | ((op >> 3) & 1);
+                    gen_setcc(s, op1);
+                    gen_op_fcmov_ST0_STN_T0(opreg);
+                }
+                break;
             default:
                 goto illegal_op;
             }
         }
+#ifdef USE_CODE_COPY
+        s->tb->cflags |= CF_TB_FP_USED;
+#endif
         break;
         /************************/
         /* string ops */
@@ -3304,6 +3380,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         else
             ot = dflag ? OT_LONG : OT_WORD;
         gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
+        gen_op_andl_T0_ffff();
         gen_check_io(s, ot, 0, pc_start - s->cs_base);
         gen_op_in[ot]();
         gen_op_mov_reg_T1[ot][R_EAX]();
@@ -3315,6 +3392,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         else
             ot = dflag ? OT_LONG : OT_WORD;
         gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
+        gen_op_andl_T0_ffff();
         gen_check_io(s, ot, 0, pc_start - s->cs_base);
         gen_op_mov_TN_reg[ot][1][R_EAX]();
         gen_op_out[ot]();
@@ -3386,7 +3464,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             if (s->cc_op != CC_OP_DYNAMIC)
                 gen_op_set_cc_op(s->cc_op);
             gen_op_jmp_im(pc_start - s->cs_base);
-            gen_op_iret_protected(s->dflag);
+            gen_op_iret_protected(s->dflag, s->pc - s->cs_base);
             s->cc_op = CC_OP_EFLAGS;
         }
         gen_eob(s);
@@ -3506,10 +3584,18 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
                     gen_op_movw_eflags_T0_cpl0();
                 }
             } else {
-                if (s->dflag) {
-                    gen_op_movl_eflags_T0();
+                if (s->cpl <= s->iopl) {
+                    if (s->dflag) {
+                        gen_op_movl_eflags_T0_io();
+                    } else {
+                        gen_op_movw_eflags_T0_io();
+                    }
                 } else {
-                    gen_op_movw_eflags_T0();
+                    if (s->dflag) {
+                        gen_op_movl_eflags_T0();
+                    } else {
+                        gen_op_movw_eflags_T0();
+                    }
                 }
             }
             gen_pop_update(s);
@@ -3632,10 +3718,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         modrm = ldub_code(s->pc++);
         reg = (modrm >> 3) & 7;
         gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+        /* NOTE: in order to handle the 0 case, we must load the
+           result. It could be optimized with a generated jump */
+        gen_op_mov_TN_reg[ot][1][reg]();
         gen_op_bsx_T0_cc[ot - OT_WORD][b & 1]();
-        /* NOTE: we always write back the result. Intel doc says it is
-           undefined if T0 == 0 */
-        gen_op_mov_reg_T0[ot][reg]();
+        gen_op_mov_reg_T1[ot][reg]();
         s->cc_op = CC_OP_LOGICB + ot;
         break;
         /************************/
@@ -3677,8 +3764,20 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         /************************/
         /* misc */
     case 0x90: /* nop */
+        /* XXX: correct lock test for all insn */
+        if (prefixes & PREFIX_LOCK)
+            goto illegal_op;
         break;
     case 0x9b: /* fwait */
+        if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == 
+            (HF_MP_MASK | HF_TS_MASK)) {
+            gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_op_jmp_im(pc_start - s->cs_base);
+            gen_op_fwait();
+        }
         break;
     case 0xcc: /* int3 */
         gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
@@ -3720,7 +3819,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             gen_sti:
                 gen_op_sti();
                 /* interruptions are enabled only the first insn after sti */
-                gen_op_set_inhibit_irq();
+                /* If several instructions disable interrupts, only the
+                   _first_ does it */
+                if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
+                    gen_op_set_inhibit_irq();
                 /* give a chance to handle pending irqs */
                 gen_op_jmp_im(s->pc - s->cs_base);
                 gen_eob(s);
@@ -3742,7 +3844,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         mod = (modrm >> 6) & 3;
         if (mod == 3)
             goto illegal_op;
-        gen_op_mov_reg_T0[ot][reg]();
+        gen_op_mov_TN_reg[ot][0][reg]();
         gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
         if (ot == OT_WORD)
             gen_op_boundw(pc_start - s->cs_base);
@@ -3789,6 +3891,32 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0x131: /* rdtsc */
         gen_op_rdtsc();
         break;
+    case 0x134: /* sysenter */
+        if (!s->pe) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC) {
+                gen_op_set_cc_op(s->cc_op);
+                s->cc_op = CC_OP_DYNAMIC;
+            }
+            gen_op_jmp_im(pc_start - s->cs_base);
+            gen_op_sysenter();
+            gen_eob(s);
+        }
+        break;
+    case 0x135: /* sysexit */
+        if (!s->pe) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC) {
+                gen_op_set_cc_op(s->cc_op);
+                s->cc_op = CC_OP_DYNAMIC;
+            }
+            gen_op_jmp_im(pc_start - s->cs_base);
+            gen_op_sysexit();
+            gen_eob(s);
+        }
+        break;
     case 0x1a2: /* cpuid */
         gen_op_cpuid();
         break;
@@ -3921,6 +4049,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             } else {
                 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
                 gen_op_lmsw_T0();
+                gen_op_jmp_im(s->pc - s->cs_base);
+                gen_eob(s);
             }
             break;
         case 7: /* invlpg */
@@ -3931,12 +4061,22 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
                     goto illegal_op;
                 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
                 gen_op_invlpg_A0();
+                gen_op_jmp_im(s->pc - s->cs_base);
+                gen_eob(s);
             }
             break;
         default:
             goto illegal_op;
         }
         break;
+    case 0x108: /* invd */
+    case 0x109: /* wbinvd */
+        if (s->cpl != 0) {
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else {
+            /* nothing to do */
+        }
+        break;
     case 0x63: /* arpl */
         if (!s->pe || s->vm86)
             goto illegal_op;
@@ -4057,6 +4197,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             gen_op_clts();
+            /* abort block because static cpu state changed */
+            gen_op_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
         }
         break;
     default:
@@ -4067,6 +4210,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         gen_op_unlock();
     return s->pc;
  illegal_op:
+    if (s->prefix & PREFIX_LOCK)
+        gen_op_unlock();
     /* XXX: ensure that no lock was generated */
     gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
     return s->pc;
@@ -4082,20 +4227,6 @@ static uint16_t opc_read_flags[NB_OPS] = {
     [INDEX_op_das] = CC_A | CC_C,
     [INDEX_op_daa] = CC_A | CC_C,
 
-    [INDEX_op_adcb_T0_T1_cc] = CC_C,
-    [INDEX_op_adcw_T0_T1_cc] = CC_C,
-    [INDEX_op_adcl_T0_T1_cc] = CC_C,
-    [INDEX_op_sbbb_T0_T1_cc] = CC_C,
-    [INDEX_op_sbbw_T0_T1_cc] = CC_C,
-    [INDEX_op_sbbl_T0_T1_cc] = CC_C,
-
-    [INDEX_op_adcb_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_adcw_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_adcl_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_sbbb_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_sbbw_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_sbbl_mem_T0_T1_cc] = CC_C,
-
     /* subtle: due to the incl/decl implementation, C is used */
     [INDEX_op_update_inc_cc] = CC_C, 
 
@@ -4167,19 +4298,34 @@ static uint16_t opc_read_flags[NB_OPS] = {
     [INDEX_op_cmc] = CC_C,
     [INDEX_op_salc] = CC_C,
 
-    [INDEX_op_rclb_T0_T1_cc] = CC_C,
-    [INDEX_op_rclw_T0_T1_cc] = CC_C,
-    [INDEX_op_rcll_T0_T1_cc] = CC_C,
-    [INDEX_op_rcrb_T0_T1_cc] = CC_C,
-    [INDEX_op_rcrw_T0_T1_cc] = CC_C,
-    [INDEX_op_rcrl_T0_T1_cc] = CC_C,
-
-    [INDEX_op_rclb_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_rclw_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_rcll_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_rcrb_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_rcrw_mem_T0_T1_cc] = CC_C,
-    [INDEX_op_rcrl_mem_T0_T1_cc] = CC_C,
+    /* needed for correct flag optimisation before string ops */
+    [INDEX_op_jz_ecxw] = CC_OSZAPC,
+    [INDEX_op_jz_ecxl] = CC_OSZAPC,
+    [INDEX_op_jz_ecxw_im] = CC_OSZAPC,
+    [INDEX_op_jz_ecxl_im] = CC_OSZAPC,
+
+#define DEF_READF(SUFFIX)\
+    [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_C,\
+\
+    [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_C,\
+    [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C,
+
+
+    DEF_READF( )
+    DEF_READF(_raw)
+#ifndef CONFIG_USER_ONLY
+    DEF_READF(_kernel)
+    DEF_READF(_user)
+#endif
 };
 
 /* flags written by an operation */
@@ -4192,20 +4338,6 @@ static uint16_t opc_write_flags[NB_OPS] = {
     [INDEX_op_update_inc_cc] = CC_OSZAPC, 
     [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
 
-    [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC,
-
-    [INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC,
-
     [INDEX_op_mulb_AL_T0] = CC_OSZAPC,
     [INDEX_op_imulb_AL_T0] = CC_OSZAPC,
     [INDEX_op_mulw_AX_T0] = CC_OSZAPC,
@@ -4226,82 +4358,14 @@ static uint16_t opc_write_flags[NB_OPS] = {
     [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
     [INDEX_op_movw_eflags_T0] = CC_OSZAPC,
     [INDEX_op_movl_eflags_T0] = CC_OSZAPC,
+    [INDEX_op_movw_eflags_T0_io] = CC_OSZAPC,
+    [INDEX_op_movl_eflags_T0_io] = CC_OSZAPC,
+    [INDEX_op_movw_eflags_T0_cpl0] = CC_OSZAPC,
+    [INDEX_op_movl_eflags_T0_cpl0] = CC_OSZAPC,
     [INDEX_op_clc] = CC_C,
     [INDEX_op_stc] = CC_C,
     [INDEX_op_cmc] = CC_C,
 
-    [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C,
-
-    [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C,
-
-    [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC,
-
-    [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC,
-
-    [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC,
-
-    [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC,
-    [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC,
-    [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC,
-    [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC,
-
-    [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC,
-    [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC,
-    [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC,
-    [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC,
-
-    [INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C,
-
-    [INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C,
-    [INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C,
-
-    [INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC,
-
-    [INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC,
-
-    [INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC,
-    [INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC,
-
-    [INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC,
-    [INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC,
-    [INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC,
-    [INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC,
-
-    [INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC,
-    [INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC,
-    [INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC,
-    [INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC,
-
     [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC,
     [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC,
     [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC,
@@ -4320,15 +4384,67 @@ static uint16_t opc_write_flags[NB_OPS] = {
     [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
     [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
 
-    [INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC,
-    [INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC,
-    [INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC,
-
     [INDEX_op_cmpxchg8b] = CC_Z,
     [INDEX_op_lar] = CC_Z,
     [INDEX_op_lsl] = CC_Z,
     [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C,
     [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C,
+
+#define DEF_WRITEF(SUFFIX)\
+    [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+\
+    [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+\
+    [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+    [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
+\
+    [INDEX_op_shlb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_shlw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_shll ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+\
+    [INDEX_op_shrb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_shrw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_shrl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+\
+    [INDEX_op_sarb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_sarw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+    [INDEX_op_sarl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
+\
+    [INDEX_op_shldw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
+    [INDEX_op_shldl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
+    [INDEX_op_shldw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
+    [INDEX_op_shldl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
+\
+    [INDEX_op_shrdw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
+    [INDEX_op_shrdl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
+    [INDEX_op_shrdw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
+    [INDEX_op_shrdl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
+\
+    [INDEX_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\
+    [INDEX_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\
+    [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,
+
+
+    DEF_WRITEF( )
+    DEF_WRITEF(_raw)
+#ifndef CONFIG_USER_ONLY
+    DEF_WRITEF(_kernel)
+    DEF_WRITEF(_user)
+#endif
 };
 
 /* simpler form of an operation if no flags need to be generated */
@@ -4340,21 +4456,6 @@ static uint16_t opc_simpler[NB_OPS] = {
     /* broken: CC_OP logic must be rewritten */
     [INDEX_op_update_inc_cc] = INDEX_op_nop,
 #endif
-    [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1,
-    [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1,
-    [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1,
-
-    [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1,
-    [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1,
-    [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1,
-
-    [INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1,
-    [INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1,
-    [INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1,
-
-    [INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1,
-    [INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1,
-    [INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1,
 
     [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1,
     [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1,
@@ -4367,6 +4468,22 @@ static uint16_t opc_simpler[NB_OPS] = {
     [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1,
     [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1,
     [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1,
+
+#define DEF_SIMPLER(SUFFIX)\
+    [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolb ## SUFFIX ## _T0_T1,\
+    [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolw ## SUFFIX ## _T0_T1,\
+    [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = INDEX_op_roll ## SUFFIX ## _T0_T1,\
+\
+    [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorb ## SUFFIX ## _T0_T1,\
+    [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorw ## SUFFIX ## _T0_T1,\
+    [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorl ## SUFFIX ## _T0_T1,
+
+    DEF_SIMPLER( )
+    DEF_SIMPLER(_raw)
+#ifndef CONFIG_USER_ONLY
+    DEF_SIMPLER(_kernel)
+    DEF_SIMPLER(_user)
+#endif
 };
 
 void optimize_flags_init(void)
@@ -4416,7 +4533,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     DisasContext dc1, *dc = &dc1;
     uint8_t *pc_ptr;
     uint16_t *gen_opc_end;
-    int flags, j, lj;
+    int flags, j, lj, cflags;
     uint8_t *pc_start;
     uint8_t *cs_base;
     
@@ -4424,8 +4541,9 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     pc_start = (uint8_t *)tb->pc;
     cs_base = (uint8_t *)tb->cs_base;
     flags = tb->flags;
-       
-    dc->pe = env->cr[0] & CR0_PE_MASK;
+    cflags = tb->cflags;
+
+    dc->pe = (flags >> HF_PE_SHIFT) & 1;
     dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
     dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
     dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
@@ -4447,11 +4565,19 @@ static inline int gen_intermediate_code_internal(CPUState *env,
         else
             dc->mem_index = 3;
     }
-    dc->jmp_opt = !(dc->tf || env->singlestep_enabled
+    dc->flags = flags;
+    dc->jmp_opt = !(dc->tf || env->singlestep_enabled ||
+                    (flags & HF_INHIBIT_IRQ_MASK)
 #ifndef CONFIG_SOFTMMU
                     || (flags & HF_SOFTMMU_MASK)
 #endif
                     );
+#if 0
+    /* check addseg logic */
+    if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
+        printf("ERROR addseg\n");
+#endif
+
     gen_opc_ptr = gen_opc_buf;
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
     gen_opparam_ptr = gen_opparam_buf;
@@ -4460,12 +4586,6 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     pc_ptr = pc_start;
     lj = -1;
 
-    /* if irq were inhibited for the next instruction, we can disable
-       them here as it is simpler (otherwise jumps would have to
-       handled as special case) */
-    if (flags & HF_INHIBIT_IRQ_MASK) {
-        gen_op_reset_inhibit_irq();
-    }
     for(;;) {
         if (env->nb_breakpoints > 0) {
             for(j = 0; j < env->nb_breakpoints; j++) {
@@ -4492,7 +4612,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
             break;
         /* if single step mode, we generate only one instruction and
            generate an exception */
-        if (dc->tf || dc->singlestep_enabled) {
+        /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
+           the flag and abort the translation to give the irqs a
+           change to be happen */
+        if (dc->tf || dc->singlestep_enabled || 
+            (flags & HF_INHIBIT_IRQ_MASK) ||
+            (cflags & CF_SINGLE_INSN)) {
             gen_op_jmp_im(pc_ptr - dc->cs_base);
             gen_eob(dc);
             break;
@@ -4515,15 +4640,19 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     }
         
 #ifdef DEBUG_DISAS
-    if (loglevel) {
+    if (loglevel & CPU_LOG_TB_CPU) {
+        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
+    }
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
         fprintf(logfile, "----------------\n");
         fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
        disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32);
         fprintf(logfile, "\n");
-
-        fprintf(logfile, "OP:\n");
-        dump_ops(gen_opc_buf, gen_opparam_buf);
-        fprintf(logfile, "\n");
+        if (loglevel & CPU_LOG_TB_OP) {
+            fprintf(logfile, "OP:\n");
+            dump_ops(gen_opc_buf, gen_opparam_buf);
+            fprintf(logfile, "\n");
+        }
     }
 #endif
 
@@ -4531,7 +4660,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf);
 
 #ifdef DEBUG_DISAS
-    if (loglevel) {
+    if (loglevel & CPU_LOG_TB_OP_OPT) {
         fprintf(logfile, "AFTER FLAGS OPT:\n");
         dump_ops(gen_opc_buf, gen_opparam_buf);
         fprintf(logfile, "\n");