]> Git Repo - qemu.git/blobdiff - target-i386/helper.c
fixed eflags optimisations with string operation (aka linux 2.6.2rc1 fix) - removed...
[qemu.git] / target-i386 / helper.c
index 861266fa14f2ad141fb3b992f8706e036522be5e..320e09a758ee7f3ff476c269183c9d3260634d85 100644 (file)
@@ -281,6 +281,10 @@ static void switch_tss(int tss_selector,
     uint8_t *ptr;
 
     type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+#ifdef DEBUG_PCALL
+    if (loglevel)
+        fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
+#endif
 
     /* if task gate, we read the TSS segment and we load it */
     if (type == 5) {
@@ -419,7 +423,8 @@ static void switch_tss(int tss_selector,
     /* load all registers without an exception, then reload them with
        possible exception */
     env->eip = new_eip;
-    eflags_mask = FL_UPDATE_CPL0_MASK;
+    eflags_mask = TF_MASK | AC_MASK | ID_MASK | 
+        IF_MASK | IOPL_MASK | VM_MASK | RF_MASK;
     if (!(type & 8))
         eflags_mask &= 0xffff;
     load_eflags(new_eflags, eflags_mask);
@@ -575,27 +580,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
     uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
     uint32_t old_eip;
 
-#ifdef DEBUG_PCALL
-    if (loglevel) {
-        static int count;
-        fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d CS:IP=%04x:%08x CPL=%d\n",
-                count, intno, error_code, is_int, env->segs[R_CS].selector, env->eip, env->hflags & 3);
-#if 0
-        {
-            int i;
-            uint8_t *ptr;
-            printf("       code=");
-            ptr = env->segs[R_CS].base + env->eip;
-            for(i = 0; i < 16; i++) {
-                printf(" %02x", ldub(ptr + i));
-            }
-            printf("\n");
-        }
-#endif
-        count++;
-    }
-#endif
-
     has_error_code = 0;
     if (!is_int && !is_hw) {
         switch(intno) {
@@ -696,10 +680,13 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
         ssp = get_seg_base(ss_e1, ss_e2);
     } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
         /* to same priviledge */
+        if (env->eflags & VM_MASK)
+            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
         new_stack = 0;
         sp_mask = get_sp_mask(env->segs[R_SS].flags);
         ssp = env->segs[R_SS].base;
         esp = ESP;
+        dpl = cpl;
     } else {
         raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
         new_stack = 0; /* avoid warning */
@@ -722,13 +709,13 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
     else
         old_eip = env->eip;
     if (shift == 1) {
-        if (env->eflags & VM_MASK) {
-            PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
-            PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
-            PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
-            PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
-        }
         if (new_stack) {
+            if (env->eflags & VM_MASK) {
+                PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
+                PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
+            }
             PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
             PUSHL(ssp, esp, sp_mask, ESP);
         }
@@ -740,6 +727,12 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
         }
     } else {
         if (new_stack) {
+            if (env->eflags & VM_MASK) {
+                PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
+                PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
+            }
             PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
             PUSHW(ssp, esp, sp_mask, ESP);
         }
@@ -752,6 +745,18 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
     }
     
     if (new_stack) {
+        if (env->eflags & VM_MASK) {
+            /* XXX: explain me why W2K hangs if the whole segment cache is
+               reset ? */
+            env->segs[R_ES].selector = 0;
+            env->segs[R_ES].flags = 0;
+            env->segs[R_DS].selector = 0;
+            env->segs[R_DS].flags = 0;
+            env->segs[R_FS].selector = 0;
+            env->segs[R_FS].flags = 0;
+            env->segs[R_GS].selector = 0;
+            env->segs[R_GS].flags = 0;
+        }
         ss = (ss & ~3) | dpl;
         cpu_x86_load_seg_cache(env, R_SS, ss, 
                                ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
@@ -775,7 +780,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
 
 /* real mode interrupt */
 static void do_interrupt_real(int intno, int is_int, int error_code,
-                                 unsigned int next_eip)
+                              unsigned int next_eip)
 {
     SegmentCache *dt;
     uint8_t *ptr, *ssp;
@@ -844,6 +849,58 @@ void do_interrupt_user(int intno, int is_int, int error_code,
 void do_interrupt(int intno, int is_int, int error_code, 
                   unsigned int next_eip, int is_hw)
 {
+#if 0
+    {
+        extern FILE *stdout;
+        static int count;
+        if ((env->cr[0] && CR0_PE_MASK)) {
+            fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x EAX=%08x\n",
+                    count, intno, error_code, is_int,
+                    env->hflags & HF_CPL_MASK,
+                    env->segs[R_CS].selector, EIP,
+                    env->segs[R_SS].selector, ESP, 
+                    EAX);
+            if (0) {
+                cpu_x86_dump_state(env, stdout, X86_DUMP_CCOP);
+#if 0
+                {
+                    int i;
+                    uint8_t *ptr;
+                    fprintf(stdout, "       code=");
+                    ptr = env->segs[R_CS].base + env->eip;
+                    for(i = 0; i < 16; i++) {
+                        fprintf(stdout, " %02x", ldub(ptr + i));
+                    }
+                    fprintf(stdout, "\n");
+                }
+#endif
+            }
+            count++;
+        }
+    }
+#endif
+
+#ifdef DEBUG_PCALL
+    if (loglevel) {
+        static int count;
+        fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n",
+                count, intno, error_code, is_int);
+        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
+#if 0
+        {
+            int i;
+            uint8_t *ptr;
+            fprintf(logfile, "       code=");
+            ptr = env->segs[R_CS].base + env->eip;
+            for(i = 0; i < 16; i++) {
+                fprintf(logfile, " %02x", ldub(ptr + i));
+            }
+            fprintf(logfile, "\n");
+        }
+#endif
+        count++;
+    }
+#endif
     if (env->cr[0] & CR0_PE_MASK) {
         do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
     } else {
@@ -954,7 +1011,6 @@ void helper_cmpxchg8b(void)
     CC_SRC = eflags;
 }
 
-/* We simulate a pre-MMX pentium as in valgrind */
 #define CPUID_FP87 (1 << 0)
 #define CPUID_VME  (1 << 1)
 #define CPUID_DE   (1 << 2)
@@ -978,31 +1034,43 @@ void helper_cmpxchg8b(void)
 
 void helper_cpuid(void)
 {
-    if (EAX == 0) {
-        EAX = 1; /* max EAX index supported */
+    switch(EAX) {
+    case 0:
+        EAX = 2; /* max EAX index supported */
         EBX = 0x756e6547;
         ECX = 0x6c65746e;
         EDX = 0x49656e69;
-    } else if (EAX == 1) {
-        int family, model, stepping;
-        /* EAX = 1 info */
+        break;
+    case 1:
+        {
+            int family, model, stepping;
+            /* EAX = 1 info */
 #if 0
-        /* pentium 75-200 */
-        family = 5;
-        model = 2;
-        stepping = 11;
+            /* pentium 75-200 */
+            family = 5;
+            model = 2;
+            stepping = 11;
 #else
-        /* pentium pro */
-        family = 6;
-        model = 1;
-        stepping = 3;
+            /* pentium pro */
+            family = 6;
+            model = 1;
+            stepping = 3;
 #endif
-        EAX = (family << 8) | (model << 4) | stepping;
+            EAX = (family << 8) | (model << 4) | stepping;
+            EBX = 0;
+            ECX = 0;
+            EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
+                CPUID_TSC | CPUID_MSR | CPUID_MCE |
+                CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
+        }
+        break;
+    default:
+        /* cache info: needed for Pentium Pro compatibility */
+        EAX = 0x410601;
         EBX = 0;
         ECX = 0;
-        EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
-            CPUID_TSC | CPUID_MSR | CPUID_MCE |
-            CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
+        EDX = 0;
+        break;
     }
 }
 
@@ -1069,14 +1137,14 @@ void helper_ltr_T0(void)
         if (!(e2 & DESC_P_MASK))
             raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
         load_seg_cache_raw_dt(&env->tr, e1, e2);
-        e2 |= 0x00000200; /* set the busy bit */
+        e2 |= DESC_TSS_BUSY_MASK;
         stl_kernel(ptr + 4, e2);
     }
     env->tr.selector = selector;
 }
 
 /* only works if protected mode and not VM86. seg_reg must be != R_CS */
-void load_seg(int seg_reg, int selector, unsigned int cur_eip)
+void load_seg(int seg_reg, int selector)
 {
     uint32_t e1, e2;
     int cpl, dpl, rpl;
@@ -1084,14 +1152,12 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip)
     int index;
     uint8_t *ptr;
 
+    selector &= 0xffff;
     if ((selector & 0xfffc) == 0) {
         /* null selector case */
-        if (seg_reg == R_SS) {
-            EIP = cur_eip;
+        if (seg_reg == R_SS)
             raise_exception_err(EXCP0D_GPF, 0);
-        } else {
-            cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
-        }
+        cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
     } else {
         
         if (selector & 0x4)
@@ -1099,49 +1165,36 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip)
         else
             dt = &env->gdt;
         index = selector & ~7;
-        if ((index + 7) > dt->limit) {
-            EIP = cur_eip;
+        if ((index + 7) > dt->limit)
             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
-        }
         ptr = dt->base + index;
         e1 = ldl_kernel(ptr);
         e2 = ldl_kernel(ptr + 4);
 
-        if (!(e2 & DESC_S_MASK)) {
-            EIP = cur_eip;
+        if (!(e2 & DESC_S_MASK))
             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
-        }
         rpl = selector & 3;
         dpl = (e2 >> DESC_DPL_SHIFT) & 3;
         cpl = env->hflags & HF_CPL_MASK;
         if (seg_reg == R_SS) {
             /* must be writable segment */
-            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
-                EIP = cur_eip;
+            if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
                 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
-            }
-            if (rpl != cpl || dpl != cpl) {
-                EIP = cur_eip;
+            if (rpl != cpl || dpl != cpl)
                 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
-            }
         } else {
             /* must be readable segment */
-            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
-                EIP = cur_eip;
+            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
                 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
-            }
             
             if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
                 /* if not conforming code, test rights */
-                if (dpl < cpl || dpl < rpl) {
-                    EIP = cur_eip;
+                if (dpl < cpl || dpl < rpl)
                     raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
-                }
             }
         }
 
         if (!(e2 & DESC_P_MASK)) {
-            EIP = cur_eip;
             if (seg_reg == R_SS)
                 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
             else
@@ -1293,6 +1346,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
     if (loglevel) {
         fprintf(logfile, "lcall %04x:%08x\n",
                 new_cs, new_eip);
+        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
     }
 #endif
     if ((new_cs & 0xfffc) == 0)
@@ -1493,25 +1547,40 @@ void helper_iret_real(int shift)
         POPW(ssp, sp, sp_mask, new_cs);
         POPW(ssp, sp, sp_mask, new_eflags);
     }
