static link
[qemu] / cpu-exec.c
index ddbeb2c..956504d 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include "config.h"
-#ifdef TARGET_I386
-#include "exec-i386.h"
-#endif
-#ifdef TARGET_ARM
-#include "exec-arm.h"
-#endif
-
+#include "exec.h"
 #include "disas.h"
 
 //#define DEBUG_EXEC
 //#define DEBUG_SIGNAL
 
-#if defined(TARGET_ARM)
+#if defined(TARGET_ARM) || defined(TARGET_SPARC)
 /* XXX: unify with i386 target */
 void cpu_loop_exit(void)
 {
@@ -136,6 +130,7 @@ int cpu_exec(CPUState *env1)
         env->VF = (psr << 3) & 0x80000000;
         env->cpsr = psr & ~0xf0000000;
     }
+#elif defined(TARGET_SPARC)
 #else
 #error unsupported target CPU
 #endif
@@ -170,7 +165,7 @@ int cpu_exec(CPUState *env1)
                     do_interrupt(env->exception_index, 
                                  env->exception_is_int, 
                                  env->error_code, 
-                                 env->exception_next_eip);
+                                 env->exception_next_eip, 0);
 #endif
                 }
                 env->exception_index = -1;
@@ -182,17 +177,18 @@ int cpu_exec(CPUState *env1)
                 tmp_T0 = T0;
 #endif     
                 interrupt_request = env->interrupt_request;
-                if (interrupt_request) {
+                if (__builtin_expect(interrupt_request, 0)) {
 #if defined(TARGET_I386)
                     /* if hardware interrupt pending, we execute it */
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
-                        (env->eflags & IF_MASK)) {
+                        (env->eflags & IF_MASK) && 
+                        !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
                         int intno;
                         intno = cpu_x86_get_pic_interrupt(env);
                         if (loglevel) {
                             fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
                         }
-                        do_interrupt(intno, 0, 0, 0);
+                        do_interrupt(intno, 0, 0, 0, 1);
                         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
                         /* ensure that no TB jump will be modified as
                            the program flow was changed */
@@ -225,37 +221,36 @@ int cpu_exec(CPUState *env1)
                     cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
                     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
 #elif defined(TARGET_ARM)
+                    env->cpsr = compute_cpsr();
                     cpu_arm_dump_state(env, logfile, 0);
+                    env->cpsr &= ~0xf0000000;
+#elif defined(TARGET_SPARC)
+                    cpu_sparc_dump_state (env, logfile, 0);
 #else
 #error unsupported target CPU 
 #endif
                 }
 #endif
-                /* we compute the CPU state. We assume it will not
-                   change during the whole generated block. */
+                /* we record a subset of the CPU state. It will
+                   always be the same before a given translated block
+                   is executed. */
 #if defined(TARGET_I386)
-                flags = (env->segs[R_CS].flags & DESC_B_MASK)
-                    >> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT);
-                flags |= (env->segs[R_SS].flags & DESC_B_MASK)
-                    >> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT);
-                flags |= (((unsigned long)env->segs[R_DS].base | 
-                           (unsigned long)env->segs[R_ES].base |
-                           (unsigned long)env->segs[R_SS].base) != 0) << 
-                    GEN_FLAG_ADDSEG_SHIFT;
-                if (!(env->eflags & VM_MASK)) {
-                    flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT;
-                } else {
-                    /* NOTE: a dummy CPL is kept */
-                    flags |= (1 << GEN_FLAG_VM_SHIFT);
-                    flags |= (3 << GEN_FLAG_CPL_SHIFT);
-                }
-                flags |= (env->eflags & (IOPL_MASK | TF_MASK));
+                flags = env->hflags;
+                flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
                 cs_base = env->segs[R_CS].base;
                 pc = cs_base + env->eip;
 #elif defined(TARGET_ARM)
                 flags = 0;
                 cs_base = 0;
                 pc = (uint8_t *)env->regs[15];
+#elif defined(TARGET_SPARC)
+                               flags = 0;
+                               cs_base = 0;
+                               if (env->npc) {
+                                       env->pc = env->npc;
+                                       env->npc = 0;
+                               }
+                               pc = (uint8_t *) env->pc;
 #else
 #error unsupported CPU
 #endif
@@ -278,17 +273,8 @@ int cpu_exec(CPUState *env1)
                     tb->tc_ptr = tc_ptr;
                     tb->cs_base = (unsigned long)cs_base;
                     tb->flags = flags;
-                    ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
-#if defined(TARGET_I386)
-                    /* XXX: suppress that, this is incorrect */
-                    /* if invalid instruction, signal it */
-                    if (ret != 0) {
-                        /* NOTE: the tb is allocated but not linked, so we
-                           can leave it */
-                        spin_unlock(&tb_lock);
-                        raise_exception(EXCP06_ILLOP);
-                    }
-#endif
+                    /* XXX: an MMU exception can occur here */
+                    cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
                     *ptb = tb;
                     tb->hash_next = NULL;
                     tb_link(tb);
