]> git.proxmox.com Git - qemu.git/blobdiff - target-i386/translate.c
monitor fixes
[qemu.git] / target-i386 / translate.c
index 2407735281aa3767cc700f0b2f00dbe4324c5817..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;
@@ -390,7 +390,7 @@ static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
     },
 
 static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
-    DEF_ARITHC()
+    DEF_ARITHC( )
 };
 
 static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[9][2] = {
@@ -419,7 +419,7 @@ static const int cc_op_arithb[8] = {
 
 
 static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = {
-    DEF_CMPXCHG()
+    DEF_CMPXCHG( )
 };
 
 static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = {
@@ -463,7 +463,7 @@ static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = {
     },
 
 static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
-    DEF_SHIFT()
+    DEF_SHIFT( )
 };
 
 static GenOpFunc *gen_op_shift_mem_T0_T1_cc[9][8] = {
@@ -697,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,
@@ -921,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);                                                      \
@@ -1530,15 +1538,17 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
             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]));
+        if (seg_reg == R_SS)
+            s->is_jmp = 3;
     }
-    /* 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;
 }
 
 static inline void gen_stack_update(DisasContext *s, int addend)
@@ -1930,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;
@@ -1955,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:
@@ -2163,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();
@@ -2234,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]();
@@ -2546,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;
@@ -2803,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);
@@ -2955,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;
@@ -3143,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;
@@ -3215,6 +3243,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
                 goto illegal_op;
             }
         }
+#ifdef USE_CODE_COPY
+        s->tb->cflags |= CF_TB_FP_USED;
+#endif
         break;
         /************************/
         /* string ops */
@@ -3433,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);
@@ -3687,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;
         /************************/
@@ -3732,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);
@@ -3800,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);
@@ -3847,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;
@@ -4127,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:
@@ -4137,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;
@@ -4223,6 +4298,12 @@ static uint16_t opc_read_flags[NB_OPS] = {
     [INDEX_op_cmc] = CC_C,
     [INDEX_op_salc] = 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,\
@@ -4239,7 +4320,7 @@ static uint16_t opc_read_flags[NB_OPS] = {
     [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C,
 
 
-    DEF_READF()
+    DEF_READF( )
     DEF_READF(_raw)
 #ifndef CONFIG_USER_ONLY
     DEF_READF(_kernel)
@@ -4358,7 +4439,7 @@ static uint16_t opc_write_flags[NB_OPS] = {
     [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,
 
 
-    DEF_WRITEF()
+    DEF_WRITEF( )
     DEF_WRITEF(_raw)
 #ifndef CONFIG_USER_ONLY
     DEF_WRITEF(_kernel)
@@ -4397,7 +4478,7 @@ static uint16_t opc_simpler[NB_OPS] = {
     [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( )
     DEF_SIMPLER(_raw)
 #ifndef CONFIG_USER_ONLY
     DEF_SIMPLER(_kernel)
@@ -4452,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;
     
@@ -4460,7 +4541,8 @@ 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;
-       
+    cflags = tb->cflags;
+
     dc->pe = (flags >> HF_PE_SHIFT) & 1;
     dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
     dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
@@ -4483,6 +4565,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
         else
             dc->mem_index = 3;
     }
+    dc->flags = flags;
     dc->jmp_opt = !(dc->tf || env->singlestep_enabled ||
                     (flags & HF_INHIBIT_IRQ_MASK)
 #ifndef CONFIG_SOFTMMU
@@ -4491,7 +4574,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
                     );
 #if 0
     /* check addseg logic */
-    if (!dc->addseg && (dc->vm86 || !dc->pe))
+    if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
         printf("ERROR addseg\n");
 #endif
 
@@ -4533,7 +4616,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
            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)) {
+            (flags & HF_INHIBIT_IRQ_MASK) ||
+            (cflags & CF_SINGLE_INSN)) {
             gen_op_jmp_im(pc_ptr - dc->cs_base);
             gen_eob(dc);
             break;
@@ -4556,16 +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");
-#if 0
-        fprintf(logfile, "OP:\n");
-        dump_ops(gen_opc_buf, gen_opparam_buf);
-        fprintf(logfile, "\n");
-#endif
+        if (loglevel & CPU_LOG_TB_OP) {
+            fprintf(logfile, "OP:\n");
+            dump_ops(gen_opc_buf, gen_opparam_buf);
+            fprintf(logfile, "\n");
+        }
     }
 #endif
 
@@ -4573,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");