-    ESP = (ESP & ~sp_mask) | (sp & 0xffff);
+    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
     load_seg_vm(R_CS, new_cs);
     env->eip = new_eip;
     if (env->eflags & VM_MASK)
-        eflags_mask = FL_UPDATE_MASK32 | IF_MASK | RF_MASK;
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK;
     else
-        eflags_mask = FL_UPDATE_CPL0_MASK;
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK;
     if (shift == 0)
         eflags_mask &= 0xffff;
     load_eflags(new_eflags, eflags_mask);
 }
 
+static inline void validate_seg(int seg_reg, int cpl)
+{
+    int dpl;
+    uint32_t e2;
+    
+    e2 = env->segs[seg_reg].flags;
+    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+    if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
+        /* data or non conforming code segment */
+        if (dpl < cpl) {
+            cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0);
+        }
+    }
+}
+
 /* protected mode iret */
 static inline void helper_ret_protected(int shift, int is_iret, int addend)
 {
     uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask;
     uint32_t new_es, new_ds, new_fs, new_gs;
     uint32_t e1, e2, ss_e1, ss_e2;
-    int cpl, dpl, rpl, eflags_mask;
+    int cpl, dpl, rpl, eflags_mask, iopl;
     uint8_t *ssp;
     
     sp_mask = get_sp_mask(env->segs[R_SS].flags);
@@ -1536,8 +1605,9 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
     }
 #ifdef DEBUG_PCALL
     if (loglevel) {
-        fprintf(logfile, "lret new %04x:%08x\n",
-                new_cs, new_eip);
+        fprintf(logfile, "lret new %04x:%08x addend=0x%x\n",
+                new_cs, new_eip, addend);
+        cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
     }
 #endif
     if ((new_cs & 0xfffc) == 0)
