aboutsummaryrefslogtreecommitdiff
path: root/linux-user/main.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-01-04 23:54:31 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-01-04 23:54:31 +0000
commit61190b14fc96d4e19c9bdde25643be4c5eb90e62 (patch)
treebfb0320d9d19f5599b5b3bafea0a93c88ec3c9c9 /linux-user/main.c
parent9886cc165ac2c594f62a597de2c7b4df9922e2e6 (diff)
PowerPC update (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@536 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user/main.c')
-rw-r--r--linux-user/main.c401
1 files changed, 315 insertions, 86 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index 2c9fe3cd64..8bc57a9e94 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -59,44 +59,44 @@ void gemu_log(const char *fmt, ...)
va_end(ap);
}
-#ifdef TARGET_I386
-/***********************************************************/
-/* CPUX86 core interface */
-
-void cpu_x86_outb(CPUX86State *env, int addr, int val)
+void cpu_outb(CPUState *env, int addr, int val)
{
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
}
-void cpu_x86_outw(CPUX86State *env, int addr, int val)
+void cpu_outw(CPUState *env, int addr, int val)
{
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
}
-void cpu_x86_outl(CPUX86State *env, int addr, int val)
+void cpu_outl(CPUState *env, int addr, int val)
{
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
}
-int cpu_x86_inb(CPUX86State *env, int addr)
+int cpu_inb(CPUState *env, int addr)
{
fprintf(stderr, "inb: port=0x%04x\n", addr);
return 0;
}
-int cpu_x86_inw(CPUX86State *env, int addr)
+int cpu_inw(CPUState *env, int addr)
{
fprintf(stderr, "inw: port=0x%04x\n", addr);
return 0;
}
-int cpu_x86_inl(CPUX86State *env, int addr)
+int cpu_inl(CPUState *env, int addr)
{
fprintf(stderr, "inl: port=0x%04x\n", addr);
return 0;
}
-int cpu_x86_get_pic_interrupt(CPUX86State *env)
+#ifdef TARGET_I386
+/***********************************************************/
+/* CPUX86 core interface */
+
+int cpu_x86_get_pic_interrupt(CPUState *env)
{
return -1;
}
@@ -428,119 +428,346 @@ void cpu_loop (CPUSPARCState *env)
void cpu_loop(CPUPPCState *env)
{
- int trapnr;
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_ppc_dump_state(env, logfile, 0);
+ }
+ }
switch(trapnr) {
case EXCP_NONE:
- case EXCP_INTERRUPT:
- case EXCP_MTMSR: /* mtmsr instruction: */
- case EXCP_BRANCH: /* branch instruction */
- /* Single step mode */
break;
+ case EXCP_SYSCALL_USER:
+ /* system call */
+ /* WARNING:
+ * PPC ABI uses overflow flag in cr0 to signal an error
+ * in syscalls.
+ */
#if 0
- case EXCP_RESET: /* System reset */
- fprintf(stderr, "RESET asked... Stop emulation\n");
- cpu_ppc_dump_state(env, stderr, 0);
- abort();
+ 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
- case EXCP_MACHINE_CHECK: /* Machine check exception */
- fprintf(stderr, "Machine check exeption... "
- "See you in kernel code !\n");
- cpu_ppc_dump_state(env, stderr, 0);
+ 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
+ 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_DSI: /* Impossible memory access */
- fprintf(stderr, "Invalid memory access\n");
- info.si_signo = SIGSEGV;
+ 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_ILL_ILLOPN;
+ 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[DAR]);
+ if (loglevel) {
+ fprintf(logfile, "Invalid data memory access: 0x%08x\n",
+ env->spr[DAR]);
+ }
+ switch (env->error_code & 0xF) {
+ case EXCP_DSI_TRANSLATE:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ case EXCP_DSI_NOTSUP:
+ case EXCP_DSI_EXTERNAL:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLADR;
+ break;
+ case EXCP_DSI_PROT:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_ACCERR;
+ break;
+ case EXCP_DSI_DABR:
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ 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);
+ }
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ }
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
- case EXCP_ISI: /* Impossible instruction fetch */
+ case EXCP_ISI:
fprintf(stderr, "Invalid instruction fetch\n");
- info.si_signo = SIGBUS;
+ if (loglevel)
+ fprintf(logfile, "Invalid instruction fetch\n");
+ switch (env->error_code) {
+ case EXCP_ISI_TRANSLATE:
+ info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->nip;
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ case EXCP_ISI_GUARD:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLADR;
+ break;
+ case EXCP_ISI_NOEXEC:
+ case EXCP_ISI_PROT:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_ACCERR;
+ 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);
+ }
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ }
+ info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
- case EXCP_EXTERNAL: /* External interruption */
- fprintf(stderr, "External access exeption\n");
- cpu_ppc_dump_state(env, stderr, 0);
- abort();
- case EXCP_ALIGN: /* Alignment exception */
- fprintf(stderr, "Alignment exception\n");
- cpu_ppc_dump_state(env, stderr, 0);
- abort();
- case EXCP_PROGRAM: /* Program exception */
- fprintf(stderr, "Program exception\n");
- cpu_ppc_dump_state(env, stderr, 0);
+ case EXCP_EXTERNAL:
+ /* Should not happen ! */
+ fprintf(stderr, "External interruption... Stop emulation\n");
+ if (loglevel)
+ fprintf(logfile, "External interruption... Stop emulation\n");
abort();
- break;
- /* Trap */
- case EXCP_TRAP: /* Trap */
- case EXCP_TRACE: /* Trace exception (optional) */
- info.si_signo = SIGTRAP;
+ case EXCP_ALIGN:
+ fprintf(stderr, "Invalid unaligned memory access\n");
+ if (loglevel)
+ fprintf(logfile, "Invalid unaligned memory access\n");
+ info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->nip;
+ info.si_code = TARGET_BUS_ADRALN;
+ info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
- /* Invalid instruction */
+ case EXCP_PROGRAM:
+ switch (env->error_code & ~0xF) {
+ case EXCP_FP:
+ fprintf(stderr, "Program exception\n");
+ if (loglevel)
+ fprintf(logfile, "Program exception\n");
+ /* Set FX */
+ env->fpscr[7] |= 0x8;
+ /* Finally, update FEX */
+ if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
+ ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
+ env->fpscr[7] |= 0x4;
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_FP_OX:
+ info.si_code = TARGET_FPE_FLTOVF;
+ break;
+ case EXCP_FP_UX:
+ info.si_code = TARGET_FPE_FLTUND;
+ break;
+ case EXCP_FP_ZX:
+ case EXCP_FP_VXZDZ:
+ info.si_code = TARGET_FPE_FLTDIV;
+ break;
+ case EXCP_FP_XX:
+ info.si_code = TARGET_FPE_FLTRES;
+ break;
+ case 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:
+ 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);
+ }
+ }
+ break;
case EXCP_INVAL:
- info.si_signo = SIGILL;
- info.si_errno = 0;
+ fprintf(stderr, "Invalid instruction\n");
+ if (loglevel)
+ fprintf(logfile, "Invalid instruction\n");
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_INVAL_INVAL:
+ info.si_code = TARGET_ILL_ILLOPC;
+ break;
+ case EXCP_INVAL_LSWX:
info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->nip;
+ break;
+ case EXCP_INVAL_SPR:
+ info.si_code = TARGET_ILL_PRVREG;
+ break;
+ case 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);
+ }
+ info.si_code = TARGET_ILL_ILLADR;
+ break;
+ }
+ break;
+ case EXCP_PRIV:
+ fprintf(stderr, "Privilege violation\n");
+ if (loglevel)
+ fprintf(logfile, "Privilege violation\n");
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_PRIV_OPC:
+ info.si_code = TARGET_ILL_PRVOPC;
+ break;
+ case EXCP_PRIV_REG:
+ info.si_code = TARGET_ILL_PRVREG;
+ break;
+ default:
+ fprintf(stderr, "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();
+ 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();
+ }
+ info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
- /* Privileged instruction */
- case EXCP_PRIV: /* Privileged instruction */
- info.si_signo = SIGILL;
+ case EXCP_NO_FP:
+ fprintf(stderr, "No floating point allowed\n");
+ if (loglevel)
+ fprintf(logfile, "No floating point allowed\n");
+ info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->nip;
+ info.si_code = TARGET_ILL_COPROC;
+ info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
break;
- case EXCP_NO_FP: /* No floating point */
- case EXCP_DECR: /* Decrementer exception */
+ case EXCP_DECR:
+ /* Should not happen ! */
+ fprintf(stderr, "Decrementer exception\n");
+ if (loglevel)
+ fprintf(logfile, "Decrementer exception\n");
+ abort();
case EXCP_RESA: /* Implementation specific */
+ /* Should not happen ! */
+ fprintf(stderr, "RESA exception should never happen !\n");
+ if (loglevel)
+ fprintf(logfile, "RESA exception should never happen !\n");
+ abort();
case EXCP_RESB: /* Implementation specific */
- case EXCP_FP_ASSIST: /* Floating-point assist (optional) */
- fprintf(stderr, "Misc expt...\n");
- cpu_ppc_dump_state(env, stderr, 0);
+ /* Should not happen ! */
+ fprintf(stderr, "RESB exception should never happen !\n");
+ if (loglevel)
+ fprintf(logfile, "RESB exception should never happen !\n");
abort();
-
- case EXCP_SYSCALL:
- {
- uint32_t ret;
- /* system call */
- /* WARNING:
- * PPC ABI uses overflow flag in cr0 to signal an error
- * in syscalls.
- */
- 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;
+ 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) {
+ fprintf(stderr, "Tried to go into supervisor mode !\n");
+ if (loglevel)
+ fprintf(logfile, "Tried to go into supervisor mode !\n");
+ abort();
}
+ break;
+ case EXCP_BRANCH:
+ /* We stopped because of a jump... */
+ break;
+ case EXCP_RFI:
+ /* Should not occur: we always are in user mode */
+ fprintf(stderr, "Return from interrupt ?\n");
+ if (loglevel)
+ fprintf(logfile, "Return from interrupt ?\n");
+ abort();
+ case EXCP_INTERRUPT:
+ /* Don't know why this should ever happen... */
+ break;
default:
-// error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
- cpu_ppc_dump_state(env, stderr, 0);
+ if (loglevel) {
+ fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
+ "0x%02x - aborting\n", trapnr, env->error_code);
+ }
abort();
}
+ if (trapnr < EXCP_PPC_MAX)
+ env->exceptions &= ~(1 << trapnr);
process_pending_signals(env);
+ if (env->exceptions != 0) {
+ check_exception_state(env);
+ }
}
}
#endif
@@ -750,8 +977,10 @@ int main(int argc, char **argv)
#elif defined(TARGET_PPC)
{
int i;
- for (i = 0; i < 32; i++)
- env->msr[i] = (regs->msr >> i) & 1;
+ for (i = 0; i < 32; i++) {
+ if (i != 12 && i != 6)
+ env->msr[i] = (regs->msr >> i) & 1;
+ }
env->nip = regs->nip;
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->gpr[i];