aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/main.c')
-rw-r--r--linux-user/main.c988
1 files changed, 664 insertions, 324 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index 7199372b3..af99d0455 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1,6 +1,6 @@
/*
* qemu user main
- *
+ *
* Copyright (c) 2003 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
@@ -131,7 +131,7 @@ uint64_t cpu_get_tsc(CPUX86State *env)
return cpu_get_real_ticks();
}
-static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
+static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int flags)
{
unsigned int e1, e2;
@@ -144,7 +144,7 @@ static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
p[1] = tswapl(e2);
}
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
unsigned long addr, unsigned int sel)
{
unsigned int e1, e2;
@@ -176,8 +176,8 @@ void cpu_loop(CPUX86State *env)
switch(trapnr) {
case 0x80:
/* linux syscall */
- env->regs[R_EAX] = do_syscall(env,
- env->regs[R_EAX],
+ env->regs[R_EAX] = do_syscall(env,
+ env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
@@ -194,9 +194,12 @@ void cpu_loop(CPUX86State *env)
queue_signal(info.si_signo, &info);
break;
case EXCP0D_GPF:
+#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_fault(env);
- } else {
+ } else
+#endif
+ {
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
@@ -215,9 +218,12 @@ void cpu_loop(CPUX86State *env)
queue_signal(info.si_signo, &info);
break;
case EXCP00_DIVZ:
+#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
- } else {
+ } else
+#endif
+ {
/* division by zero */
info.si_signo = SIGFPE;
info.si_errno = 0;
@@ -228,9 +234,12 @@ void cpu_loop(CPUX86State *env)
break;
case EXCP01_SSTP:
case EXCP03_INT3:
+#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
- } else {
+ } else
+#endif
+ {
info.si_signo = SIGTRAP;
info.si_errno = 0;
if (trapnr == EXCP01_SSTP) {
@@ -245,9 +254,12 @@ void cpu_loop(CPUX86State *env)
break;
case EXCP04_INTO:
case EXCP05_BOUND:
+#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
- } else {
+ } else
+#endif
+ {
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
@@ -281,7 +293,7 @@ void cpu_loop(CPUX86State *env)
break;
default:
pc = env->segs[R_CS].base + env->eip;
- fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+ fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
(long)pc, trapnr);
abort();
}
@@ -319,7 +331,7 @@ void cpu_loop(CPUARMState *env)
unsigned int n, insn;
target_siginfo_t info;
uint32_t addr;
-
+
for(;;) {
trapnr = cpu_arm_exec(env);
switch(trapnr) {
@@ -331,7 +343,7 @@ void cpu_loop(CPUARMState *env)
/* we handle the FPU emulation here, as Linux */
/* we get the opcode */
opcode = tget32(env->regs[15]);
-
+
if (EmulateAll(opcode, &ts->fpa, env) == 0) {
info.si_signo = SIGILL;
info.si_errno = 0;
@@ -383,8 +395,8 @@ void cpu_loop(CPUARMState *env)
n -= ARM_SYSCALL_BASE;
env->eabi = 0;
}
- env->regs[0] = do_syscall(env,
- n,
+ env->regs[0] = do_syscall(env,
+ n,
env->regs[0],
env->regs[1],
env->regs[2],
@@ -431,7 +443,7 @@ void cpu_loop(CPUARMState *env)
break;
default:
error:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+ fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
abort();
@@ -463,10 +475,10 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1)
{
unsigned int i;
target_ulong sp_ptr;
-
+
sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
#if defined(DEBUG_WIN)
- printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
+ printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
(int)sp_ptr, cwp1);
#endif
for(i = 0; i < 16; i++) {
@@ -494,15 +506,15 @@ static void restore_window(CPUSPARCState *env)
{
unsigned int new_wim, i, cwp1;
target_ulong sp_ptr;
-
+
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
((1LL << NWINDOWS) - 1);
-
+
/* restore the invalid window */
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
#if defined(DEBUG_WIN)
- printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
+ printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
(int)sp_ptr, cwp1);
#endif
for(i = 0; i < 16; i++) {
@@ -543,20 +555,20 @@ void cpu_loop (CPUSPARCState *env)
{
int trapnr, ret;
target_siginfo_t info;
-
+
while (1) {
trapnr = cpu_sparc_exec (env);
-
+
switch (trapnr) {
#ifndef TARGET_SPARC64
- case 0x88:
+ case 0x88:
case 0x90:
#else
case 0x16d:
#endif
ret = do_syscall (env, env->gregs[1],
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
+ env->regwptr[0], env->regwptr[1],
+ env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5]);
if ((unsigned int)ret >= (unsigned int)(-515)) {
#ifdef TARGET_SPARC64
@@ -608,7 +620,20 @@ void cpu_loop (CPUSPARCState *env)
case TT_FILL: /* window underflow */
restore_window(env);
break;
- // XXX
+ case TT_TFAULT:
+ case TT_DFAULT:
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ if (trapnr == TT_DFAULT)
+ info._sifields._sigfault._addr = env->dmmuregs[4];
+ else
+ info._sifields._sigfault._addr = env->tpc[env->tl];
+ queue_signal(info.si_signo, &info);
+ }
+ break;
#endif
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
@@ -639,111 +664,85 @@ void cpu_loop (CPUSPARCState *env)
#endif
#ifdef TARGET_PPC
-
static inline uint64_t cpu_ppc_get_tb (CPUState *env)
{
/* TO FIX */
return 0;
}
-
+
uint32_t cpu_ppc_load_tbl (CPUState *env)
{
return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
}
-
+
uint32_t cpu_ppc_load_tbu (CPUState *env)
{
return cpu_ppc_get_tb(env) >> 32;
}
-
-static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
+
+uint32_t cpu_ppc_load_atbl (CPUState *env)
{
- /* TO FIX */
+ return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
}
-void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+uint32_t cpu_ppc_load_atbu (CPUState *env)
{
- cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
+ return cpu_ppc_get_tb(env) >> 32;
}
-
-void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
{
- cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
+ return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
}
-
-uint32_t cpu_ppc_load_decr (CPUState *env)
+
+/* XXX: to be fixed */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
{
- /* TO FIX */
return -1;
}
-
-void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
{
- /* TO FIX */
+ return -1;
}
-
+
+#define EXCP_DUMP(env, fmt, args...) \
+do { \
+ fprintf(stderr, fmt , ##args); \
+ cpu_dump_state(env, stderr, fprintf, 0); \
+ if (loglevel != 0) { \
+ fprintf(logfile, fmt , ##args); \
+ cpu_dump_state(env, logfile, fprintf, 0); \
+ } \
+} while (0)
+
void cpu_loop(CPUPPCState *env)
{
target_siginfo_t info;
int trapnr;
uint32_t ret;
-
+
for(;;) {
trapnr = cpu_ppc_exec(env);
- if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
- trapnr != EXCP_TRACE) {
- if (loglevel > 0) {
- cpu_dump_state(env, logfile, fprintf, 0);
- }
- }
switch(trapnr) {
- case EXCP_NONE:
+ case POWERPC_EXCP_NONE:
+ /* Just go on */
break;
- case EXCP_SYSCALL_USER:
- /* system call */
- /* WARNING:
- * PPC ABI uses overflow flag in cr0 to signal an error
- * in syscalls.
- */
-#if 0
- printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
- env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
-#endif
- env->crf[0] &= ~0x1;
- ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
- env->gpr[5], env->gpr[6], env->gpr[7],
- env->gpr[8]);
- if (ret > (uint32_t)(-515)) {
- env->crf[0] |= 0x1;
- ret = -ret;
- }
- env->gpr[3] = ret;
-#if 0
- printf("syscall returned 0x%08x (%d)\n", ret, ret);
-#endif
+ case POWERPC_EXCP_CRITICAL: /* Critical input */
+ cpu_abort(env, "Critical interrupt while in user mode. "
+ "Aborting\n");
break;
- case EXCP_RESET:
- /* Should not happen ! */
- fprintf(stderr, "RESET asked... Stop emulation\n");
- if (loglevel)
- fprintf(logfile, "RESET asked... Stop emulation\n");
- abort();
- case EXCP_MACHINE_CHECK:
- fprintf(stderr, "Machine check exeption... Stop emulation\n");
- if (loglevel)
- fprintf(logfile, "RESET asked... Stop emulation\n");
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_OBJERR;
- info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(info.si_signo, &info);
- case EXCP_DSI:
- fprintf(stderr, "Invalid data memory access: 0x%08x\n",
- env->spr[SPR_DAR]);
- if (loglevel) {
- fprintf(logfile, "Invalid data memory access: 0x%08x\n",
- env->spr[SPR_DAR]);
- }
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ cpu_abort(env, "Machine check exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ EXCP_DUMP(env, "Invalid data memory access: 0x" ADDRX "\n",
+ env->spr[SPR_DAR]);
+ /* XXX: check this. Seems bugged */
switch (env->error_code & 0xFF000000) {
case 0x40000000:
info.si_signo = TARGET_SIGSEGV;
@@ -762,12 +761,8 @@ void cpu_loop(CPUPPCState *env)
break;
default:
/* Let's send a regular segfault... */
- fprintf(stderr, "Invalid segfault errno (%02x)\n",
- env->error_code);
- if (loglevel) {
- fprintf(logfile, "Invalid segfault errno (%02x)\n",
- env->error_code);
- }
+ EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
+ env->error_code);
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
@@ -776,10 +771,10 @@ void cpu_loop(CPUPPCState *env)
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
- case EXCP_ISI:
- fprintf(stderr, "Invalid instruction fetch\n");
- if (loglevel)
- fprintf(logfile, "Invalid instruction fetch\n");
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n",
+ env->spr[SPR_DAR]);
+ /* XXX: check this */
switch (env->error_code & 0xFF000000) {
case 0x40000000:
info.si_signo = TARGET_SIGSEGV;
@@ -794,12 +789,8 @@ void cpu_loop(CPUPPCState *env)
break;
default:
/* Let's send a regular segfault... */
- fprintf(stderr, "Invalid segfault errno (%02x)\n",
- env->error_code);
- if (loglevel) {
- fprintf(logfile, "Invalid segfault errno (%02x)\n",
- env->error_code);
- }
+ EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
+ env->error_code);
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
@@ -808,28 +799,24 @@ void cpu_loop(CPUPPCState *env)
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
- case EXCP_EXTERNAL:
- /* Should not happen ! */
- fprintf(stderr, "External interruption... Stop emulation\n");
- if (loglevel)
- fprintf(logfile, "External interruption... Stop emulation\n");
- abort();
- case EXCP_ALIGN:
- fprintf(stderr, "Invalid unaligned memory access\n");
- if (loglevel)
- fprintf(logfile, "Invalid unaligned memory access\n");
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ cpu_abort(env, "External interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ EXCP_DUMP(env, "Unaligned memory access\n");
+ /* XXX: check this */
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
- case EXCP_PROGRAM:
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ /* XXX: check this */
switch (env->error_code & ~0xF) {
- case EXCP_FP:
- fprintf(stderr, "Program exception\n");
- if (loglevel)
- fprintf(logfile, "Program exception\n");
+ case POWERPC_EXCP_FP:
+ EXCP_DUMP(env, "Floating point program exception\n");
/* Set FX */
env->fpscr[7] |= 0x8;
/* Finally, update FEX */
@@ -839,155 +826,138 @@ void cpu_loop(CPUPPCState *env)
info.si_signo = TARGET_SIGFPE;
info.si_errno = 0;
switch (env->error_code & 0xF) {
- case EXCP_FP_OX:
+ case POWERPC_EXCP_FP_OX:
info.si_code = TARGET_FPE_FLTOVF;
break;
- case EXCP_FP_UX:
+ case POWERPC_EXCP_FP_UX:
info.si_code = TARGET_FPE_FLTUND;
break;
- case EXCP_FP_ZX:
- case EXCP_FP_VXZDZ:
+ case POWERPC_EXCP_FP_ZX:
+ case POWERPC_EXCP_FP_VXZDZ:
info.si_code = TARGET_FPE_FLTDIV;
break;
- case EXCP_FP_XX:
+ case POWERPC_EXCP_FP_XX:
info.si_code = TARGET_FPE_FLTRES;
break;
- case EXCP_FP_VXSOFT:
+ case POWERPC_EXCP_FP_VXSOFT:
info.si_code = TARGET_FPE_FLTINV;
break;
- case EXCP_FP_VXNAN:
- case EXCP_FP_VXISI:
- case EXCP_FP_VXIDI:
- case EXCP_FP_VXIMZ:
- case EXCP_FP_VXVC:
- case EXCP_FP_VXSQRT:
- case EXCP_FP_VXCVI:
+ case POWERPC_EXCP_FP_VXNAN:
+ case POWERPC_EXCP_FP_VXISI:
+ case POWERPC_EXCP_FP_VXIDI:
+ case POWERPC_EXCP_FP_VXIMZ:
+ case POWERPC_EXCP_FP_VXVC:
+ case POWERPC_EXCP_FP_VXSQRT:
+ case POWERPC_EXCP_FP_VXCVI:
info.si_code = TARGET_FPE_FLTSUB;
break;
default:
- fprintf(stderr, "Unknown floating point exception "
- "(%02x)\n", env->error_code);
- if (loglevel) {
- fprintf(logfile, "Unknown floating point exception "
- "(%02x)\n", env->error_code & 0xF);
- }
+ EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
+ env->error_code);
+ break;
}
- break;
- case EXCP_INVAL:
- fprintf(stderr, "Invalid instruction\n");
- if (loglevel)
- fprintf(logfile, "Invalid instruction\n");
+ break;
+ case POWERPC_EXCP_INVAL:
+ EXCP_DUMP(env, "Invalid instruction\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) {
- case EXCP_INVAL_INVAL:
+ case POWERPC_EXCP_INVAL_INVAL:
info.si_code = TARGET_ILL_ILLOPC;
break;
- case EXCP_INVAL_LSWX:
- info.si_code = TARGET_ILL_ILLOPN;
+ case POWERPC_EXCP_INVAL_LSWX:
+ info.si_code = TARGET_ILL_ILLOPN;
break;
- case EXCP_INVAL_SPR:
+ case POWERPC_EXCP_INVAL_SPR:
info.si_code = TARGET_ILL_PRVREG;
break;
- case EXCP_INVAL_FP:
+ case POWERPC_EXCP_INVAL_FP:
info.si_code = TARGET_ILL_COPROC;
break;
default:
- fprintf(stderr, "Unknown invalid operation (%02x)\n",
- env->error_code & 0xF);
- if (loglevel) {
- fprintf(logfile, "Unknown invalid operation (%02x)\n",
- env->error_code & 0xF);
- }
+ EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
+ env->error_code & 0xF);
info.si_code = TARGET_ILL_ILLADR;
break;
}
break;
- case EXCP_PRIV:
- fprintf(stderr, "Privilege violation\n");
- if (loglevel)
- fprintf(logfile, "Privilege violation\n");
+ case POWERPC_EXCP_PRIV:
+ EXCP_DUMP(env, "Privilege violation\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) {
- case EXCP_PRIV_OPC:
+ case POWERPC_EXCP_PRIV_OPC:
info.si_code = TARGET_ILL_PRVOPC;
break;
- case EXCP_PRIV_REG:
+ case POWERPC_EXCP_PRIV_REG:
info.si_code = TARGET_ILL_PRVREG;
- break;
+ break;
default:
- fprintf(stderr, "Unknown privilege violation (%02x)\n",
- env->error_code & 0xF);
+ EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
+ env->error_code & 0xF);
info.si_code = TARGET_ILL_PRVOPC;
break;
}
break;
- case EXCP_TRAP:
- fprintf(stderr, "Tried to call a TRAP\n");
- if (loglevel)
- fprintf(logfile, "Tried to call a TRAP\n");
- abort();
+ case POWERPC_EXCP_TRAP:
+ cpu_abort(env, "Tried to call a TRAP\n");
+ break;
default:
/* Should not happen ! */
- fprintf(stderr, "Unknown program exception (%02x)\n",
- env->error_code);
- if (loglevel) {
- fprintf(logfile, "Unknwon program exception (%02x)\n",
- env->error_code);
- }
- abort();
+ cpu_abort(env, "Unknown program exception (%02x)\n",
+ env->error_code);
+ break;
}
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
- case EXCP_NO_FP:
- fprintf(stderr, "No floating point allowed\n");
- if (loglevel)
- fprintf(logfile, "No floating point allowed\n");
+ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
+ EXCP_DUMP(env, "No floating point allowed\n");
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
- case EXCP_DECR:
- /* Should not happen ! */
- fprintf(stderr, "Decrementer exception\n");
- if (loglevel)
- fprintf(logfile, "Decrementer exception\n");
- abort();
- case EXCP_TRACE:
- /* Do nothing: we use this to trace execution */
- break;
- case EXCP_FP_ASSIST:
- /* Should not happen ! */
- fprintf(stderr, "Floating point assist exception\n");
- if (loglevel)
- fprintf(logfile, "Floating point assist exception\n");
- abort();
- case EXCP_MTMSR:
- /* We reloaded the msr, just go on */
- if (msr_pr == 0) {
- fprintf(stderr, "Tried to go into supervisor mode !\n");
- if (loglevel)
- fprintf(logfile, "Tried to go into supervisor mode !\n");
- abort();
- }
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ cpu_abort(env, "Syscall exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
+ EXCP_DUMP(env, "No APU instruction allowed\n");
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_COPROC;
+ info._sifields._sigfault._addr = env->nip - 4;
+ queue_signal(info.si_signo, &info);
break;
- case EXCP_BRANCH:
- /* We stopped because of a jump... */
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ cpu_abort(env, "Decrementer interrupt while in user mode. "
+ "Aborting\n");
break;
- case EXCP_INTERRUPT:
- /* Don't know why this should ever happen... */
+ case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
+ cpu_abort(env, "Fix interval timer interrupt while in user mode. "
+ "Aborting\n");
break;
- case EXCP_DEBUG:
+ case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
+ cpu_abort(env, "Watchdog timer interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_DTLB: /* Data TLB error */
+ cpu_abort(env, "Data TLB exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_ITLB: /* Instruction TLB error */
+ cpu_abort(env, "Instruction TLB exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_DEBUG: /* Debug interrupt */
+ /* XXX: check this */
{
int sig;
- sig = gdb_handlesig (env, TARGET_SIGTRAP);
- if (sig)
- {
+ sig = gdb_handlesig(env, TARGET_SIGTRAP);
+ if (sig) {
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
@@ -995,14 +965,174 @@ void cpu_loop(CPUPPCState *env)
}
}
break;
- default:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
- trapnr);
- if (loglevel) {
- fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
- "0x%02x - aborting\n", trapnr, env->error_code);
+#if defined(TARGET_PPCEMB)
+ case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
+ EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_COPROC;
+ info._sifields._sigfault._addr = env->nip - 4;
+ queue_signal(info.si_signo, &info);
+ break;
+ case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
+ cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
+ break;
+ case POWERPC_EXCP_EFPRI: /* Embedded floating-point round IRQ */
+ cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
+ break;
+ case POWERPC_EXCP_EPERFM: /* Embedded performance monitor IRQ */
+ cpu_abort(env, "Performance monitor exception not handled\n");
+ break;
+ case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
+ cpu_abort(env, "Doorbell interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
+ cpu_abort(env, "Doorbell critical interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ cpu_abort(env, "Reset interrupt while in user mode. "
+ "Aborting\n");
+ break;
+#endif /* defined(TARGET_PPCEMB) */
+#if defined(TARGET_PPC64) /* PowerPC 64 */
+ case POWERPC_EXCP_DSEG: /* Data segment exception */
+ cpu_abort(env, "Data segment exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_ISEG: /* Instruction segment exception */
+ cpu_abort(env, "Instruction segment exception "
+ "while in user mode. Aborting\n");
+ break;
+#endif /* defined(TARGET_PPC64) */
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+ case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
+ cpu_abort(env, "Hypervisor decrementer interrupt "
+ "while in user mode. Aborting\n");
+ break;
+#endif /* defined(TARGET_PPC64H) */
+ case POWERPC_EXCP_TRACE: /* Trace exception */
+ /* Nothing to do:
+ * we use this exception to emulate step-by-step execution mode.
+ */
+ break;
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
+ cpu_abort(env, "Hypervisor data storage exception "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_HISI: /* Hypervisor instruction storage excp */
+ cpu_abort(env, "Hypervisor instruction storage exception "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
+ cpu_abort(env, "Hypervisor data segment exception "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment excp */
+ cpu_abort(env, "Hypervisor instruction segment exception "
+ "while in user mode. Aborting\n");
+ break;
+#endif /* defined(TARGET_PPC64H) */
+ case POWERPC_EXCP_VPU: /* Vector unavailable exception */
+ EXCP_DUMP(env, "No Altivec instructions allowed\n");
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_COPROC;
+ info._sifields._sigfault._addr = env->nip - 4;
+ queue_signal(info.si_signo, &info);
+ break;
+ case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
+ cpu_abort(env, "Programable interval timer interrupt "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_IO: /* IO error exception */
+ cpu_abort(env, "IO error exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_RUNM: /* Run mode exception */
+ cpu_abort(env, "Run mode exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_EMUL: /* Emulation trap exception */
+ cpu_abort(env, "Emulation trap exception not handled\n");
+ break;
+ case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
+ cpu_abort(env, "Instruction fetch TLB exception "
+ "while in user-mode. Aborting");
+ break;
+ case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
+ cpu_abort(env, "Data load TLB exception while in user-mode. "
+ "Aborting");
+ break;
+ case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
+ cpu_abort(env, "Data store TLB exception while in user-mode. "
+ "Aborting");
+ break;
+ case POWERPC_EXCP_FPA: /* Floating-point assist exception */
+ cpu_abort(env, "Floating-point assist exception not handled\n");
+ break;
+ case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
+ cpu_abort(env, "Instruction address breakpoint exception "
+ "not handled\n");
+ break;
+ case POWERPC_EXCP_SMI: /* System management interrupt */
+ cpu_abort(env, "System management interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_THERM: /* Thermal interrupt */
+ cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_PERFM: /* Embedded performance monitor IRQ */
+ cpu_abort(env, "Performance monitor exception not handled\n");
+ break;
+ case POWERPC_EXCP_VPUA: /* Vector assist exception */
+ cpu_abort(env, "Vector assist exception not handled\n");
+ break;
+ case POWERPC_EXCP_SOFTP: /* Soft patch exception */
+ cpu_abort(env, "Soft patch exception not handled\n");
+ break;
+ case POWERPC_EXCP_MAINT: /* Maintenance exception */
+ cpu_abort(env, "Maintenance exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_STOP: /* stop translation */
+ /* We did invalidate the instruction cache. Go on */
+ break;
+ case POWERPC_EXCP_BRANCH: /* branch instruction: */
+ /* We just stopped because of a branch. Go on */
+ break;
+ case POWERPC_EXCP_SYSCALL_USER:
+ /* system call in user-mode emulation */
+ /* WARNING:
+ * PPC ABI uses overflow flag in cr0 to signal an error
+ * in syscalls.
+ */
+#if 0
+ printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
+ env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
+#endif
+ env->crf[0] &= ~0x1;
+ ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+ env->gpr[5], env->gpr[6], env->gpr[7],
+ env->gpr[8]);
+ if (ret > (uint32_t)(-515)) {
+ env->crf[0] |= 0x1;
+ ret = -ret;
}
- abort();
+ env->gpr[3] = ret;
+#if 0
+ printf("syscall returned 0x%08x (%d)\n", ret, ret);
+#endif
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ default:
+ cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
+ break;
}
process_pending_signals(env);
}
@@ -1295,8 +1425,41 @@ static const uint8_t mips_syscall_args[] = {
MIPS_SYS(sys_waitid , 4)
MIPS_SYS(sys_ni_syscall , 0) /* available, was setaltroot */
MIPS_SYS(sys_add_key , 5)
- MIPS_SYS(sys_request_key , 4)
+ MIPS_SYS(sys_request_key, 4)
MIPS_SYS(sys_keyctl , 5)
+ MIPS_SYS(sys_set_thread_area, 1)
+ MIPS_SYS(sys_inotify_init, 0)
+ MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
+ MIPS_SYS(sys_inotify_rm_watch, 2)
+ MIPS_SYS(sys_migrate_pages, 4)
+ MIPS_SYS(sys_openat, 4)
+ MIPS_SYS(sys_mkdirat, 3)
+ MIPS_SYS(sys_mknodat, 4) /* 4290 */
+ MIPS_SYS(sys_fchownat, 5)
+ MIPS_SYS(sys_futimesat, 3)
+ MIPS_SYS(sys_fstatat64, 4)
+ MIPS_SYS(sys_unlinkat, 3)
+ MIPS_SYS(sys_renameat, 4) /* 4295 */
+ MIPS_SYS(sys_linkat, 5)
+ MIPS_SYS(sys_symlinkat, 3)
+ MIPS_SYS(sys_readlinkat, 4)
+ MIPS_SYS(sys_fchmodat, 3)
+ MIPS_SYS(sys_faccessat, 3) /* 4300 */
+ MIPS_SYS(sys_pselect6, 6)
+ MIPS_SYS(sys_ppoll, 5)
+ MIPS_SYS(sys_unshare, 1)
+ MIPS_SYS(sys_splice, 4)
+ MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
+ MIPS_SYS(sys_tee, 4)
+ MIPS_SYS(sys_vmsplice, 4)
+ MIPS_SYS(sys_move_pages, 6)
+ MIPS_SYS(sys_set_robust_list, 2)
+ MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
+ MIPS_SYS(sys_kexec_load, 4)
+ MIPS_SYS(sys_getcpu, 3)
+ MIPS_SYS(sys_epoll_pwait, 6)
+ MIPS_SYS(sys_ioprio_set, 3)
+ MIPS_SYS(sys_ioprio_get, 2)
};
#undef MIPS_SYS
@@ -1304,53 +1467,47 @@ static const uint8_t mips_syscall_args[] = {
void cpu_loop(CPUMIPSState *env)
{
target_siginfo_t info;
- int trapnr, ret, nb_args;
+ int trapnr, ret;
unsigned int syscall_num;
- target_ulong arg5, arg6, sp_reg;
for(;;) {
trapnr = cpu_mips_exec(env);
switch(trapnr) {
case EXCP_SYSCALL:
- {
- syscall_num = env->gpr[2] - 4000;
- env->PC += 4;
- if (syscall_num >= sizeof(mips_syscall_args)) {
- ret = -ENOSYS;
- } else {
- nb_args = mips_syscall_args[syscall_num];
- if (nb_args >= 5) {
- sp_reg = env->gpr[29];
- /* these arguments are taken from the stack */
- arg5 = tgetl(sp_reg + 16);
- if (nb_args >= 6) {
- arg6 = tgetl(sp_reg + 20);
- } else {
- arg6 = 0;
- }
- } else {
- arg5 = 0;
- arg6 = 0;
- }
- ret = do_syscall(env,
- env->gpr[2],
- env->gpr[4],
- env->gpr[5],
- env->gpr[6],
- env->gpr[7],
- arg5,
- arg6);
- }
- if ((unsigned int)ret >= (unsigned int)(-1133)) {
- env->gpr[7] = 1; /* error flag */
- ret = -ret;
- env->gpr[0] = ret;
- env->gpr[2] = ret;
- } else {
- env->gpr[7] = 0; /* error flag */
- env->gpr[2] = ret;
+ syscall_num = env->gpr[2][env->current_tc] - 4000;
+ env->PC[env->current_tc] += 4;
+ if (syscall_num >= sizeof(mips_syscall_args)) {
+ ret = -ENOSYS;
+ } else {
+ int nb_args;
+ target_ulong sp_reg;
+ target_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
+
+ nb_args = mips_syscall_args[syscall_num];
+ sp_reg = env->gpr[29][env->current_tc];
+ switch (nb_args) {
+ /* these arguments are taken from the stack */
+ case 8: arg8 = tgetl(sp_reg + 28);
+ case 7: arg7 = tgetl(sp_reg + 24);
+ case 6: arg6 = tgetl(sp_reg + 20);
+ case 5: arg5 = tgetl(sp_reg + 16);
+ default:
+ break;
}
+ ret = do_syscall(env, env->gpr[2][env->current_tc],
+ env->gpr[4][env->current_tc],
+ env->gpr[5][env->current_tc],
+ env->gpr[6][env->current_tc],
+ env->gpr[7][env->current_tc],
+ arg5, arg6/*, arg7, arg8*/);
}
+ if ((unsigned int)ret >= (unsigned int)(-1133)) {
+ env->gpr[7][env->current_tc] = 1; /* error flag */
+ ret = -ret;
+ } else {
+ env->gpr[7][env->current_tc] = 0; /* error flag */
+ }
+ env->gpr[2][env->current_tc] = ret;
break;
case EXCP_TLBL:
case EXCP_TLBS:
@@ -1380,7 +1537,7 @@ void cpu_loop(CPUMIPSState *env)
break;
default:
// error:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+ fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
abort();
@@ -1395,19 +1552,19 @@ void cpu_loop (CPUState *env)
{
int trapnr, ret;
target_siginfo_t info;
-
+
while (1) {
trapnr = cpu_sh4_exec (env);
-
+
switch (trapnr) {
case 0x160:
- ret = do_syscall(env,
- env->gregs[3],
- env->gregs[4],
- env->gregs[5],
- env->gregs[6],
- env->gregs[7],
- env->gregs[0],
+ ret = do_syscall(env,
+ env->gregs[3],
+ env->gregs[4],
+ env->gregs[5],
+ env->gregs[6],
+ env->gregs[7],
+ env->gregs[0],
0);
env->gregs[0] = ret;
env->pc += 2;
@@ -1444,7 +1601,7 @@ void cpu_loop(CPUM68KState *env)
unsigned int n;
target_siginfo_t info;
TaskState *ts = env->opaque;
-
+
for(;;) {
trapnr = cpu_m68k_exec(env);
switch(trapnr) {
@@ -1460,9 +1617,9 @@ void cpu_loop(CPUM68KState *env)
}
}
break;
- case EXCP_HALTED:
+ case EXCP_HALT_INSN:
/* Semihosing syscall. */
- env->pc += 2;
+ env->pc += 4;
do_m68k_semihosting(env, env->dregs[0]);
break;
case EXCP_LINEA:
@@ -1480,8 +1637,8 @@ void cpu_loop(CPUM68KState *env)
ts->sim_syscalls = 0;
n = env->dregs[0];
env->pc += 2;
- env->dregs[0] = do_syscall(env,
- n,
+ env->dregs[0] = do_syscall(env,
+ n,
env->dregs[1],
env->dregs[2],
env->dregs[3],
@@ -1518,7 +1675,7 @@ void cpu_loop(CPUM68KState *env)
}
break;
default:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+ fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
abort();
@@ -1528,16 +1685,108 @@ void cpu_loop(CPUM68KState *env)
}
#endif /* TARGET_M68K */
+#ifdef TARGET_ALPHA
+void cpu_loop (CPUState *env)
+{
+ int trapnr;
+ target_siginfo_t info;
+
+ while (1) {
+ trapnr = cpu_alpha_exec (env);
+
+ switch (trapnr) {
+ case EXCP_RESET:
+ fprintf(stderr, "Reset requested. Exit\n");
+ exit(1);
+ break;
+ case EXCP_MCHK:
+ fprintf(stderr, "Machine check exception. Exit\n");
+ exit(1);
+ break;
+ case EXCP_ARITH:
+ fprintf(stderr, "Arithmetic trap.\n");
+ exit(1);
+ break;
+ case EXCP_HW_INTERRUPT:
+ fprintf(stderr, "External interrupt. Exit\n");
+ exit(1);
+ break;
+ case EXCP_DFAULT:
+ fprintf(stderr, "MMU data fault\n");
+ exit(1);
+ break;
+ case EXCP_DTB_MISS_PAL:
+ fprintf(stderr, "MMU data TLB miss in PALcode\n");
+ exit(1);
+ break;
+ case EXCP_ITB_MISS:
+ fprintf(stderr, "MMU instruction TLB miss\n");
+ exit(1);
+ break;
+ case EXCP_ITB_ACV:
+ fprintf(stderr, "MMU instruction access violation\n");
+ exit(1);
+ break;
+ case EXCP_DTB_MISS_NATIVE:
+ fprintf(stderr, "MMU data TLB miss\n");
+ exit(1);
+ break;
+ case EXCP_UNALIGN:
+ fprintf(stderr, "Unaligned access\n");
+ exit(1);
+ break;
+ case EXCP_OPCDEC:
+ fprintf(stderr, "Invalid instruction\n");
+ exit(1);
+ break;
+ case EXCP_FEN:
+ fprintf(stderr, "Floating-point not allowed\n");
+ exit(1);
+ break;
+ case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
+ fprintf(stderr, "Call to PALcode\n");
+ call_pal(env, (trapnr >> 6) | 0x80);
+ break;
+ case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1):
+ fprintf(stderr, "Privileged call to PALcode\n");
+ exit(1);
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(info.si_signo, &info);
+ }
+ }
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ exit (1);
+ }
+ process_pending_signals (env);
+ }
+}
+#endif /* TARGET_ALPHA */
+
void usage(void)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
- "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n"
+ "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] [-cpu model] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
- "-h print this help\n"
- "-g port wait gdb connection to port\n"
- "-L path set the elf interpreter prefix (default=%s)\n"
- "-s size set the stack size in bytes (default=%ld)\n"
+ "-h print this help\n"
+ "-g port wait gdb connection to port\n"
+ "-L path set the elf interpreter prefix (default=%s)\n"
+ "-s size set the stack size in bytes (default=%ld)\n"
+ "-cpu model select CPU (-cpu ? for list)\n"
+ "-drop-ld-preload drop LD_PRELOAD for target process\n"
"\n"
"debug options:\n"
#ifdef USE_CODE_COPY
@@ -1546,7 +1795,7 @@ void usage(void)
"-d options activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n",
TARGET_ARCH,
- interp_prefix,
+ interp_prefix,
x86_stack_size,
DEBUG_LOGFILE);
_exit(1);
@@ -1561,6 +1810,7 @@ TaskState *first_task_state;
int main(int argc, char **argv)
{
const char *filename;
+ const char *cpu_model;
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
@@ -1568,13 +1818,16 @@ int main(int argc, char **argv)
int optind;
const char *r;
int gdbstub_port = 0;
-
+ int drop_ld_preload = 0, environ_count = 0;
+ char **target_environ, **wrk, **dst;
+
if (argc <= 1)
usage();
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
+ cpu_model = NULL;
optind = 1;
for(;;) {
if (optind >= argc)
@@ -1592,7 +1845,7 @@ int main(int argc, char **argv)
if (optind >= argc)
break;
-
+
r = argv[optind++];
mask = cpu_str_to_log_mask(r);
if (!mask) {
@@ -1625,11 +1878,27 @@ int main(int argc, char **argv)
gdbstub_port = atoi(argv[optind++]);
} else if (!strcmp(r, "r")) {
qemu_uname_release = argv[optind++];
- } else
+ } else if (!strcmp(r, "cpu")) {
+ cpu_model = argv[optind++];
+ if (strcmp(cpu_model, "?") == 0) {
+#if defined(TARGET_PPC)
+ ppc_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_ARM)
+ arm_cpu_list();
+#elif defined(TARGET_MIPS)
+ mips_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_SPARC)
+ sparc_cpu_list(stdout, &fprintf);
+#endif
+ _exit(1);
+ }
+ } else if (!strcmp(r, "drop-ld-preload")) {
+ drop_ld_preload = 1;
+ } else
#ifdef USE_CODE_COPY
if (!strcmp(r, "no-code-copy")) {
code_copy_enabled = 0;
- } else
+ } else
#endif
{
usage();
@@ -1652,15 +1921,35 @@ int main(int argc, char **argv)
qemu_host_page_size */
env = cpu_init();
global_env = env;
-
- if (loader_exec(filename, argv+optind, environ, regs, info) != 0) {
- printf("Error loading %s\n", filename);
- _exit(1);
+
+ wrk = environ;
+ while (*(wrk++))
+ environ_count++;
+
+ target_environ = malloc((environ_count + 1) * sizeof(char *));
+ if (!target_environ)
+ abort();
+ for (wrk = environ, dst = target_environ; *wrk; wrk++) {
+ if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11))
+ continue;
+ *(dst++) = strdup(*wrk);
}
-
+ *dst = NULL; /* NULL terminate target_environ */
+
+ if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+ printf("Error loading %s\n", filename);
+ _exit(1);
+ }
+
+ for (wrk = target_environ; *wrk; wrk++) {
+ free(*wrk);
+ }
+
+ free(target_environ);
+
if (loglevel) {
page_dump(logfile);
-
+
fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
@@ -1681,7 +1970,7 @@ int main(int argc, char **argv)
ts->used = 1;
ts->info = info;
env->user_mode_only = 1;
-
+
#if defined(TARGET_I386)
cpu_x86_set_cpl(env, 3);
@@ -1694,8 +1983,19 @@ int main(int argc, char **argv)
/* flags setup : we activate the IRQs by default as in user mode */
env->eflags |= IF_MASK;
-
+
/* linux register setup */
+#if defined(TARGET_X86_64)
+ env->regs[R_EAX] = regs->rax;
+ env->regs[R_EBX] = regs->rbx;
+ env->regs[R_ECX] = regs->rcx;
+ env->regs[R_EDX] = regs->rdx;
+ env->regs[R_ESI] = regs->rsi;
+ env->regs[R_EDI] = regs->rdi;
+ env->regs[R_EBP] = regs->rbp;
+ env->regs[R_ESP] = regs->rsp;
+ env->eip = regs->rip;
+#else
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
env->regs[R_ECX] = regs->ecx;
@@ -1705,6 +2005,7 @@ int main(int argc, char **argv)
env->regs[R_EBP] = regs->ebp;
env->regs[R_ESP] = regs->esp;
env->eip = regs->eip;
+#endif
/* linux interrupt setup */
env->idt.base = h2g(idt_table);
@@ -1735,10 +2036,10 @@ int main(int argc, char **argv)
env->gdt.base = h2g(gdt_table);
env->gdt.limit = sizeof(gdt_table) - 1;
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
cpu_x86_load_seg(env, R_CS, __USER_CS);
cpu_x86_load_seg(env, R_DS, __USER_DS);
@@ -1747,22 +2048,36 @@ int main(int argc, char **argv)
cpu_x86_load_seg(env, R_FS, __USER_DS);
cpu_x86_load_seg(env, R_GS, __USER_DS);
+ /* This hack makes Wine work... */
+ env->segs[R_FS].selector = 0;
#elif defined(TARGET_ARM)
{
int i;
- cpu_arm_set_model(env, ARM_CPUID_ARM1026);
+ if (cpu_model == NULL)
+ cpu_model = "arm926";
+ cpu_arm_set_model(env, cpu_model);
cpsr_write(env, regs->uregs[16], 0xffffffff);
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
}
- ts->stack_base = info->start_stack;
- ts->heap_base = info->brk;
- /* This will be filled in on the first SYS_HEAPINFO call. */
- ts->heap_limit = 0;
}
#elif defined(TARGET_SPARC)
{
int i;
+ const sparc_def_t *def;
+#ifdef TARGET_SPARC64
+ if (cpu_model == NULL)
+ cpu_model = "TI UltraSparc II";
+#else
+ if (cpu_model == NULL)
+ cpu_model = "Fujitsu MB86904";
+#endif
+ sparc_find_by_name(cpu_model, &def);
+ if (def == NULL) {
+ fprintf(stderr, "Unable to find Sparc CPU definition\n");
+ exit(1);
+ }
+ cpu_sparc_register(env, def);
env->pc = regs->pc;
env->npc = regs->npc;
env->y = regs->y;
@@ -1777,15 +2092,9 @@ int main(int argc, char **argv)
int i;
/* Choose and initialise CPU */
- /* XXX: CPU model (or PVR) should be provided on command line */
- // ppc_find_by_name("750gx", &def);
- // ppc_find_by_name("750fx", &def);
- // ppc_find_by_name("750p", &def);
- ppc_find_by_name("750", &def);
- // ppc_find_by_name("G3", &def);
- // ppc_find_by_name("604r", &def);
- // ppc_find_by_name("604e", &def);
- // ppc_find_by_name("604", &def);
+ if (cpu_model == NULL)
+ cpu_model = "750";
+ ppc_find_by_name(cpu_model, &def);
if (def == NULL) {
cpu_abort(env,
"Unable to find PowerPC CPU definition\n");
@@ -1796,6 +2105,9 @@ int main(int argc, char **argv)
if (i != 12 && i != 6 && i != 13)
env->msr[i] = (regs->msr >> i) & 1;
}
+#if defined(TARGET_PPC64)
+ msr_sf = 1;
+#endif
env->nip = regs->nip;
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->gpr[i];
@@ -1803,13 +2115,12 @@ int main(int argc, char **argv)
}
#elif defined(TARGET_M68K)
{
- m68k_def_t *def;
- def = m68k_find_by_name("cfv4e");
- if (def == NULL) {
+ if (cpu_model == NULL)
+ cpu_model = "any";
+ if (cpu_m68k_set_model(env, cpu_model)) {
cpu_abort(cpu_single_env,
"Unable to find m68k CPU definition\n");
}
- cpu_m68k_register(cpu_single_env, def);
env->pc = regs->pc;
env->dregs[0] = regs->d0;
env->dregs[1] = regs->d1;
@@ -1832,15 +2143,25 @@ int main(int argc, char **argv)
}
#elif defined(TARGET_MIPS)
{
+ mips_def_t *def;
int i;
+ /* Choose and initialise CPU */
+ if (cpu_model == NULL)
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+ cpu_model = "20Kc";
+#else
+ cpu_model = "24Kf";
+#endif
+ mips_find_by_name(cpu_model, &def);
+ if (def == NULL)
+ cpu_abort(env, "Unable to find MIPS CPU definition\n");
+ cpu_mips_register(env, def);
+
for(i = 0; i < 32; i++) {
- env->gpr[i] = regs->regs[i];
+ env->gpr[i][env->current_tc] = regs->regs[i];
}
- env->PC = regs->cp0_epc;
-#ifdef MIPS_USES_FPU
- env->CP0_Status |= (1 << CP0St_CU1);
-#endif
+ env->PC[env->current_tc] = regs->cp0_epc;
}
#elif defined(TARGET_SH4)
{
@@ -1851,10 +2172,29 @@ int main(int argc, char **argv)
}
env->pc = regs->pc;
}
+#elif defined(TARGET_ALPHA)
+ {
+ int i;
+
+ for(i = 0; i < 28; i++) {
+ env->ir[i] = ((target_ulong *)regs)[i];
+ }
+ env->ipr[IPR_USP] = regs->usp;
+ env->ir[30] = regs->usp;
+ env->pc = regs->pc;
+ env->unique = regs->unique;
+ }
#else
#error unsupported target CPU
#endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
+ ts->stack_base = info->start_stack;
+ ts->heap_base = info->brk;
+ /* This will be filled in on the first SYS_HEAPINFO call. */
+ ts->heap_limit = 0;
+#endif
+
if (gdbstub_port) {
gdbserver_start (gdbstub_port);
gdb_handlesig(env, 0);