@@ -1607,15 +1677,23 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
         cpu_x86_set_cpl(env, rpl);
         sp = new_esp;
         /* XXX: change sp_mask according to old segment ? */
+
+        /* validate data segments */
+        validate_seg(R_ES, cpl);
+        validate_seg(R_DS, cpl);
+        validate_seg(R_FS, cpl);
+        validate_seg(R_GS, cpl);
     }
     ESP = (ESP & ~sp_mask) | (sp & sp_mask);
     env->eip = new_eip;
     if (is_iret) {
-        /* NOTE: 'cpl' can be different from the current CPL */
+        /* NOTE: 'cpl' is the _old_ CPL */
+        eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK;
         if (cpl == 0)
-            eflags_mask = FL_UPDATE_CPL0_MASK;
-        else
-            eflags_mask = FL_UPDATE_MASK32;
+            eflags_mask |= IOPL_MASK;
+        iopl = (env->eflags >> IOPL_SHIFT) & 3;
+        if (cpl <= iopl)
+            eflags_mask |= IF_MASK;
         if (shift == 0)
             eflags_mask &= 0xffff;
         load_eflags(new_eflags, eflags_mask);
@@ -1631,7 +1709,8 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
     POPL(ssp, sp, sp_mask, new_gs);
     
     /* modify processor state */
-    load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
+    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | 
+                IF_MASK | IOPL_MASK | VM_MASK | VIF_MASK | VIP_MASK);
     load_seg_vm(R_CS, new_cs & 0xffff);
     cpu_x86_set_cpl(env, 3);
     load_seg_vm(R_SS, new_ss & 0xffff);
@@ -2373,10 +2452,6 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
        generated code */
     saved_env = env;
     env = cpu_single_env;
-    if (is_write && page_unprotect(addr)) {
-        /* nothing more to do: the page was write protected because
-           there was code in it. page_unprotect() flushed the code. */
-    }
 
     ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
     if (ret) {
This page took 0.036152 seconds and 4 git commands to generate.