* 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)
{
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
- int code_gen_size, ret;
+ int code_gen_size, ret, interrupt_request;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
env->VF = (psr << 3) & 0x80000000;
env->cpsr = psr & ~0xf0000000;
}
+#elif defined(TARGET_SPARC)
#else
#error unsupported target CPU
#endif
- env->interrupt_request = 0;
+ env->exception_index = -1;
/* prepare setjmp context for exception handling */
- if (setjmp(env->jmp_env) == 0) {
- T0 = 0; /* force lookup of first TB */
- for(;;) {
+ for(;;) {
+ if (setjmp(env->jmp_env) == 0) {
+ /* if an exception is pending, we execute it here */
+ if (env->exception_index >= 0) {
+ if (env->exception_index >= EXCP_INTERRUPT) {
+ /* exit request from the cpu execution loop */
+ ret = env->exception_index;
+ break;
+ } else if (env->user_mode_only) {
+ /* if user mode only, we simulate a fake exception
+ which will be hanlded outside the cpu execution
+ loop */
+#if defined(TARGET_I386)
+ do_interrupt_user(env->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip);
+#endif
+ ret = env->exception_index;
+ break;
+ } else {
+#if defined(TARGET_I386)
+ /* simulate a real cpu exception. On i386, it can
+ trigger new exceptions, but we do not handle
+ double or triple faults yet. */
+ do_interrupt(env->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip, 0);
+#endif
+ }
+ env->exception_index = -1;
+ }
+ T0 = 0; /* force lookup of first TB */
+ for(;;) {
#ifdef __sparc__
- /* g1 can be modified by some libc? functions */
- tmp_T0 = T0;
+ /* g1 can be modified by some libc? functions */
+ tmp_T0 = T0;
#endif
- if (env->interrupt_request) {
- env->exception_index = EXCP_INTERRUPT;
- cpu_loop_exit();
- }
+ interrupt_request = env->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->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, 1);
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ /* ensure that no TB jump will be modified as
+ the program flow was changed */
+#ifdef __sparc__
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ }
+#endif
+ if (interrupt_request & CPU_INTERRUPT_EXIT) {
+ env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
+ env->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit();
+ }
+ }
#ifdef DEBUG_EXEC
- if (loglevel) {
+ if (loglevel) {
#if defined(TARGET_I386)
- /* restore flags in standard format */
- env->regs[R_EAX] = EAX;
- env->regs[R_EBX] = EBX;
- env->regs[R_ECX] = ECX;
- env->regs[R_EDX] = EDX;
- env->regs[R_ESI] = ESI;
- env->regs[R_EDI] = EDI;
- env->regs[R_EBP] = EBP;
- env->regs[R_ESP] = ESP;
- env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
- cpu_x86_dump_state(env, logfile, 0);
- env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ /* restore flags in standard format */
+ env->regs[R_EAX] = EAX;
+ env->regs[R_EBX] = EBX;
+ env->regs[R_ECX] = ECX;
+ env->regs[R_EDX] = EDX;
+ env->regs[R_ESI] = ESI;
+ env->regs[R_EDI] = EDI;
+ env->regs[R_EBP] = EBP;
+ env->regs[R_ESP] = ESP;
+ env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
+ 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)
- cpu_arm_dump_state(env, logfile, 0);
+ 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->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
- flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
- flags |= (((unsigned long)env->seg_cache[R_DS].base |
- (unsigned long)env->seg_cache[R_ES].base |
- (unsigned long)env->seg_cache[R_SS].base) != 0) <<
- GEN_FLAG_ADDSEG_SHIFT;
- if (!(env->eflags & VM_MASK)) {
- flags |= (env->segs[R_CS] & 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));
- cs_base = env->seg_cache[R_CS].base;
- pc = cs_base + env->eip;
+ 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];
+ 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
- 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);
+ tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
+ flags);
if (!tb) {
- /* flush must be done */
- tb_flush();
- /* cannot fail at this point */
+ spin_lock(&tb_lock);
+ /* if no translated code available, then translate it now */
tb = tb_alloc((unsigned long)pc);
- /* don't forget to invalidate previous TB info */
- ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
- T0 = 0;
- }
- tc_ptr = code_gen_ptr;
- 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 */
+ if (!tb) {
+ /* flush must be done */
+ tb_flush();
+ /* cannot fail at this point */
+ tb = tb_alloc((unsigned long)pc);
+ /* don't forget to invalidate previous TB info */
+ ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
+ T0 = 0;
+ }
+ tc_ptr = code_gen_ptr;
+ tb->tc_ptr = tc_ptr;
+ tb->cs_base = (unsigned long)cs_base;
+ tb->flags = flags;
+ cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
+ *ptb = tb;
+ 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);
- raise_exception(EXCP06_ILLOP);
}
-#endif
- *ptb = tb;
- 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) {
- fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
- (long)tb->tc_ptr, (long)tb->pc,
- lookup_symbol((void *)tb->pc));
- }
+ if (loglevel) {
+ fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
+ (long)tb->tc_ptr, (long)tb->pc,
+ lookup_symbol((void *)tb->pc));
+ }
#endif
#ifdef __sparc__
- T0 = tmp_T0;
+ 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
- ) {
- spin_lock(&tb_lock);
- tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
- spin_unlock(&tb_lock);
- }
- tc_ptr = tb->tc_ptr;
-
- /* execute the generated code */
- gen_func = (void *)tc_ptr;
+ /* 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);
+ }
+ tc_ptr = tb->tc_ptr;
+ env->current_tb = tb;
+ /* execute the generated code */
+ gen_func = (void *)tc_ptr;
#if defined(__sparc__)
- __asm__ __volatile__("call %0\n\t"
- "mov %%o7,%%i0"
- : /* no outputs */
- : "r" (gen_func)
- : "i0", "i1", "i2", "i3", "i4", "i5");
+ __asm__ __volatile__("call %0\n\t"
+ "mov %%o7,%%i0"
+ : /* no outputs */
+ : "r" (gen_func)
+ : "i0", "i1", "i2", "i3", "i4", "i5");
#elif defined(__arm__)
- asm volatile ("mov pc, %0\n\t"
- ".global exec_loop\n\t"
- "exec_loop:\n\t"
- : /* no outputs */
- : "r" (gen_func)
- : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
+ asm volatile ("mov pc, %0\n\t"
+ ".global exec_loop\n\t"
+ "exec_loop:\n\t"
+ : /* no outputs */
+ : "r" (gen_func)
+ : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
#else
- gen_func();
+ 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 {
}
- }
- ret = env->exception_index;
+ } /* for(;;) */
+
#if defined(TARGET_I386)
/* restore flags in standard format */
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
return ret;
}
-void cpu_interrupt(CPUState *s)
-{
- s->interrupt_request = 1;
-}
-
-
#if defined(TARGET_I386)
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->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;
+ cpu_x86_load_seg_cache(env, seg_reg, selector,
+ (uint8_t *)(selector << 4), 0xffff, 0);
} else {
load_seg(seg_reg, selector, 0);
}
#include <signal.h>
#include <sys/ucontext.h>
+#if defined(TARGET_I386)
+
/* 'pc' is the host PC at which the exception was raised. 'address' is
the effective address of the memory exception. 'is_write' is 1 if a
write caused the exception and otherwise 0'. 'old_set' is the
{
TranslationBlock *tb;
int ret;
- uint32_t found_pc;
-
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
- printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
+ printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
return 1;
}
+ /* see if it is an MMU fault */
+ ret = cpu_x86_handle_mmu_fault(env, address, is_write);
+ if (ret < 0)
+ return 0; /* not an MMU fault */
+ if (ret == 0)
+ return 1; /* the MMU fault was handled without causing real CPU fault */
+ /* now we have a real cpu fault */
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_search_pc(tb, &found_pc, pc);
- if (ret < 0)
- return 0;
-#if defined(TARGET_I386)
- env->eip = found_pc - tb->cs_base;
- env->cr2 = address;
+ 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);
+#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, 4 | (is_write << 1));
+ 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;
+}
+
#elif defined(TARGET_ARM)
- env->regs[15] = found_pc;
- /* XXX: do more */
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set)
+{
+ /* 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
- /* never comes here */
- return 1;
- } else {
- return 0;
- }
-}
#if defined(__i386__)
&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 CPU specific signal handler needed
+#error host CPU specific signal handler needed
#endif