@@ -305,12 +291,8 @@ int cpu_exec(CPUState *env1)
 #ifdef __sparc__
                 T0 = tmp_T0;
 #endif     
-                /* see if we can patch the calling TB. XXX: remove TF test */
-                if (T0 != 0 
-#if defined(TARGET_I386)
-                    && !(env->eflags & TF_MASK)
-#endif
-                    ) {
+                /* see if we can patch the calling TB. */
+                if (T0 != 0) {
                     spin_lock(&tb_lock);
                     tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
                     spin_unlock(&tb_lock);
@@ -336,6 +318,15 @@ int cpu_exec(CPUState *env1)
                 gen_func();
 #endif
                 env->current_tb = NULL;
+                /* reset soft MMU for next block (it can currently
+                   only be set by a memory fault) */
+#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
+                if (env->hflags & HF_SOFTMMU_MASK) {
+                    env->hflags &= ~HF_SOFTMMU_MASK;
+                    /* do not allow linking to another block */
+                    T0 = 0;
+                }
+#endif
             }
         } else {
         }
@@ -372,12 +363,8 @@ int cpu_exec(CPUState *env1)
     EDI = saved_EDI;
 #endif
 #elif defined(TARGET_ARM)
-    {
-        int ZF;
-        ZF = (env->NZF == 0);
-        env->cpsr = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | 
-            (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
-    }
+    env->cpsr = compute_cpsr();
+#elif defined(TARGET_SPARC)
 #else
 #error unsupported target CPU
 #endif
@@ -399,16 +386,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
 
     saved_env = env;
     env = s;
-    if (env->eflags & VM_MASK) {
-        SegmentCache *sc;
+    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
         selector &= 0xffff;
-        sc = &env->segs[seg_reg];
-        /* NOTE: in VM86 mode, limit and flags are never reloaded,
-           so we must load them here */
-        sc->base = (void *)(selector << 4);
-        sc->limit = 0xffff;
-        sc->flags = 0;
-        sc->selector = selector;
+        cpu_x86_load_seg_cache(env, seg_reg, selector, 
+                               (uint8_t *)(selector << 4), 0xffff, 0);
     } else {
         load_seg(seg_reg, selector, 0);
     }
@@ -476,7 +457,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
         return 1;
     }
     /* see if it is an MMU fault */
-    ret = cpu_x86_handle_mmu_fault(env, address, is_write);
+    ret = cpu_x86_handle_mmu_fault(env, address, is_write, 
+                                   ((env->hflags & HF_CPL_MASK) == 3), 0);
     if (ret < 0)
         return 0; /* not an MMU fault */
     if (ret == 0)
@@ -488,14 +470,21 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
            a virtual CPU fault */
         cpu_restore_state(tb, env, pc);
     }
+    if (ret == 1) {
 #if 0
-    printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
-           env->eip, env->cr[2], env->error_code);
+        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
+               env->eip, env->cr[2], env->error_code);
 #endif
-    /* we restore the process signal mask as the sigreturn should
-       do it (XXX: use sigsetjmp) */
-    sigprocmask(SIG_SETMASK, old_set, NULL);
-    raise_exception_err(EXCP0E_PAGE, env->error_code);
+        /* we restore the process signal mask as the sigreturn should
+           do it (XXX: use sigsetjmp) */
+        sigprocmask(SIG_SETMASK, old_set, NULL);
+        raise_exception_err(EXCP0E_PAGE, env->error_code);
+    } else {
+        /* activate soft MMU for this block */
+        env->hflags |= HF_SOFTMMU_MASK;
+        sigprocmask(SIG_SETMASK, old_set, NULL);
+        cpu_loop_exit();
+    }
     /* never comes here */
     return 1;
 }
@@ -507,6 +496,12 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
     /* XXX: do more */
     return 0;
 }
+#elif defined(TARGET_SPARC)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+                                    int is_write, sigset_t *old_set)
+{
+       return 0;
+}
 #else
 #error unsupported target CPU
 #endif
@@ -635,6 +630,23 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
                              &uc->uc_sigmask);
 }
 
+#elif defined(__mc68000)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info, 
+                       void *puc)
+{
+    struct ucontext *uc = puc;
+    unsigned long pc;
+    int is_write;
+    
+    pc = uc->uc_mcontext.gregs[16];
+    /* XXX: compute is_write */
+    is_write = 0;
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
+                             is_write,
+                             &uc->uc_sigmask);
+}
+
 #else
 
 #error host CPU specific signal handler needed