version 1.1.1.11, 2018/04/24 17:57:07
|
version 1.1.1.12, 2018/04/24 18:23:30
|
Line 21
|
Line 21
|
#include "disas.h" |
#include "disas.h" |
#include "tcg.h" |
#include "tcg.h" |
#include "kvm.h" |
#include "kvm.h" |
|
#include "qemu-barrier.h" |
|
|
#if !defined(CONFIG_SOFTMMU) |
#if !defined(CONFIG_SOFTMMU) |
#undef EAX |
#undef EAX |
Line 56 int qemu_cpu_has_work(CPUState *env)
|
Line 57 int qemu_cpu_has_work(CPUState *env)
|
|
|
void cpu_loop_exit(void) |
void cpu_loop_exit(void) |
{ |
{ |
/* NOTE: the register at this point must be saved by hand because |
env->current_tb = NULL; |
longjmp restore them */ |
|
regs_to_env(); |
|
longjmp(env->jmp_env, 1); |
longjmp(env->jmp_env, 1); |
} |
} |
|
|
Line 83 void cpu_resume_from_signal(CPUState *en
|
Line 82 void cpu_resume_from_signal(CPUState *en
|
if (puc) { |
if (puc) { |
/* XXX: use siglongjmp ? */ |
/* XXX: use siglongjmp ? */ |
#ifdef __linux__ |
#ifdef __linux__ |
|
#ifdef __ia64 |
|
sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL); |
|
#else |
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); |
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); |
|
#endif |
#elif defined(__OpenBSD__) |
#elif defined(__OpenBSD__) |
sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); |
sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); |
#endif |
#endif |
Line 110 static void cpu_exec_nocache(int max_cyc
|
Line 113 static void cpu_exec_nocache(int max_cyc
|
env->current_tb = tb; |
env->current_tb = tb; |
/* execute the generated code */ |
/* execute the generated code */ |
next_tb = tcg_qemu_tb_exec(tb->tc_ptr); |
next_tb = tcg_qemu_tb_exec(tb->tc_ptr); |
|
env->current_tb = NULL; |
|
|
if ((next_tb & 3) == 2) { |
if ((next_tb & 3) == 2) { |
/* Restore PC. This may happen if async event occurs before |
/* Restore PC. This may happen if async event occurs before |
Line 126 static TranslationBlock *tb_find_slow(ta
|
Line 130 static TranslationBlock *tb_find_slow(ta
|
{ |
{ |
TranslationBlock *tb, **ptb1; |
TranslationBlock *tb, **ptb1; |
unsigned int h; |
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; |
tb_invalidated_flag = 0; |
|
|
regs_to_env(); /* XXX: do it just before cpu_gen_code() */ |
|
|
|
/* find translated block using physical mappings */ |
/* 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_page1 = phys_pc & TARGET_PAGE_MASK; |
phys_page2 = -1; |
phys_page2 = -1; |
h = tb_phys_hash_func(phys_pc); |
h = tb_phys_hash_func(phys_pc); |
Line 150 static TranslationBlock *tb_find_slow(ta
|
Line 153 static TranslationBlock *tb_find_slow(ta
|
if (tb->page_addr[1] != -1) { |
if (tb->page_addr[1] != -1) { |
virt_page2 = (pc & TARGET_PAGE_MASK) + |
virt_page2 = (pc & TARGET_PAGE_MASK) + |
TARGET_PAGE_SIZE; |
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) |
if (tb->page_addr[1] == phys_page2) |
goto found; |
goto found; |
} else { |
} else { |
Line 211 static void cpu_handle_debug_exception(C
|
Line 214 static void cpu_handle_debug_exception(C
|
|
|
/* main execution loop */ |
/* main execution loop */ |
|
|
|
volatile sig_atomic_t exit_request; |
|
|
int cpu_exec(CPUState *env1) |
int cpu_exec(CPUState *env1) |
{ |
{ |
#define DECLARE_HOST_REGS 1 |
volatile host_reg_t saved_env_reg; |
#include "hostregs_helper.h" |
|
int ret, interrupt_request; |
int ret, interrupt_request; |
TranslationBlock *tb; |
TranslationBlock *tb; |
uint8_t *tc_ptr; |
uint8_t *tc_ptr; |
Line 225 int cpu_exec(CPUState *env1)
|
Line 229 int cpu_exec(CPUState *env1)
|
|
|
cpu_single_env = env1; |
cpu_single_env = env1; |
|
|
/* first we save global registers */ |
/* the access to env below is actually saving the global register's |
#define SAVE_HOST_REGS 1 |
value, so that files not including target-xyz/exec.h are free to |
#include "hostregs_helper.h" |
use it. */ |
|
QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env)); |
|
saved_env_reg = (host_reg_t) env; |
|
barrier(); |
env = env1; |
env = env1; |
|
|
env_to_regs(); |
if (unlikely(exit_request)) { |
|
env->exit_request = 1; |
|
} |
|
|
#if defined(TARGET_I386) |
#if defined(TARGET_I386) |
if (!kvm_enabled()) { |
if (!kvm_enabled()) { |
/* put eflags in CPU temporary format */ |
/* put eflags in CPU temporary format */ |
Line 266 int cpu_exec(CPUState *env1)
|
Line 276 int cpu_exec(CPUState *env1)
|
env = cpu_single_env; |
env = cpu_single_env; |
#define env cpu_single_env |
#define env cpu_single_env |
#endif |
#endif |
env->current_tb = NULL; |
|
/* if an exception is pending, we execute it here */ |
/* if an exception is pending, we execute it here */ |
if (env->exception_index >= 0) { |
if (env->exception_index >= 0) { |
if (env->exception_index >= EXCP_INTERRUPT) { |
if (env->exception_index >= EXCP_INTERRUPT) { |
Line 320 int cpu_exec(CPUState *env1)
|
Line 329 int cpu_exec(CPUState *env1)
|
#elif defined(TARGET_M68K) |
#elif defined(TARGET_M68K) |
do_interrupt(0); |
do_interrupt(0); |
#endif |
#endif |
|
env->exception_index = -1; |
#endif |
#endif |
} |
} |
env->exception_index = -1; |
|
} |
} |
|
|
if (kvm_enabled()) { |
if (kvm_enabled()) { |
Line 451 int cpu_exec(CPUState *env1)
|
Line 460 int cpu_exec(CPUState *env1)
|
next_tb = 0; |
next_tb = 0; |
} |
} |
#elif defined(TARGET_SPARC) |
#elif defined(TARGET_SPARC) |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
if (interrupt_request & CPU_INTERRUPT_HARD) { |
cpu_interrupts_enabled(env)) { |
if (cpu_interrupts_enabled(env) && |
int pil = env->interrupt_index & 15; |
env->interrupt_index > 0) { |
int type = env->interrupt_index & 0xf0; |
int pil = env->interrupt_index & 0xf; |
|
int type = env->interrupt_index & 0xf0; |
if (((type == TT_EXTINT) && |
|
(pil == 15 || pil > env->psrpil)) || |
if (((type == TT_EXTINT) && |
type != TT_EXTINT) { |
cpu_pil_allowed(env, pil)) || |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
type != TT_EXTINT) { |
env->exception_index = env->interrupt_index; |
env->exception_index = env->interrupt_index; |
do_interrupt(env); |
do_interrupt(env); |
env->interrupt_index = 0; |
next_tb = 0; |
next_tb = 0; |
} |
} |
} |
} else if (interrupt_request & CPU_INTERRUPT_TIMER) { |
} else if (interrupt_request & CPU_INTERRUPT_TIMER) { |
//do_interrupt(0, 0, 0, 0, 0); |
//do_interrupt(0, 0, 0, 0, 0); |
env->interrupt_request &= ~CPU_INTERRUPT_TIMER; |
env->interrupt_request &= ~CPU_INTERRUPT_TIMER; |
Line 504 int cpu_exec(CPUState *env1)
|
Line 513 int cpu_exec(CPUState *env1)
|
} |
} |
#elif defined(TARGET_CRIS) |
#elif defined(TARGET_CRIS) |
if (interrupt_request & CPU_INTERRUPT_HARD |
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; |
env->exception_index = EXCP_IRQ; |
do_interrupt(env); |
do_interrupt(env); |
next_tb = 0; |
next_tb = 0; |
Line 543 int cpu_exec(CPUState *env1)
|
Line 553 int cpu_exec(CPUState *env1)
|
env->exception_index = EXCP_INTERRUPT; |
env->exception_index = EXCP_INTERRUPT; |
cpu_loop_exit(); |
cpu_loop_exit(); |
} |
} |
#ifdef CONFIG_DEBUG_EXEC |
#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC) |
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { |
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { |
/* restore flags in standard format */ |
/* restore flags in standard format */ |
regs_to_env(); |
|
#if defined(TARGET_I386) |
#if defined(TARGET_I386) |
env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); |
env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); |
log_cpu_state(env, X86_DUMP_CCOP); |
log_cpu_state(env, X86_DUMP_CCOP); |
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
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) |
#elif defined(TARGET_M68K) |
cpu_m68k_flush_flags(env, env->cc_op); |
cpu_m68k_flush_flags(env, env->cc_op); |
env->cc_op = CC_OP_FLAGS; |
env->cc_op = CC_OP_FLAGS; |
env->sr = (env->sr & 0xffe0) |
env->sr = (env->sr & 0xffe0) |
| env->cc_dest | (env->cc_x << 4); |
| env->cc_dest | (env->cc_x << 4); |
log_cpu_state(env, 0); |
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 |
#else |
#error unsupported target CPU |
log_cpu_state(env, 0); |
#endif |
#endif |
} |
} |
#endif |
#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */ |
spin_lock(&tb_lock); |
spin_lock(&tb_lock); |
tb = tb_find_fast(); |
tb = tb_find_fast(); |
/* Note: we do it here to avoid a gcc bug on Mac OS X when |
/* Note: we do it here to avoid a gcc bug on Mac OS X when |
Line 597 int cpu_exec(CPUState *env1)
|
Line 590 int cpu_exec(CPUState *env1)
|
/* see if we can patch the calling TB. When the TB |
/* see if we can patch the calling TB. When the TB |
spans two pages, we cannot safely do a direct |
spans two pages, we cannot safely do a direct |
jump. */ |
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); |
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); |
} |
} |
} |
|
spin_unlock(&tb_lock); |
spin_unlock(&tb_lock); |
env->current_tb = tb; |
|
|
|
/* cpu_interrupt might be called while translating the |
/* cpu_interrupt might be called while translating the |
TB, but before it is linked into a potentially |
TB, but before it is linked into a potentially |
infinite loop and becomes env->current_tb. Avoid |
infinite loop and becomes env->current_tb. Avoid |
starting execution if there is a pending interrupt. */ |
starting execution if there is a pending interrupt. */ |
if (unlikely (env->exit_request)) |
env->current_tb = tb; |
env->current_tb = NULL; |
barrier(); |
|
if (likely(!env->exit_request)) { |
while (env->current_tb) { |
|
tc_ptr = tb->tc_ptr; |
tc_ptr = tb->tc_ptr; |
/* execute the generated code */ |
/* execute the generated code */ |
#if defined(__sparc__) && !defined(CONFIG_SOLARIS) |
#if defined(__sparc__) && !defined(CONFIG_SOLARIS) |
Line 621 int cpu_exec(CPUState *env1)
|
Line 610 int cpu_exec(CPUState *env1)
|
#define env cpu_single_env |
#define env cpu_single_env |
#endif |
#endif |
next_tb = tcg_qemu_tb_exec(tc_ptr); |
next_tb = tcg_qemu_tb_exec(tc_ptr); |
env->current_tb = NULL; |
|
if ((next_tb & 3) == 2) { |
if ((next_tb & 3) == 2) { |
/* Instruction counter expired. */ |
/* Instruction counter expired. */ |
int insns_left; |
int insns_left; |
Line 650 int cpu_exec(CPUState *env1)
|
Line 638 int cpu_exec(CPUState *env1)
|
} |
} |
} |
} |
} |
} |
|
env->current_tb = NULL; |
/* reset soft MMU for next block (it can currently |
/* reset soft MMU for next block (it can currently |
only be set by a memory fault) */ |
only be set by a memory fault) */ |
} /* for(;;) */ |
} /* for(;;) */ |
} else { |
|
env_to_regs(); |
|
} |
} |
} /* for(;;) */ |
} /* for(;;) */ |
|
|
Line 683 int cpu_exec(CPUState *env1)
|
Line 670 int cpu_exec(CPUState *env1)
|
#endif |
#endif |
|
|
/* restore global registers */ |
/* restore global registers */ |
#include "hostregs_helper.h" |
barrier(); |
|
env = (void *) saved_env_reg; |
|
|
/* fail safe : never use cpu_single_env outside cpu_exec() */ |
/* fail safe : never use cpu_single_env outside cpu_exec() */ |
cpu_single_env = NULL; |
cpu_single_env = NULL; |
Line 935 int cpu_signal_handler(int host_signum,
|
Line 923 int cpu_signal_handler(int host_signum,
|
# define TRAP_sig(context) REG_sig(trap, context) |
# define TRAP_sig(context) REG_sig(trap, context) |
#endif /* linux */ |
#endif /* linux */ |
|
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
|
#include <ucontext.h> |
|
# 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__ |
#ifdef __APPLE__ |
# include <sys/ucontext.h> |
# include <sys/ucontext.h> |
typedef struct ucontext SIGCONTEXT; |
typedef struct ucontext SIGCONTEXT; |
Line 964 int cpu_signal_handler(int host_signum,
|
Line 966 int cpu_signal_handler(int host_signum,
|
void *puc) |
void *puc) |
{ |
{ |
siginfo_t *info = pinfo; |
siginfo_t *info = pinfo; |
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
|
ucontext_t *uc = puc; |
|
#else |
struct ucontext *uc = puc; |
struct ucontext *uc = puc; |
|
#endif |
unsigned long pc; |
unsigned long pc; |
int is_write; |
int is_write; |
|
|
Line 1140 int cpu_signal_handler(int host_signum,
|
Line 1146 int cpu_signal_handler(int host_signum,
|
} |
} |
return handle_cpu_signal(ip, (unsigned long)info->si_addr, |
return handle_cpu_signal(ip, (unsigned long)info->si_addr, |
is_write, |
is_write, |
&uc->uc_sigmask, puc); |
(sigset_t *)&uc->uc_sigmask, puc); |
} |
} |
|
|
#elif defined(__s390__) |
#elif defined(__s390__) |
Line 1151 int cpu_signal_handler(int host_signum,
|
Line 1157 int cpu_signal_handler(int host_signum,
|
siginfo_t *info = pinfo; |
siginfo_t *info = pinfo; |
struct ucontext *uc = puc; |
struct ucontext *uc = puc; |
unsigned long pc; |
unsigned long pc; |
int is_write; |
uint16_t *pinsn; |
|
int is_write = 0; |
|
|
pc = uc->uc_mcontext.psw.addr; |
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, |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
is_write, &uc->uc_sigmask, puc); |
is_write, &uc->uc_sigmask, puc); |
} |
} |
Line 1183 int cpu_signal_handler(int host_signum,
|
Line 1225 int cpu_signal_handler(int host_signum,
|
{ |
{ |
struct siginfo *info = pinfo; |
struct siginfo *info = pinfo; |
struct ucontext *uc = puc; |
struct ucontext *uc = puc; |
unsigned long pc; |
unsigned long pc = uc->uc_mcontext.sc_iaoq[0]; |
int is_write; |
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, |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
is_write, |
is_write, &uc->uc_sigmask, puc); |
&uc->uc_sigmask, puc); |
|
} |
} |
|
|
#else |
#else |