X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;ds=sidebyside;f=cpu-exec.c;h=8a585c1066e11e960b7d07d7b3871ef976d4250d;hb=8dbca8dd8a81d7f1afd6ef23b418c8f9d292b65d;hp=94c35e31b579d0568374d65b9f38f354d5744954;hpb=b7bcbe9524c05d5134136cce2d5d2a09c09a4f83;p=qemu diff --git a/cpu-exec.c b/cpu-exec.c index 94c35e3..8a585c1 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1,7 +1,7 @@ /* * i386 emulator main execution loop * - * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -47,6 +47,9 @@ void cpu_loop_exit(void) longjmp(env->jmp_env, 1); } #endif +#ifndef TARGET_SPARC +#define reg_T2 +#endif /* exit the current TB from a signal handler. The host registers are restored in a state compatible with the CPU emulator @@ -70,12 +73,157 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) longjmp(env->jmp_env, 1); } + +static TranslationBlock *tb_find_slow(target_ulong pc, + target_ulong cs_base, + unsigned int flags) +{ + TranslationBlock *tb, **ptb1; + int code_gen_size; + unsigned int h; + target_ulong phys_pc, phys_page1, phys_page2, virt_page2; + uint8_t *tc_ptr; + + spin_lock(&tb_lock); + + tb_invalidated_flag = 0; + + regs_to_env(); /* XXX: do it just before cpu_gen_code() */ + + /* find translated block using physical mappings */ + phys_pc = get_phys_addr_code(env, 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 == pc && + tb->page_addr[0] == phys_page1 && + tb->cs_base == cs_base && + tb->flags == flags) { + /* check next page if needed */ + if (tb->page_addr[1] != -1) { + virt_page2 = (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(pc); + if (!tb) { + /* flush must be done */ + tb_flush(env); + /* cannot fail at this point */ + tb = tb_alloc(pc); + /* don't forget to invalidate previous TB info */ + tb_invalidated_flag = 1; + } + tc_ptr = code_gen_ptr; + tb->tc_ptr = tc_ptr; + tb->cs_base = cs_base; + tb->flags = flags; + 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 = (pc + tb->size - 1) & TARGET_PAGE_MASK; + phys_page2 = -1; + if ((pc & TARGET_PAGE_MASK) != virt_page2) { + phys_page2 = get_phys_addr_code(env, virt_page2); + } + tb_link_phys(tb, phys_pc, phys_page2); + + found: + /* we add the TB in the virtual pc hash table */ + env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; + spin_unlock(&tb_lock); + return tb; +} + +static inline TranslationBlock *tb_find_fast(void) +{ + TranslationBlock *tb; + target_ulong cs_base, pc; + unsigned int flags; + + /* 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->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 = env->thumb | (env->vfp.vec_len << 1) + | (env->vfp.vec_stride << 4); + if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) + flags |= (1 << 6); + if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) + flags |= (1 << 7); + cs_base = 0; + pc = env->regs[15]; +#elif defined(TARGET_SPARC) +#ifdef TARGET_SPARC64 + flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); +#else + flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); +#endif + cs_base = env->npc; + pc = env->pc; +#elif defined(TARGET_PPC) + flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | + (msr_se << MSR_SE) | (msr_le << MSR_LE); + cs_base = 0; + pc = env->nip; +#elif defined(TARGET_MIPS) + flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK); + cs_base = 0; + pc = env->PC; +#elif defined(TARGET_SH4) + flags = env->sr & (SR_MD | SR_RB); + cs_base = 0; /* XXXXX */ + pc = env->pc; +#else +#error unsupported CPU +#endif + tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; + if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base || + tb->flags != flags, 0)) { + tb = tb_find_slow(pc, cs_base, flags); + /* Note: we do it here to avoid a gcc bug on Mac OS X when + doing it in tb_find_slow */ + if (tb_invalidated_flag) { + /* as some TB could have been invalidated because + of memory exceptions while generating the code, we + must recompute the hash index here */ + T0 = 0; + } + } + return tb; +} + + /* main execution loop */ int cpu_exec(CPUState *env1) { - int saved_T0, saved_T1, saved_T2; + int saved_T0, saved_T1; +#if defined(reg_T2) + int saved_T2; +#endif CPUState *saved_env; +#if defined(TARGET_I386) #ifdef reg_EAX int saved_EAX; #endif @@ -100,22 +248,81 @@ int cpu_exec(CPUState *env1) #ifdef reg_EDI int saved_EDI; #endif +#elif defined(TARGET_SPARC) +#if defined(reg_REGWPTR) + uint32_t *saved_regwptr; +#endif +#endif #ifdef __sparc__ int saved_i7, tmp_T0; #endif - int code_gen_size, ret, interrupt_request; + int ret, interrupt_request; void (*gen_func)(void); - TranslationBlock *tb, **ptb; - target_ulong cs_base, pc; + TranslationBlock *tb; uint8_t *tc_ptr; - unsigned int flags; + +#if defined(TARGET_I386) + /* handle exit of HALTED state */ + if (env1->hflags & HF_HALTED_MASK) { + /* disable halt condition */ + if ((env1->interrupt_request & CPU_INTERRUPT_HARD) && + (env1->eflags & IF_MASK)) { + env1->hflags &= ~HF_HALTED_MASK; + } else { + return EXCP_HALTED; + } + } +#elif defined(TARGET_PPC) + if (env1->halted) { + if (env1->msr[MSR_EE] && + (env1->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) { + env1->halted = 0; + } else { + return EXCP_HALTED; + } + } +#elif defined(TARGET_SPARC) + if (env1->halted) { + if ((env1->interrupt_request & CPU_INTERRUPT_HARD) && + (env1->psret != 0)) { + env1->halted = 0; + } else { + return EXCP_HALTED; + } + } +#elif defined(TARGET_ARM) + if (env1->halted) { + /* An interrupt wakes the CPU even if the I and F CPSR bits are + set. */ + if (env1->interrupt_request + & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD)) { + env1->halted = 0; + } else { + return EXCP_HALTED; + } + } +#elif defined(TARGET_MIPS) + if (env1->halted) { + if (env1->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) { + env1->halted = 0; + } else { + return EXCP_HALTED; + } + } +#endif + + cpu_single_env = env1; /* first we save global registers */ saved_env = env; env = env1; saved_T0 = T0; saved_T1 = T1; +#if defined(reg_T2) saved_T2 = T2; +#endif #ifdef __sparc__ /* we also save i7 because longjmp may not restore it */ asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); @@ -154,17 +361,14 @@ int cpu_exec(CPUState *env1) CC_OP = CC_OP_EFLAGS; env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_ARM) - { - unsigned int psr; - psr = env->cpsr; - env->CF = (psr >> 29) & 1; - env->NZF = (psr & 0xc0000000) ^ 0x40000000; - env->VF = (psr << 3) & 0x80000000; - env->QF = (psr >> 27) & 1; - env->cpsr = psr & ~CACHED_CPSR_BITS; - } #elif defined(TARGET_SPARC) +#if defined(reg_REGWPTR) + saved_regwptr = REGWPTR; +#endif #elif defined(TARGET_PPC) +#elif defined(TARGET_MIPS) +#elif defined(TARGET_SH4) + /* XXXXX */ #else #error unsupported target CPU #endif @@ -203,8 +407,14 @@ int cpu_exec(CPUState *env1) env->exception_next_eip, 0); #elif defined(TARGET_PPC) do_interrupt(env); +#elif defined(TARGET_MIPS) + do_interrupt(env); #elif defined(TARGET_SPARC) do_interrupt(env->exception_index); +#elif defined(TARGET_ARM) + do_interrupt(env); +#elif defined(TARGET_SH4) + do_interrupt(env); #endif } env->exception_index = -1; @@ -270,30 +480,88 @@ int cpu_exec(CPUState *env1) } #endif if (msr_ee != 0) { - if ((interrupt_request & CPU_INTERRUPT_HARD)) { + if ((interrupt_request & CPU_INTERRUPT_HARD)) { /* Raise it */ env->exception_index = EXCP_EXTERNAL; env->error_code = 0; do_interrupt(env); - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { - /* Raise it */ - env->exception_index = EXCP_DECR; - env->error_code = 0; - do_interrupt(env); + env->interrupt_request &= ~CPU_INTERRUPT_HARD; +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif + } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { + /* Raise it */ + env->exception_index = EXCP_DECR; + env->error_code = 0; + do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; - } +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif + } } -#elif defined(TARGET_SPARC) - if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(env->interrupt_index); +#elif defined(TARGET_MIPS) + if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->CP0_Status & (1 << CP0St_IE)) && + (env->CP0_Status & env->CP0_Cause & 0x0000FF00) && + !(env->hflags & MIPS_HFLAG_EXL) && + !(env->hflags & MIPS_HFLAG_ERL) && + !(env->hflags & MIPS_HFLAG_DM)) { + /* Raise it */ + env->exception_index = EXCP_EXT_INTERRUPT; + env->error_code = 0; + do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif + } +#elif defined(TARGET_SPARC) + if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->psret != 0)) { + int pil = env->interrupt_index & 15; + int type = env->interrupt_index & 0xf0; + + if (((type == TT_EXTINT) && + (pil == 15 || pil > env->psrpil)) || + type != TT_EXTINT) { + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + do_interrupt(env->interrupt_index); + env->interrupt_index = 0; +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif + } } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; - } + } else if (interrupt_request & CPU_INTERRUPT_HALT) { + env1->halted = 1; + return EXCP_HALTED; + } +#elif defined(TARGET_ARM) + if (interrupt_request & CPU_INTERRUPT_FIQ + && !(env->uncached_cpsr & CPSR_F)) { + env->exception_index = EXCP_FIQ; + do_interrupt(env); + } + if (interrupt_request & CPU_INTERRUPT_HARD + && !(env->uncached_cpsr & CPSR_I)) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + } +#elif defined(TARGET_SH4) + /* XXXXX */ #endif - if (interrupt_request & CPU_INTERRUPT_EXITTB) { + if (env->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 */ @@ -310,141 +578,54 @@ int cpu_exec(CPUState *env1) } } #ifdef DEBUG_EXEC - if ((loglevel & CPU_LOG_EXEC)) { + if ((loglevel & CPU_LOG_TB_CPU)) { #if defined(TARGET_I386) /* restore flags in standard format */ +#ifdef reg_EAX env->regs[R_EAX] = EAX; +#endif +#ifdef reg_EBX env->regs[R_EBX] = EBX; +#endif +#ifdef reg_ECX env->regs[R_ECX] = ECX; +#endif +#ifdef reg_EDX env->regs[R_EDX] = EDX; +#endif +#ifdef reg_ESI env->regs[R_ESI] = ESI; +#endif +#ifdef reg_EDI env->regs[R_EDI] = EDI; +#endif +#ifdef reg_EBP env->regs[R_EBP] = EBP; +#endif +#ifdef reg_ESP env->regs[R_ESP] = ESP; +#endif env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); cpu_dump_state(env, logfile, fprintf, 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_dump_state(env, logfile, fprintf, 0); - env->cpsr &= ~CACHED_CPSR_BITS; #elif defined(TARGET_SPARC) - cpu_dump_state (env, logfile, fprintf, 0); + REGWPTR = env->regbase + (env->cwp * 16); + env->regwptr = REGWPTR; + cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_PPC) cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_MIPS) + cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_SH4) + cpu_dump_state(env, logfile, fprintf, 0); #else #error unsupported target CPU #endif } #endif - /* 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->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 = env->thumb | (env->vfp.vec_len << 1) - | (env->vfp.vec_stride << 4); - cs_base = 0; - pc = env->regs[15]; -#elif defined(TARGET_SPARC) - flags = 0; - cs_base = env->npc; - pc = env->pc; -#elif defined(TARGET_PPC) - flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_se << MSR_SE); - cs_base = 0; - pc = env->nip; -#else -#error unsupported CPU -#endif - tb = tb_find(&ptb, pc, 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; - - regs_to_env(); /* XXX: do it just before cpu_gen_code() */ - - /* find translated block using physical mappings */ - phys_pc = get_phys_addr_code(env, 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 == pc && - tb->page_addr[0] == phys_page1 && - tb->cs_base == cs_base && - tb->flags == flags) { - /* check next page if needed */ - if (tb->page_addr[1] != -1) { - virt_page2 = (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(pc); - if (!tb) { - /* flush must be done */ - tb_flush(env); - /* cannot fail at this point */ - tb = tb_alloc(pc); - /* don't forget to invalidate previous TB info */ - ptb = &tb_hash[tb_hash_func(pc)]; - T0 = 0; - } - tc_ptr = code_gen_ptr; - tb->tc_ptr = tc_ptr; - tb->cs_base = cs_base; - tb->flags = flags; - 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 = (pc + tb->size - 1) & TARGET_PAGE_MASK; - phys_page2 = -1; - if ((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 - must recompute the hash index here */ - ptb = &tb_hash[tb_hash_func(pc)]; - while (*ptb != NULL) - 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); - spin_unlock(&tb_lock); - } + tb = tb_find_fast(); #ifdef DEBUG_EXEC if ((loglevel & CPU_LOG_EXEC)) { fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", @@ -455,9 +636,15 @@ int cpu_exec(CPUState *env1) #ifdef __sparc__ T0 = tmp_T0; #endif - /* see if we can patch the calling TB. */ + /* see if we can patch the calling TB. When the TB + spans two pages, we cannot safely do a direct + jump. */ { - if (T0 != 0 + if (T0 != 0 && +#if USE_KQEMU + (env->kqemu_enabled != 2) && +#endif + tb->page_addr[1] == -1 #if defined(TARGET_I386) && defined(USE_CODE_COPY) && (tb->cflags & CF_CODE_COPY) == (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY) @@ -564,6 +751,15 @@ int cpu_exec(CPUState *env1) ); } } +#elif defined(__ia64) + struct fptr { + void *ip; + void *gp; + } fp; + + fp.ip = tc_ptr; + fp.gp = code_gen_buffer + 2 * (1 << 20); + (*(void (*)(void)) &fp)(); #else gen_func(); #endif @@ -577,6 +773,13 @@ int cpu_exec(CPUState *env1) T0 = 0; } #endif +#if defined(USE_KQEMU) +#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000) + if (kqemu_is_ok(env) && + (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) { + cpu_loop_exit(); + } +#endif } } else { env_to_regs(); @@ -619,10 +822,15 @@ int cpu_exec(CPUState *env1) EDI = saved_EDI; #endif #elif defined(TARGET_ARM) - env->cpsr = compute_cpsr(); /* XXX: Save/restore host fpu exception state?. */ #elif defined(TARGET_SPARC) +#if defined(reg_REGWPTR) + REGWPTR = saved_regwptr; +#endif #elif defined(TARGET_PPC) +#elif defined(TARGET_MIPS) +#elif defined(TARGET_SH4) + /* XXXXX */ #else #error unsupported target CPU #endif @@ -631,8 +839,12 @@ int cpu_exec(CPUState *env1) #endif T0 = saved_T0; T1 = saved_T1; +#if defined(reg_T2) T2 = saved_T2; +#endif env = saved_env; + /* fail safe : never use cpu_single_env outside cpu_exec() */ + cpu_single_env = NULL; return ret; } @@ -715,7 +927,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } @@ -741,7 +953,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* 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); + raise_exception_err(env->exception_index, env->error_code); } else { /* activate soft MMU for this block */ env->hflags |= HF_SOFTMMU_MASK; @@ -766,7 +978,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } /* see if it is an MMU fault */ @@ -802,7 +1014,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } /* see if it is an MMU fault */ @@ -838,7 +1050,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } @@ -872,6 +1084,106 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* never comes here */ return 1; } + +#elif defined (TARGET_MIPS) +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + 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); +#endif + /* XXX: locking issue */ + if (is_write && page_unprotect(h2g(address), pc, puc)) { + return 1; + } + + /* see if it is an MMU fault */ + ret = cpu_mips_handle_mmu_fault(env, address, is_write, 1, 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, puc); + } + if (ret == 1) { +#if 0 + 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); + do_raise_exception_err(env->exception_index, env->error_code); + } else { + /* activate soft MMU for this block */ + cpu_resume_from_signal(env, puc); + } + /* never comes here */ + return 1; +} + +#elif defined (TARGET_SH4) +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + 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); +#endif + /* XXX: locking issue */ + if (is_write && page_unprotect(h2g(address), pc, puc)) { + return 1; + } + + /* see if it is an MMU fault */ + ret = cpu_sh4_handle_mmu_fault(env, address, is_write, 1, 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, puc); + } + if (ret == 1) { +#if 0 + 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); + // do_raise_exception_err(env->exception_index, env->error_code); + } else { + /* activate soft MMU for this block */ + cpu_resume_from_signal(env, puc); + } + /* never comes here */ + return 1; +} #else #error unsupported target CPU #endif @@ -1109,6 +1421,56 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, &uc->uc_sigmask, puc); } +#elif defined(__ia64) + +#ifndef __ISR_VALID + /* This ought to be in ... */ +# define __ISR_VALID 1 +#endif + +int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) +{ + struct ucontext *uc = puc; + unsigned long ip; + int is_write = 0; + + ip = uc->uc_mcontext.sc_ip; + switch (host_signum) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGTRAP: + if (info->si_code && (info->si_segvflags & __ISR_VALID)) + /* ISR.W (write-access) is bit 33: */ + is_write = (info->si_isr >> 33) & 1; + break; + + default: + break; + } + return handle_cpu_signal(ip, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + +#elif defined(__s390__) + +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.psw.addr; + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask, puc); +} + #else #error host CPU specific signal handler needed