--- qemu/cpu-exec.c 2018/04/24 17:57:07 1.1.1.11 +++ qemu/cpu-exec.c 2018/04/24 18:23:30 1.1.1.12 @@ -21,6 +21,7 @@ #include "disas.h" #include "tcg.h" #include "kvm.h" +#include "qemu-barrier.h" #if !defined(CONFIG_SOFTMMU) #undef EAX @@ -56,9 +57,7 @@ int qemu_cpu_has_work(CPUState *env) void cpu_loop_exit(void) { - /* NOTE: the register at this point must be saved by hand because - longjmp restore them */ - regs_to_env(); + env->current_tb = NULL; longjmp(env->jmp_env, 1); } @@ -83,7 +82,11 @@ void cpu_resume_from_signal(CPUState *en if (puc) { /* XXX: use siglongjmp ? */ #ifdef __linux__ +#ifdef __ia64 + sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL); +#else sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); +#endif #elif defined(__OpenBSD__) sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); #endif @@ -110,6 +113,7 @@ static void cpu_exec_nocache(int max_cyc env->current_tb = tb; /* execute the generated code */ next_tb = tcg_qemu_tb_exec(tb->tc_ptr); + env->current_tb = NULL; if ((next_tb & 3) == 2) { /* Restore PC. This may happen if async event occurs before @@ -126,14 +130,13 @@ static TranslationBlock *tb_find_slow(ta { TranslationBlock *tb, **ptb1; unsigned int h; - target_ulong phys_pc, phys_page1, phys_page2, virt_page2; + tb_page_addr_t phys_pc, phys_page1, phys_page2; + target_ulong virt_page2; 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_pc = get_page_addr_code(env, pc); phys_page1 = phys_pc & TARGET_PAGE_MASK; phys_page2 = -1; h = tb_phys_hash_func(phys_pc); @@ -150,7 +153,7 @@ static TranslationBlock *tb_find_slow(ta if (tb->page_addr[1] != -1) { virt_page2 = (pc & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; - phys_page2 = get_phys_addr_code(env, virt_page2); + phys_page2 = get_page_addr_code(env, virt_page2); if (tb->page_addr[1] == phys_page2) goto found; } else { @@ -211,10 +214,11 @@ static void cpu_handle_debug_exception(C /* main execution loop */ +volatile sig_atomic_t exit_request; + int cpu_exec(CPUState *env1) { -#define DECLARE_HOST_REGS 1 -#include "hostregs_helper.h" + volatile host_reg_t saved_env_reg; int ret, interrupt_request; TranslationBlock *tb; uint8_t *tc_ptr; @@ -225,12 +229,18 @@ int cpu_exec(CPUState *env1) cpu_single_env = env1; - /* first we save global registers */ -#define SAVE_HOST_REGS 1 -#include "hostregs_helper.h" + /* the access to env below is actually saving the global register's + value, so that files not including target-xyz/exec.h are free to + use it. */ + QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env)); + saved_env_reg = (host_reg_t) env; + barrier(); env = env1; - env_to_regs(); + if (unlikely(exit_request)) { + env->exit_request = 1; + } + #if defined(TARGET_I386) if (!kvm_enabled()) { /* put eflags in CPU temporary format */ @@ -266,7 +276,6 @@ int cpu_exec(CPUState *env1) env = cpu_single_env; #define env cpu_single_env #endif - env->current_tb = NULL; /* if an exception is pending, we execute it here */ if (env->exception_index >= 0) { if (env->exception_index >= EXCP_INTERRUPT) { @@ -320,9 +329,9 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_M68K) do_interrupt(0); #endif + env->exception_index = -1; #endif } - env->exception_index = -1; } if (kvm_enabled()) { @@ -451,20 +460,20 @@ int cpu_exec(CPUState *env1) next_tb = 0; } #elif defined(TARGET_SPARC) - if ((interrupt_request & CPU_INTERRUPT_HARD) && - cpu_interrupts_enabled(env)) { - 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; - env->exception_index = env->interrupt_index; - do_interrupt(env); - env->interrupt_index = 0; - next_tb = 0; - } + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu_interrupts_enabled(env) && + env->interrupt_index > 0) { + int pil = env->interrupt_index & 0xf; + int type = env->interrupt_index & 0xf0; + + if (((type == TT_EXTINT) && + cpu_pil_allowed(env, pil)) || + type != TT_EXTINT) { + env->exception_index = env->interrupt_index; + do_interrupt(env); + next_tb = 0; + } + } } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; @@ -504,7 +513,8 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_CRIS) if (interrupt_request & CPU_INTERRUPT_HARD - && (env->pregs[PR_CCS] & I_FLAG)) { + && (env->pregs[PR_CCS] & I_FLAG) + && !env->locked_irq) { env->exception_index = EXCP_IRQ; do_interrupt(env); next_tb = 0; @@ -543,41 +553,24 @@ int cpu_exec(CPUState *env1) env->exception_index = EXCP_INTERRUPT; cpu_loop_exit(); } -#ifdef CONFIG_DEBUG_EXEC +#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC) if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { /* restore flags in standard format */ - regs_to_env(); #if defined(TARGET_I386) env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); log_cpu_state(env, X86_DUMP_CCOP); env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); -#elif defined(TARGET_ARM) - log_cpu_state(env, 0); -#elif defined(TARGET_SPARC) - log_cpu_state(env, 0); -#elif defined(TARGET_PPC) - log_cpu_state(env, 0); #elif defined(TARGET_M68K) cpu_m68k_flush_flags(env, env->cc_op); env->cc_op = CC_OP_FLAGS; env->sr = (env->sr & 0xffe0) | env->cc_dest | (env->cc_x << 4); log_cpu_state(env, 0); -#elif defined(TARGET_MICROBLAZE) - log_cpu_state(env, 0); -#elif defined(TARGET_MIPS) - log_cpu_state(env, 0); -#elif defined(TARGET_SH4) - log_cpu_state(env, 0); -#elif defined(TARGET_ALPHA) - log_cpu_state(env, 0); -#elif defined(TARGET_CRIS) - log_cpu_state(env, 0); #else -#error unsupported target CPU + log_cpu_state(env, 0); #endif } -#endif +#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */ spin_lock(&tb_lock); tb = tb_find_fast(); /* Note: we do it here to avoid a gcc bug on Mac OS X when @@ -597,22 +590,18 @@ int cpu_exec(CPUState *env1) /* see if we can patch the calling TB. When the TB spans two pages, we cannot safely do a direct jump. */ - { - if (next_tb != 0 && tb->page_addr[1] == -1) { + if (next_tb != 0 && tb->page_addr[1] == -1) { tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); } - } spin_unlock(&tb_lock); - env->current_tb = tb; /* cpu_interrupt might be called while translating the TB, but before it is linked into a potentially infinite loop and becomes env->current_tb. Avoid starting execution if there is a pending interrupt. */ - if (unlikely (env->exit_request)) - env->current_tb = NULL; - - while (env->current_tb) { + env->current_tb = tb; + barrier(); + if (likely(!env->exit_request)) { tc_ptr = tb->tc_ptr; /* execute the generated code */ #if defined(__sparc__) && !defined(CONFIG_SOLARIS) @@ -621,7 +610,6 @@ int cpu_exec(CPUState *env1) #define env cpu_single_env #endif next_tb = tcg_qemu_tb_exec(tc_ptr); - env->current_tb = NULL; if ((next_tb & 3) == 2) { /* Instruction counter expired. */ int insns_left; @@ -650,11 +638,10 @@ int cpu_exec(CPUState *env1) } } } + env->current_tb = NULL; /* reset soft MMU for next block (it can currently only be set by a memory fault) */ } /* for(;;) */ - } else { - env_to_regs(); } } /* for(;;) */ @@ -683,7 +670,8 @@ int cpu_exec(CPUState *env1) #endif /* restore global registers */ -#include "hostregs_helper.h" + barrier(); + env = (void *) saved_env_reg; /* fail safe : never use cpu_single_env outside cpu_exec() */ cpu_single_env = NULL; @@ -935,6 +923,20 @@ int cpu_signal_handler(int host_signum, # define TRAP_sig(context) REG_sig(trap, context) #endif /* linux */ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include +# define IAR_sig(context) ((context)->uc_mcontext.mc_srr0) +# define MSR_sig(context) ((context)->uc_mcontext.mc_srr1) +# define CTR_sig(context) ((context)->uc_mcontext.mc_ctr) +# define XER_sig(context) ((context)->uc_mcontext.mc_xer) +# define LR_sig(context) ((context)->uc_mcontext.mc_lr) +# define CR_sig(context) ((context)->uc_mcontext.mc_cr) +/* Exception Registers access */ +# define DAR_sig(context) ((context)->uc_mcontext.mc_dar) +# define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr) +# define TRAP_sig(context) ((context)->uc_mcontext.mc_exc) +#endif /* __FreeBSD__|| __FreeBSD_kernel__ */ + #ifdef __APPLE__ # include typedef struct ucontext SIGCONTEXT; @@ -964,7 +966,11 @@ int cpu_signal_handler(int host_signum, void *puc) { siginfo_t *info = pinfo; +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + ucontext_t *uc = puc; +#else struct ucontext *uc = puc; +#endif unsigned long pc; int is_write; @@ -1140,7 +1146,7 @@ int cpu_signal_handler(int host_signum, } return handle_cpu_signal(ip, (unsigned long)info->si_addr, is_write, - &uc->uc_sigmask, puc); + (sigset_t *)&uc->uc_sigmask, puc); } #elif defined(__s390__) @@ -1151,11 +1157,47 @@ int cpu_signal_handler(int host_signum, siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; - int is_write; + uint16_t *pinsn; + int is_write = 0; pc = uc->uc_mcontext.psw.addr; - /* XXX: compute is_write */ - is_write = 0; + + /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead + of the normal 2 arguments. The 3rd argument contains the "int_code" + from the hardware which does in fact contain the is_write value. + The rt signal handler, as far as I can tell, does not give this value + at all. Not that we could get to it from here even if it were. */ + /* ??? This is not even close to complete, since it ignores all + of the read-modify-write instructions. */ + pinsn = (uint16_t *)pc; + switch (pinsn[0] >> 8) { + case 0x50: /* ST */ + case 0x42: /* STC */ + case 0x40: /* STH */ + is_write = 1; + break; + case 0xc4: /* RIL format insns */ + switch (pinsn[0] & 0xf) { + case 0xf: /* STRL */ + case 0xb: /* STGRL */ + case 0x7: /* STHRL */ + is_write = 1; + } + break; + case 0xe3: /* RXY format insns */ + switch (pinsn[2] & 0xff) { + case 0x50: /* STY */ + case 0x24: /* STG */ + case 0x72: /* STCY */ + case 0x70: /* STHY */ + case 0x8e: /* STPQ */ + case 0x3f: /* STRVH */ + case 0x3e: /* STRV */ + case 0x2f: /* STRVG */ + is_write = 1; + } + break; + } return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, &uc->uc_sigmask, puc); } @@ -1183,15 +1225,39 @@ int cpu_signal_handler(int host_signum, { struct siginfo *info = pinfo; struct ucontext *uc = puc; - unsigned long pc; - int is_write; + unsigned long pc = uc->uc_mcontext.sc_iaoq[0]; + uint32_t insn = *(uint32_t *)pc; + int is_write = 0; + + /* XXX: need kernel patch to get write flag faster. */ + switch (insn >> 26) { + case 0x1a: /* STW */ + case 0x19: /* STH */ + case 0x18: /* STB */ + case 0x1b: /* STWM */ + is_write = 1; + break; + + case 0x09: /* CSTWX, FSTWX, FSTWS */ + case 0x0b: /* CSTDX, FSTDX, FSTDS */ + /* Distinguish from coprocessor load ... */ + is_write = (insn >> 9) & 1; + break; + + case 0x03: + switch ((insn >> 6) & 15) { + case 0xa: /* STWS */ + case 0x9: /* STHS */ + case 0x8: /* STBS */ + case 0xe: /* STWAS */ + case 0xc: /* STBYS */ + is_write = 1; + } + break; + } - pc = uc->uc_mcontext.sc_iaoq[0]; - /* FIXME: compute is_write */ - is_write = 0; return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, - &uc->uc_sigmask, puc); + is_write, &uc->uc_sigmask, puc); } #else