version 1.1.1.8, 2018/04/24 16:56:15
|
version 1.1.1.9, 2018/04/24 17:20:28
|
Line 14
|
Line 14
|
* Lesser General Public License for more details. |
* Lesser General Public License for more details. |
* |
* |
* You should have received a copy of the GNU Lesser General Public |
* You should have received a copy of the GNU Lesser General Public |
* License along with this library; if not, write to the Free Software |
* License along with this library; if not, see <http://www.gnu.org/licenses/>. |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA |
|
*/ |
*/ |
#include "config.h" |
#include "config.h" |
#define CPU_NO_GLOBAL_REGS |
|
#include "exec.h" |
#include "exec.h" |
#include "disas.h" |
#include "disas.h" |
#include "tcg.h" |
#include "tcg.h" |
Line 51 int tb_invalidated_flag;
|
Line 49 int tb_invalidated_flag;
|
//#define DEBUG_EXEC |
//#define DEBUG_EXEC |
//#define DEBUG_SIGNAL |
//#define DEBUG_SIGNAL |
|
|
|
int qemu_cpu_has_work(CPUState *env) |
|
{ |
|
return cpu_has_work(env); |
|
} |
|
|
void cpu_loop_exit(void) |
void cpu_loop_exit(void) |
{ |
{ |
/* NOTE: the register at this point must be saved by hand because |
/* NOTE: the register at this point must be saved by hand because |
Line 242 int cpu_exec(CPUState *env1)
|
Line 245 int cpu_exec(CPUState *env1)
|
#elif defined(TARGET_ALPHA) |
#elif defined(TARGET_ALPHA) |
#elif defined(TARGET_ARM) |
#elif defined(TARGET_ARM) |
#elif defined(TARGET_PPC) |
#elif defined(TARGET_PPC) |
|
#elif defined(TARGET_MICROBLAZE) |
#elif defined(TARGET_MIPS) |
#elif defined(TARGET_MIPS) |
#elif defined(TARGET_SH4) |
#elif defined(TARGET_SH4) |
#elif defined(TARGET_CRIS) |
#elif defined(TARGET_CRIS) |
Line 254 int cpu_exec(CPUState *env1)
|
Line 258 int cpu_exec(CPUState *env1)
|
/* prepare setjmp context for exception handling */ |
/* prepare setjmp context for exception handling */ |
for(;;) { |
for(;;) { |
if (setjmp(env->jmp_env) == 0) { |
if (setjmp(env->jmp_env) == 0) { |
|
#if defined(__sparc__) && !defined(HOST_SOLARIS) |
|
#undef env |
|
env = cpu_single_env; |
|
#define env cpu_single_env |
|
#endif |
env->current_tb = NULL; |
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) { |
Line 291 int cpu_exec(CPUState *env1)
|
Line 300 int cpu_exec(CPUState *env1)
|
env->old_exception = -1; |
env->old_exception = -1; |
#elif defined(TARGET_PPC) |
#elif defined(TARGET_PPC) |
do_interrupt(env); |
do_interrupt(env); |
|
#elif defined(TARGET_MICROBLAZE) |
|
do_interrupt(env); |
#elif defined(TARGET_MIPS) |
#elif defined(TARGET_MIPS) |
do_interrupt(env); |
do_interrupt(env); |
#elif defined(TARGET_SPARC) |
#elif defined(TARGET_SPARC) |
Line 310 int cpu_exec(CPUState *env1)
|
Line 321 int cpu_exec(CPUState *env1)
|
} |
} |
env->exception_index = -1; |
env->exception_index = -1; |
} |
} |
#ifdef USE_KQEMU |
#ifdef CONFIG_KQEMU |
if (kqemu_is_ok(env) && env->interrupt_request == 0 && env->exit_request == 0) { |
if (kqemu_is_ok(env) && env->interrupt_request == 0 && env->exit_request == 0) { |
int ret; |
int ret; |
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); |
Line 358 int cpu_exec(CPUState *env1)
|
Line 369 int cpu_exec(CPUState *env1)
|
cpu_loop_exit(); |
cpu_loop_exit(); |
} |
} |
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ |
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ |
defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) |
defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ |
|
defined(TARGET_MICROBLAZE) |
if (interrupt_request & CPU_INTERRUPT_HALT) { |
if (interrupt_request & CPU_INTERRUPT_HALT) { |
env->interrupt_request &= ~CPU_INTERRUPT_HALT; |
env->interrupt_request &= ~CPU_INTERRUPT_HALT; |
env->halted = 1; |
env->halted = 1; |
Line 367 int cpu_exec(CPUState *env1)
|
Line 379 int cpu_exec(CPUState *env1)
|
} |
} |
#endif |
#endif |
#if defined(TARGET_I386) |
#if defined(TARGET_I386) |
if (env->hflags2 & HF2_GIF_MASK) { |
if (interrupt_request & CPU_INTERRUPT_INIT) { |
|
svm_check_intercept(SVM_EXIT_INIT); |
|
do_cpu_init(env); |
|
env->exception_index = EXCP_HALTED; |
|
cpu_loop_exit(); |
|
} else if (interrupt_request & CPU_INTERRUPT_SIPI) { |
|
do_cpu_sipi(env); |
|
} else if (env->hflags2 & HF2_GIF_MASK) { |
if ((interrupt_request & CPU_INTERRUPT_SMI) && |
if ((interrupt_request & CPU_INTERRUPT_SMI) && |
!(env->hflags & HF_SMM_MASK)) { |
!(env->hflags & HF_SMM_MASK)) { |
svm_check_intercept(SVM_EXIT_SMI); |
svm_check_intercept(SVM_EXIT_SMI); |
Line 380 int cpu_exec(CPUState *env1)
|
Line 399 int cpu_exec(CPUState *env1)
|
env->hflags2 |= HF2_NMI_MASK; |
env->hflags2 |= HF2_NMI_MASK; |
do_interrupt(EXCP02_NMI, 0, 0, 0, 1); |
do_interrupt(EXCP02_NMI, 0, 0, 0, 1); |
next_tb = 0; |
next_tb = 0; |
|
} else if (interrupt_request & CPU_INTERRUPT_MCE) { |
|
env->interrupt_request &= ~CPU_INTERRUPT_MCE; |
|
do_interrupt(EXCP12_MCHK, 0, 0, 0, 0); |
|
next_tb = 0; |
} else if ((interrupt_request & CPU_INTERRUPT_HARD) && |
} else if ((interrupt_request & CPU_INTERRUPT_HARD) && |
(((env->hflags2 & HF2_VINTR_MASK) && |
(((env->hflags2 & HF2_VINTR_MASK) && |
(env->hflags2 & HF2_HIF_MASK)) || |
(env->hflags2 & HF2_HIF_MASK)) || |
Line 391 int cpu_exec(CPUState *env1)
|
Line 414 int cpu_exec(CPUState *env1)
|
env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); |
env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); |
intno = cpu_get_pic_interrupt(env); |
intno = cpu_get_pic_interrupt(env); |
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno); |
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno); |
|
#if defined(__sparc__) && !defined(HOST_SOLARIS) |
|
#undef env |
|
env = cpu_single_env; |
|
#define env cpu_single_env |
|
#endif |
do_interrupt(intno, 0, 0, 0, 1); |
do_interrupt(intno, 0, 0, 0, 1); |
/* ensure that no TB jump will be modified as |
/* ensure that no TB jump will be modified as |
the program flow was changed */ |
the program flow was changed */ |
Line 422 int cpu_exec(CPUState *env1)
|
Line 450 int cpu_exec(CPUState *env1)
|
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
next_tb = 0; |
next_tb = 0; |
} |
} |
|
#elif defined(TARGET_MICROBLAZE) |
|
if ((interrupt_request & CPU_INTERRUPT_HARD) |
|
&& (env->sregs[SR_MSR] & MSR_IE) |
|
&& !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) |
|
&& !(env->iflags & (D_FLAG | IMM_FLAG))) { |
|
env->exception_index = EXCP_IRQ; |
|
do_interrupt(env); |
|
next_tb = 0; |
|
} |
#elif defined(TARGET_MIPS) |
#elif defined(TARGET_MIPS) |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
(env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && |
(env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && |
Line 437 int cpu_exec(CPUState *env1)
|
Line 474 int cpu_exec(CPUState *env1)
|
} |
} |
#elif defined(TARGET_SPARC) |
#elif defined(TARGET_SPARC) |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
(env->psret != 0)) { |
cpu_interrupts_enabled(env)) { |
int pil = env->interrupt_index & 15; |
int pil = env->interrupt_index & 15; |
int type = env->interrupt_index & 0xf0; |
int type = env->interrupt_index & 0xf0; |
|
|
Line 448 int cpu_exec(CPUState *env1)
|
Line 485 int cpu_exec(CPUState *env1)
|
env->exception_index = env->interrupt_index; |
env->exception_index = env->interrupt_index; |
do_interrupt(env); |
do_interrupt(env); |
env->interrupt_index = 0; |
env->interrupt_index = 0; |
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) |
#if !defined(CONFIG_USER_ONLY) |
cpu_check_irqs(env); |
cpu_check_irqs(env); |
#endif |
#endif |
next_tb = 0; |
next_tb = 0; |
Line 551 int cpu_exec(CPUState *env1)
|
Line 588 int cpu_exec(CPUState *env1)
|
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) |
#elif defined(TARGET_MIPS) |
log_cpu_state(env, 0); |
log_cpu_state(env, 0); |
#elif defined(TARGET_SH4) |
#elif defined(TARGET_SH4) |
Line 585 int cpu_exec(CPUState *env1)
|
Line 624 int cpu_exec(CPUState *env1)
|
jump. */ |
jump. */ |
{ |
{ |
if (next_tb != 0 && |
if (next_tb != 0 && |
#ifdef USE_KQEMU |
#ifdef CONFIG_KQEMU |
(env->kqemu_enabled != 2) && |
(env->kqemu_enabled != 2) && |
#endif |
#endif |
tb->page_addr[1] == -1) { |
tb->page_addr[1] == -1) { |
Line 642 int cpu_exec(CPUState *env1)
|
Line 681 int cpu_exec(CPUState *env1)
|
} |
} |
/* 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) */ |
#if defined(USE_KQEMU) |
#if defined(CONFIG_KQEMU) |
#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000) |
#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000) |
if (kqemu_is_ok(env) && |
if (kqemu_is_ok(env) && |
(cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) { |
(cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) { |
Line 668 int cpu_exec(CPUState *env1)
|
Line 707 int cpu_exec(CPUState *env1)
|
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); |
|
#elif defined(TARGET_MICROBLAZE) |
#elif defined(TARGET_MIPS) |
#elif defined(TARGET_MIPS) |
#elif defined(TARGET_SH4) |
#elif defined(TARGET_SH4) |
#elif defined(TARGET_ALPHA) |
#elif defined(TARGET_ALPHA) |
Line 1014 static inline int handle_cpu_signal(unsi
|
Line 1054 static inline int handle_cpu_signal(unsi
|
return 1; |
return 1; |
} |
} |
|
|
|
#elif defined (TARGET_MICROBLAZE) |
|
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_mb_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 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: PC=0x" TARGET_FMT_lx " error=0x%x %p\n", |
|
env->PC, 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); |
|
cpu_loop_exit(); |
|
} else { |
|
/* activate soft MMU for this block */ |
|
cpu_resume_from_signal(env, puc); |
|
} |
|
/* never comes here */ |
|
return 1; |
|
} |
|
|
#elif defined (TARGET_SH4) |
#elif defined (TARGET_SH4) |
static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
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, |
Line 1156 static inline int handle_cpu_signal(unsi
|
Line 1246 static inline int handle_cpu_signal(unsi
|
# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip)) |
# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip)) |
# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) |
# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) |
# define ERROR_sig(context) ((context)->uc_mcontext->es.err) |
# define ERROR_sig(context) ((context)->uc_mcontext->es.err) |
|
# define MASK_sig(context) ((context)->uc_sigmask) |
|
#elif defined(__OpenBSD__) |
|
# define EIP_sig(context) ((context)->sc_eip) |
|
# define TRAP_sig(context) ((context)->sc_trapno) |
|
# define ERROR_sig(context) ((context)->sc_err) |
|
# define MASK_sig(context) ((context)->sc_mask) |
#else |
#else |
# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) |
# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) |
# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) |
# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) |
# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) |
# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) |
|
# define MASK_sig(context) ((context)->uc_sigmask) |
#endif |
#endif |
|
|
int cpu_signal_handler(int host_signum, void *pinfo, |
int cpu_signal_handler(int host_signum, void *pinfo, |
void *puc) |
void *puc) |
{ |
{ |
siginfo_t *info = pinfo; |
siginfo_t *info = pinfo; |
|
#if defined(__OpenBSD__) |
|
struct sigcontext *uc = puc; |
|
#else |
struct ucontext *uc = puc; |
struct ucontext *uc = puc; |
|
#endif |
unsigned long pc; |
unsigned long pc; |
int trapno; |
int trapno; |
|
|
Line 1181 int cpu_signal_handler(int host_signum,
|
Line 1282 int cpu_signal_handler(int host_signum,
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
trapno == 0xe ? |
trapno == 0xe ? |
(ERROR_sig(uc) >> 1) & 1 : 0, |
(ERROR_sig(uc) >> 1) & 1 : 0, |
&uc->uc_sigmask, puc); |
&MASK_sig(uc), puc); |
} |
} |
|
|
#elif defined(__x86_64__) |
#elif defined(__x86_64__) |
|
|
#ifdef __NetBSD__ |
#ifdef __NetBSD__ |
#define REG_ERR _REG_ERR |
#define PC_sig(context) _UC_MACHINE_PC(context) |
#define REG_TRAPNO _REG_TRAPNO |
#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) |
|
#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) |
#define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.__gregs[(reg)] |
#define MASK_sig(context) ((context)->uc_sigmask) |
#define QEMU_UC_MACHINE_PC(uc) _UC_MACHINE_PC(uc) |
#elif defined(__OpenBSD__) |
|
#define PC_sig(context) ((context)->sc_rip) |
|
#define TRAP_sig(context) ((context)->sc_trapno) |
|
#define ERROR_sig(context) ((context)->sc_err) |
|
#define MASK_sig(context) ((context)->sc_mask) |
#else |
#else |
#define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.gregs[(reg)] |
#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP]) |
#define QEMU_UC_MACHINE_PC(uc) QEMU_UC_MCONTEXT_GREGS(uc, REG_RIP) |
#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) |
|
#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) |
|
#define MASK_sig(context) ((context)->uc_sigmask) |
#endif |
#endif |
|
|
int cpu_signal_handler(int host_signum, void *pinfo, |
int cpu_signal_handler(int host_signum, void *pinfo, |
Line 1204 int cpu_signal_handler(int host_signum,
|
Line 1311 int cpu_signal_handler(int host_signum,
|
unsigned long pc; |
unsigned long pc; |
#ifdef __NetBSD__ |
#ifdef __NetBSD__ |
ucontext_t *uc = puc; |
ucontext_t *uc = puc; |
|
#elif defined(__OpenBSD__) |
|
struct sigcontext *uc = puc; |
#else |
#else |
struct ucontext *uc = puc; |
struct ucontext *uc = puc; |
#endif |
#endif |
|
|
pc = QEMU_UC_MACHINE_PC(uc); |
pc = PC_sig(uc); |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
QEMU_UC_MCONTEXT_GREGS(uc, REG_TRAPNO) == 0xe ? |
TRAP_sig(uc) == 0xe ? |
(QEMU_UC_MCONTEXT_GREGS(uc, REG_ERR) >> 1) & 1 : 0, |
(ERROR_sig(uc) >> 1) & 1 : 0, |
&uc->uc_sigmask, puc); |
&MASK_sig(uc), puc); |
} |
} |
|
|
#elif defined(_ARCH_PPC) |
#elif defined(_ARCH_PPC) |
Line 1349 int cpu_signal_handler(int host_signum,
|
Line 1458 int cpu_signal_handler(int host_signum,
|
if ((insn >> 30) == 3) { |
if ((insn >> 30) == 3) { |
switch((insn >> 19) & 0x3f) { |
switch((insn >> 19) & 0x3f) { |
case 0x05: // stb |
case 0x05: // stb |
|
case 0x15: // stba |
case 0x06: // sth |
case 0x06: // sth |
|
case 0x16: // stha |
case 0x04: // st |
case 0x04: // st |
|
case 0x14: // sta |
case 0x07: // std |
case 0x07: // std |
|
case 0x17: // stda |
|
case 0x0e: // stx |
|
case 0x1e: // stxa |
case 0x24: // stf |
case 0x24: // stf |
|
case 0x34: // stfa |
case 0x27: // stdf |
case 0x27: // stdf |
|
case 0x37: // stdfa |
|
case 0x26: // stqf |
|
case 0x36: // stqfa |
case 0x25: // stfsr |
case 0x25: // stfsr |
|
case 0x3c: // casa |
|
case 0x3e: // casxa |
is_write = 1; |
is_write = 1; |
break; |
break; |
} |
} |