added fsave/frstor/fstenv/fldenv/fcomi - fixed cpuid - make lret/iret restartable
[qemu] / exec-i386.c
index 978b1da..2114d65 100644 (file)
@@ -39,9 +39,7 @@ void cpu_unlock(void)
     spin_unlock(&global_cpu_lock);
 }
 
-/* exception support */
-/* NOTE: not static to force relocation generation by GCC */
-void raise_exception_err(int exception_index, int error_code)
+void cpu_loop_exit(void)
 {
     /* NOTE: the register at this point must be saved by hand because
        longjmp restore them */
@@ -76,17 +74,9 @@ void raise_exception_err(int exception_index, int error_code)
 #ifdef reg_EDI
     env->regs[R_EDI] = EDI;
 #endif
-    env->exception_index = exception_index;
-    env->error_code = error_code;
     longjmp(env->jmp_env, 1);
 }
 
-/* short cut if error_code is 0 or not present */
-void raise_exception(int exception_index)
-{
-    raise_exception_err(exception_index, 0);
-}
-
 int cpu_x86_exec(CPUX86State *env1)
 {
     int saved_T0, saved_T1, saved_A0;
@@ -115,7 +105,7 @@ int cpu_x86_exec(CPUX86State *env1)
 #ifdef reg_EDI
     int saved_EDI;
 #endif
-    int code_gen_size, ret, code_size;
+    int code_gen_size, ret;
     void (*gen_func)(void);
     TranslationBlock *tb, **ptb;
     uint8_t *tc_ptr, *cs_base, *pc;
@@ -172,7 +162,8 @@ int cpu_x86_exec(CPUX86State *env1)
         T0 = 0; /* force lookup of first TB */
         for(;;) {
             if (env->interrupt_request) {
-                raise_exception(EXCP_INTERRUPT);
+                env->exception_index = EXCP_INTERRUPT;
+                cpu_loop_exit();
             }
 #ifdef DEBUG_EXEC
             if (loglevel) {
@@ -206,14 +197,13 @@ int cpu_x86_exec(CPUX86State *env1)
                 flags |= (1 << GEN_FLAG_VM_SHIFT);
                 flags |= (3 << GEN_FLAG_CPL_SHIFT);
             }
-            flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT);
-            flags |= (env->eflags & TF_MASK) << (GEN_FLAG_TF_SHIFT - 8);
+            flags |= (env->eflags & (IOPL_MASK | TF_MASK));
             cs_base = env->seg_cache[R_CS].base;
             pc = cs_base + env->eip;
-            spin_lock(&tb_lock);
             tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
                          flags);
             if (!tb) {
+                spin_lock(&tb_lock);
                 /* if no translated code available, then translate it now */
                 tb = tb_alloc((unsigned long)pc);
                 if (!tb) {
@@ -227,9 +217,9 @@ int cpu_x86_exec(CPUX86State *env1)
                 }
                 tc_ptr = code_gen_ptr;
                 tb->tc_ptr = tc_ptr;
-                ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
-                                       &code_gen_size, pc, cs_base, flags,
-                                       &code_size, tb);
+                tb->cs_base = (unsigned long)cs_base;
+                tb->flags = flags;
+                ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
                 /* if invalid instruction, signal it */
                 if (ret != 0) {
                     /* NOTE: the tb is allocated but not linked, so we
@@ -238,12 +228,10 @@ int cpu_x86_exec(CPUX86State *env1)
                     raise_exception(EXCP06_ILLOP);
                 }
                 *ptb = tb;
-                tb->size = code_size;
-                tb->cs_base = (unsigned long)cs_base;
-                tb->flags = flags;
                 tb->hash_next = NULL;
                 tb_link(tb);
                 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+                spin_unlock(&tb_lock);
             }
 #ifdef DEBUG_EXEC
            if (loglevel) {
@@ -252,13 +240,14 @@ int cpu_x86_exec(CPUX86State *env1)
                        lookup_symbol((void *)tb->pc));
            }
 #endif
-
             /* see if we can patch the calling TB */
             if (T0 != 0 && !(env->eflags & TF_MASK)) {
+                spin_lock(&tb_lock);
                 tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
+                spin_unlock(&tb_lock);
             }
+
             tc_ptr = tb->tc_ptr;
-            spin_unlock(&tb_lock);
 
             /* execute the generated code */
             gen_func = (void *)tc_ptr;
@@ -322,7 +311,43 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
 
     saved_env = env;
     env = s;
-    load_seg(seg_reg, selector);
+    if (env->eflags & VM_MASK) {
+        SegmentCache *sc;
+        selector &= 0xffff;
+        sc = &env->seg_cache[seg_reg];
+        /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
+           so we must load them here */
+        sc->base = (void *)(selector << 4);
+        sc->limit = 0xffff;
+        sc->seg_32bit = 0;
+        env->segs[seg_reg] = selector;
+    } else {
+        load_seg(seg_reg, selector, 0);
+    }
+    env = saved_env;
+}
+
+void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
+{
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = s;
+    
+    helper_fsave(ptr, data32);
+
+    env = saved_env;
+}
+
+void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
+{
+    CPUX86State *saved_env;
+
+    saved_env = env;
+    env = s;
+    
+    helper_frstor(ptr, data32);
+
     env = saved_env;
 }
 
@@ -345,6 +370,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
                                     int is_write, sigset_t *old_set)
 {
+    TranslationBlock *tb;
+    int ret;
+    uint32_t found_pc;
+    
 #if defined(DEBUG_SIGNAL)
     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", 
            pc, address, is_write, *(unsigned long *)old_set);
@@ -353,16 +382,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
     if (is_write && page_unprotect(address)) {
         return 1;
     }
-    if (pc >= (unsigned long)code_gen_buffer &&
-        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
+    tb = tb_find_pc(pc);
+    if (tb) {
         /* the PC is inside the translated code. It means that we have
            a virtual CPU fault */
+        ret = cpu_x86_search_pc(tb, &found_pc, pc);
+        if (ret < 0)
+            return 0;
+        env->eip = found_pc - tb->cs_base;
+        env->cr2 = address;
         /* we restore the process signal mask as the sigreturn should
-           do it */
+           do it (XXX: use sigsetjmp) */
         sigprocmask(SIG_SETMASK, old_set, NULL);
-        /* XXX: need to compute virtual pc position by retranslating
-           code. The rest of the CPU state should be correct. */
-        env->cr2 = address;
         raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
         /* never comes here */
         return 1;