/* prepare setjmp context for exception handling */
for(;;) {
if (setjmp(env->jmp_env) == 0) {
+ env->current_tb = NULL;
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
if (env->exception_index >= EXCP_INTERRUPT) {
env->exception_is_int,
env->error_code,
env->exception_next_eip, 0);
+#elif defined(TARGET_PPC)
+ do_interrupt(env);
#endif
}
env->exception_index = -1;
T0 = 0;
#endif
}
+#elif defined(TARGET_PPC)
+ if ((interrupt_request & CPU_INTERRUPT_HARD)) {
+ do_queue_exception(EXCP_EXTERNAL);
+ if (check_exception_state(env))
+ do_interrupt(env);
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ }
+#endif
+ if (interrupt_request & CPU_INTERRUPT_EXITTB) {
+ env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
+ /* ensure that no TB jump will be modified as
+ the program flow was changed */
+#ifdef __sparc__
+ tmp_T0 = 0;
+#else
+ T0 = 0;
#endif
+ }
if (interrupt_request & CPU_INTERRUPT_EXIT) {
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
env->exception_index = EXCP_INTERRUPT;
pc = (uint8_t *)env->regs[15];
#elif defined(TARGET_SPARC)
flags = 0;
- cs_base = env->npc;
+ cs_base = (uint8_t *)env->npc;
pc = (uint8_t *) env->pc;
#elif defined(TARGET_PPC)
flags = 0;
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
flags);
if (!tb) {
+ TranslationBlock **ptb1;
+ unsigned int h;
+ target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
+
+
spin_lock(&tb_lock);
+
+ tb_invalidated_flag = 0;
+
+ /* find translated block using physical mappings */
+ phys_pc = get_phys_addr_code(env, (unsigned long)pc);
+ phys_page1 = phys_pc & TARGET_PAGE_MASK;
+ phys_page2 = -1;
+ h = tb_phys_hash_func(phys_pc);
+ ptb1 = &tb_phys_hash[h];
+ for(;;) {
+ tb = *ptb1;
+ if (!tb)
+ goto not_found;
+ if (tb->pc == (unsigned long)pc &&
+ tb->page_addr[0] == phys_page1 &&
+ tb->cs_base == (unsigned long)cs_base &&
+ tb->flags == flags) {
+ /* check next page if needed */
+ if (tb->page_addr[1] != -1) {
+ virt_page2 = ((unsigned long)pc & TARGET_PAGE_MASK) +
+ TARGET_PAGE_SIZE;
+ phys_page2 = get_phys_addr_code(env, virt_page2);
+ if (tb->page_addr[1] == phys_page2)
+ goto found;
+ } else {
+ goto found;
+ }
+ }
+ ptb1 = &tb->phys_hash_next;
+ }
+ not_found:
/* if no translated code available, then translate it now */
tb = tb_alloc((unsigned long)pc);
if (!tb) {
tb->tc_ptr = tc_ptr;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
- tb_invalidated_flag = 0;
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
+ code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+
+ /* check next page if needed */
+ virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
+ phys_page2 = -1;
+ if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
+ phys_page2 = get_phys_addr_code(env, virt_page2);
+ }
+ tb_link_phys(tb, phys_pc, phys_page2);
+
+ found:
if (tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
ptb = &(*ptb)->hash_next;
T0 = 0;
}
+ /* we add the TB in the virtual pc hash table */
*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
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. */
- if (T0 != 0) {
+ if (T0 != 0
+#if defined(TARGET_I386) && defined(USE_CODE_COPY)
+ && (tb->cflags & CF_CODE_COPY) ==
+ (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
+#endif
+ ) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
+#if defined(USE_CODE_COPY)
+ /* propagates the FP use info */
+ ((TranslationBlock *)(T0 & ~3))->cflags |=
+ (tb->cflags & CF_FP_USED);
+#endif
spin_unlock(&tb_lock);
}
tc_ptr = tb->tc_ptr;
: /* no outputs */
: "r" (gen_func)
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
+#elif defined(TARGET_I386) && defined(USE_CODE_COPY)
+{
+ if (!(tb->cflags & CF_CODE_COPY)) {
+ if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) {
+ save_native_fp_state(env);
+ }
+ gen_func();
+ } else {
+ if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) {
+ restore_native_fp_state(env);
+ }
+ /* we work with native eflags */
+ CC_SRC = cc_table[CC_OP].compute_all();
+ CC_OP = CC_OP_EFLAGS;
+ asm(".globl exec_loop\n"
+ "\n"
+ "debug1:\n"
+ " pushl %%ebp\n"
+ " fs movl %10, %9\n"
+ " fs movl %11, %%eax\n"
+ " andl $0x400, %%eax\n"
+ " fs orl %8, %%eax\n"
+ " pushl %%eax\n"
+ " popf\n"
+ " fs movl %%esp, %12\n"
+ " fs movl %0, %%eax\n"
+ " fs movl %1, %%ecx\n"
+ " fs movl %2, %%edx\n"
+ " fs movl %3, %%ebx\n"
+ " fs movl %4, %%esp\n"
+ " fs movl %5, %%ebp\n"
+ " fs movl %6, %%esi\n"
+ " fs movl %7, %%edi\n"
+ " fs jmp *%9\n"
+ "exec_loop:\n"
+ " fs movl %%esp, %4\n"
+ " fs movl %12, %%esp\n"
+ " fs movl %%eax, %0\n"
+ " fs movl %%ecx, %1\n"
+ " fs movl %%edx, %2\n"
+ " fs movl %%ebx, %3\n"
+ " fs movl %%ebp, %5\n"
+ " fs movl %%esi, %6\n"
+ " fs movl %%edi, %7\n"
+ " pushf\n"
+ " popl %%eax\n"
+ " movl %%eax, %%ecx\n"
+ " andl $0x400, %%ecx\n"
+ " shrl $9, %%ecx\n"
+ " andl $0x8d5, %%eax\n"
+ " fs movl %%eax, %8\n"
+ " movl $1, %%eax\n"
+ " subl %%ecx, %%eax\n"
+ " fs movl %%eax, %11\n"
+ " fs movl %9, %%ebx\n" /* get T0 value */
+ " popl %%ebp\n"
+ :
+ : "m" (*(uint8_t *)offsetof(CPUState, regs[0])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[1])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[2])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[3])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[4])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[5])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[6])),
+ "m" (*(uint8_t *)offsetof(CPUState, regs[7])),
+ "m" (*(uint8_t *)offsetof(CPUState, cc_src)),
+ "m" (*(uint8_t *)offsetof(CPUState, tmp0)),
+ "a" (gen_func),
+ "m" (*(uint8_t *)offsetof(CPUState, df)),
+ "m" (*(uint8_t *)offsetof(CPUState, saved_esp))
+ : "%ecx", "%edx"
+ );
+ }
+}
#else
gen_func();
#endif
#if defined(TARGET_I386)
+#if defined(USE_CODE_COPY)
+ if (env->native_fp_regs) {
+ save_native_fp_state(env);
+ }
+#endif
/* restore flags in standard format */
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
write caused the exception and otherwise 0'. 'old_set' is the
signal set which should be restored */
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
- int is_write, sigset_t *old_set)
+ int is_write, sigset_t *old_set,
+ void *puc)
{
TranslationBlock *tb;
int ret;
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 w=%d oldset=0x%08lx\n",
- pc, address, is_write, *(unsigned long *)old_set);
+ qemu_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)) {
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, pc, puc);
}
if (ret == 1) {
#if 0
#elif defined(TARGET_ARM)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
- int is_write, sigset_t *old_set)
+ int is_write, sigset_t *old_set,
+ void *puc)
{
/* 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)
+ int is_write, sigset_t *old_set,
+ void *puc)
{
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
}
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
- int is_write, sigset_t *old_set)
+ int is_write, sigset_t *old_set,
+ void *puc)
{
TranslationBlock *tb;
+ int ret;
-#if 0
+#if 1
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#endif
return 1;
}
+ /* see if it is an MMU fault */
+ ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
+ 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 */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, pc, puc);
}
+ 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: NIP=0x%08x error=0x%x %p\n",
+ env->nip, env->error_code, tb);
#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(EXCP_PROGRAM, env->error_code);
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ do_queue_exception_err(env->exception_index, env->error_code);
+ } else {
+ /* activate soft MMU for this block */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ cpu_loop_exit();
+ }
/* never comes here */
return 1;
}
#if defined(__i386__)
+#if defined(USE_CODE_COPY)
+static void cpu_send_trap(unsigned long pc, int trap,
+ struct ucontext *uc)
+{
+ TranslationBlock *tb;
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
+ /* 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 */
+ cpu_restore_state(tb, env, pc, uc);
+ }
+ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ raise_exception_err(trap, env->error_code);
+}
+#endif
+
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
-
+ int trapno;
+
#ifndef REG_EIP
/* for glibc 2.1 */
#define REG_EIP EIP
#define REG_TRAPNO TRAPNO
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
+ trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
+#if defined(TARGET_I386) && defined(USE_CODE_COPY)
+ if (trapno == 0x00 || trapno == 0x05) {
+ /* send division by zero or bound exception */
+ cpu_send_trap(pc, trapno, uc);
+ return 1;
+ } else
+#endif
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ trapno == 0xe ?
+ (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
+ &uc->uc_sigmask, puc);
+}
+
+#elif defined(__x86_64__)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+
+ pc = uc->uc_mcontext.gregs[REG_RIP];
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
- &uc->uc_sigmask);
+ &uc->uc_sigmask, puc);
}
#elif defined(__powerpc)
is_write = 1;
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- is_write, &uc->uc_sigmask);
+ is_write, &uc->uc_sigmask, puc);
}
#elif defined(__alpha__)
}
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- is_write, &uc->uc_sigmask);
+ is_write, &uc->uc_sigmask, puc);
}
#elif defined(__sparc__)
}
}
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- is_write, sigmask);
+ is_write, sigmask, NULL);
}
#elif defined(__arm__)
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
- &uc->uc_sigmask);
+ &uc->uc_sigmask, puc);
}
#else