mirror of https://github.com/xqemu/xqemu.git
simplified PowerPC exception handling (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1492 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
f68c781c2d
commit
2be0071f22
|
@ -68,9 +68,9 @@ typedef uint64_t target_phys_addr_t;
|
||||||
|
|
||||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
||||||
|
|
||||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
#define EXCP_INTERRUPT 0x10000 /* async interruption */
|
||||||
#define EXCP_HLT 257 /* hlt instruction reached */
|
#define EXCP_HLT 0x10001 /* hlt instruction reached */
|
||||||
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
|
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
|
||||||
|
|
||||||
#define MAX_BREAKPOINTS 32
|
#define MAX_BREAKPOINTS 32
|
||||||
|
|
||||||
|
|
|
@ -706,28 +706,22 @@ void cpu_loop(CPUPPCState *env)
|
||||||
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
|
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
|
||||||
env->spr[SPR_DAR]);
|
env->spr[SPR_DAR]);
|
||||||
}
|
}
|
||||||
switch (env->error_code & 0xF) {
|
switch (env->error_code & 0xFF000000) {
|
||||||
case EXCP_DSI_TRANSLATE:
|
case 0x40000000:
|
||||||
info.si_signo = TARGET_SIGSEGV;
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
info.si_errno = 0;
|
info.si_errno = 0;
|
||||||
info.si_code = TARGET_SEGV_MAPERR;
|
info.si_code = TARGET_SEGV_MAPERR;
|
||||||
break;
|
break;
|
||||||
case EXCP_DSI_NOTSUP:
|
case 0x04000000:
|
||||||
case EXCP_DSI_EXTERNAL:
|
|
||||||
info.si_signo = TARGET_SIGILL;
|
info.si_signo = TARGET_SIGILL;
|
||||||
info.si_errno = 0;
|
info.si_errno = 0;
|
||||||
info.si_code = TARGET_ILL_ILLADR;
|
info.si_code = TARGET_ILL_ILLADR;
|
||||||
break;
|
break;
|
||||||
case EXCP_DSI_PROT:
|
case 0x08000000:
|
||||||
info.si_signo = TARGET_SIGSEGV;
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
info.si_errno = 0;
|
info.si_errno = 0;
|
||||||
info.si_code = TARGET_SEGV_ACCERR;
|
info.si_code = TARGET_SEGV_ACCERR;
|
||||||
break;
|
break;
|
||||||
case EXCP_DSI_DABR:
|
|
||||||
info.si_signo = TARGET_SIGTRAP;
|
|
||||||
info.si_errno = 0;
|
|
||||||
info.si_code = TARGET_TRAP_BRKPT;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
/* Let's send a regular segfault... */
|
/* Let's send a regular segfault... */
|
||||||
fprintf(stderr, "Invalid segfault errno (%02x)\n",
|
fprintf(stderr, "Invalid segfault errno (%02x)\n",
|
||||||
|
@ -748,19 +742,14 @@ void cpu_loop(CPUPPCState *env)
|
||||||
fprintf(stderr, "Invalid instruction fetch\n");
|
fprintf(stderr, "Invalid instruction fetch\n");
|
||||||
if (loglevel)
|
if (loglevel)
|
||||||
fprintf(logfile, "Invalid instruction fetch\n");
|
fprintf(logfile, "Invalid instruction fetch\n");
|
||||||
switch (env->error_code) {
|
switch (env->error_code & 0xFF000000) {
|
||||||
case EXCP_ISI_TRANSLATE:
|
case 0x40000000:
|
||||||
info.si_signo = TARGET_SIGSEGV;
|
info.si_signo = TARGET_SIGSEGV;
|
||||||
info.si_errno = 0;
|
info.si_errno = 0;
|
||||||
info.si_code = TARGET_SEGV_MAPERR;
|
info.si_code = TARGET_SEGV_MAPERR;
|
||||||
break;
|
break;
|
||||||
case EXCP_ISI_GUARD:
|
case 0x10000000:
|
||||||
info.si_signo = TARGET_SIGILL;
|
case 0x08000000:
|
||||||
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_signo = TARGET_SIGSEGV;
|
||||||
info.si_errno = 0;
|
info.si_errno = 0;
|
||||||
info.si_code = TARGET_SEGV_ACCERR;
|
info.si_code = TARGET_SEGV_ACCERR;
|
||||||
|
@ -930,18 +919,6 @@ void cpu_loop(CPUPPCState *env)
|
||||||
if (loglevel)
|
if (loglevel)
|
||||||
fprintf(logfile, "Decrementer exception\n");
|
fprintf(logfile, "Decrementer exception\n");
|
||||||
abort();
|
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 */
|
|
||||||
/* Should not happen ! */
|
|
||||||
fprintf(stderr, "RESB exception should never happen !\n");
|
|
||||||
if (loglevel)
|
|
||||||
fprintf(logfile, "RESB exception should never happen !\n");
|
|
||||||
abort();
|
|
||||||
case EXCP_TRACE:
|
case EXCP_TRACE:
|
||||||
/* Do nothing: we use this to trace execution */
|
/* Do nothing: we use this to trace execution */
|
||||||
break;
|
break;
|
||||||
|
@ -963,12 +940,6 @@ void cpu_loop(CPUPPCState *env)
|
||||||
case EXCP_BRANCH:
|
case EXCP_BRANCH:
|
||||||
/* We stopped because of a jump... */
|
/* We stopped because of a jump... */
|
||||||
break;
|
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:
|
case EXCP_INTERRUPT:
|
||||||
/* Don't know why this should ever happen... */
|
/* Don't know why this should ever happen... */
|
||||||
break;
|
break;
|
||||||
|
|
116
target-ppc/cpu.h
116
target-ppc/cpu.h
|
@ -924,62 +924,72 @@ enum {
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Exceptions */
|
/* Exceptions */
|
||||||
enum {
|
#define EXCP_NONE -1
|
||||||
EXCP_NONE = -1,
|
/* PowerPC hardware exceptions : exception vectors defined in PowerPC book 3 */
|
||||||
/* PowerPC hardware exceptions : exception vector / 0x100 */
|
#define EXCP_RESET 0x0100 /* System reset */
|
||||||
EXCP_RESET = 0x01, /* System reset */
|
#define EXCP_MACHINE_CHECK 0x0200 /* Machine check exception */
|
||||||
EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */
|
#define EXCP_DSI 0x0300 /* Data storage exception */
|
||||||
EXCP_DSI = 0x03, /* Impossible memory access */
|
#define EXCP_DSEG 0x0380 /* Data segment exception */
|
||||||
EXCP_ISI = 0x04, /* Impossible instruction fetch */
|
#define EXCP_ISI 0x0400 /* Instruction storage exception */
|
||||||
EXCP_EXTERNAL = 0x05, /* External interruption */
|
#define EXCP_ISEG 0x0480 /* Instruction segment exception */
|
||||||
EXCP_ALIGN = 0x06, /* Alignment exception */
|
#define EXCP_EXTERNAL 0x0500 /* External interruption */
|
||||||
EXCP_PROGRAM = 0x07, /* Program exception */
|
#define EXCP_ALIGN 0x0600 /* Alignment exception */
|
||||||
EXCP_NO_FP = 0x08, /* No floating point */
|
#define EXCP_PROGRAM 0x0700 /* Program exception */
|
||||||
EXCP_DECR = 0x09, /* Decrementer exception */
|
#define EXCP_NO_FP 0x0800 /* Floating point unavailable exception */
|
||||||
EXCP_RESA = 0x0A, /* Implementation specific */
|
#define EXCP_DECR 0x0900 /* Decrementer exception */
|
||||||
EXCP_RESB = 0x0B, /* Implementation specific */
|
#define EXCP_HDECR 0x0980 /* Hypervisor decrementer exception */
|
||||||
EXCP_SYSCALL = 0x0C, /* System call */
|
#define EXCP_SYSCALL 0x0C00 /* System call */
|
||||||
EXCP_TRACE = 0x0D, /* Trace exception (optional) */
|
#define EXCP_TRACE 0x0D00 /* Trace exception */
|
||||||
EXCP_FP_ASSIST = 0x0E, /* Floating-point assist (optional) */
|
#define EXCP_PERF 0x0F00 /* Performance monitor exception */
|
||||||
/* MPC740/745/750 & IBM 750 */
|
/* Exceptions defined in PowerPC 32 bits programming environment manual */
|
||||||
EXCP_PERF = 0x0F, /* Performance monitor */
|
#define EXCP_FP_ASSIST 0x0E00 /* Floating-point assist */
|
||||||
EXCP_IABR = 0x13, /* Instruction address breakpoint */
|
/* Implementation specific exceptions */
|
||||||
EXCP_SMI = 0x14, /* System management interrupt */
|
/* 40x exceptions */
|
||||||
EXCP_THRM = 0x15, /* Thermal management interrupt */
|
#define EXCP_40x_PIT 0x1000 /* Programmable interval timer interrupt */
|
||||||
/* MPC755 */
|
#define EXCP_40x_FIT 0x1010 /* Fixed interval timer interrupt */
|
||||||
EXCP_TLBMISS = 0x10, /* Instruction TLB miss */
|
#define EXCP_40x_WATCHDOG 0x1020 /* Watchdog timer exception */
|
||||||
EXCP_TLBMISS_DL = 0x11, /* Data TLB miss for load */
|
#define EXCP_40x_DTLBMISS 0x1100 /* Data TLB miss exception */
|
||||||
EXCP_TLBMISS_DS = 0x12, /* Data TLB miss for store */
|
#define EXCP_40x_ITLBMISS 0x1200 /* Instruction TLB miss exception */
|
||||||
EXCP_PPC_MAX = 0x16,
|
#define EXCP_40x_DEBUG 0x2000 /* Debug exception */
|
||||||
/* Qemu exception */
|
/* 405 specific exceptions */
|
||||||
EXCP_OFCALL = 0x20, /* Call open-firmware emulator */
|
#define EXCP_405_APU 0x0F20 /* APU unavailable exception */
|
||||||
EXCP_RTASCALL = 0x21, /* Call RTAS emulator */
|
/* TLB assist exceptions (602/603) */
|
||||||
/* Special cases where we want to stop translation */
|
#define EXCP_I_TLBMISS 0x1000 /* Instruction TLB miss */
|
||||||
EXCP_MTMSR = 0x104, /* mtmsr instruction: */
|
#define EXCP_DL_TLBMISS 0x1100 /* Data load TLB miss */
|
||||||
|
#define EXCP_DS_TLBMISS 0x1200 /* Data store TLB miss */
|
||||||
|
/* Breakpoint exceptions (602/603/604/620/740/745/750/755...) */
|
||||||
|
#define EXCP_IABR 0x1300 /* Instruction address breakpoint */
|
||||||
|
#define EXCP_SMI 0x1400 /* System management interrupt */
|
||||||
|
/* Altivec related exceptions */
|
||||||
|
#define EXCP_VPU 0x0F20 /* VPU unavailable exception */
|
||||||
|
/* 601 specific exceptions */
|
||||||
|
#define EXCP_601_IO 0x0600 /* IO error exception */
|
||||||
|
#define EXCP_601_RUNM 0x2000 /* Run mode exception */
|
||||||
|
/* 602 specific exceptions */
|
||||||
|
#define EXCP_602_WATCHDOG 0x1500 /* Watchdog exception */
|
||||||
|
#define EXCP_602_EMUL 0x1600 /* Emulation trap exception */
|
||||||
|
/* G2 specific exceptions */
|
||||||
|
#define EXCP_G2_CRIT 0x0A00 /* Critical interrupt */
|
||||||
|
/* MPC740/745/750 & IBM 750 specific exceptions */
|
||||||
|
#define EXCP_THRM 0x1700 /* Thermal management interrupt */
|
||||||
|
/* 74xx specific exceptions */
|
||||||
|
#define EXCP_74xx_VPUA 0x1600 /* VPU assist exception */
|
||||||
|
/* 970FX specific exceptions */
|
||||||
|
#define EXCP_970_SOFTP 0x1500 /* Soft patch exception */
|
||||||
|
#define EXCP_970_MAINT 0x1600 /* Maintenance exception */
|
||||||
|
#define EXCP_970_THRM 0x1800 /* Thermal exception */
|
||||||
|
#define EXCP_970_VPUA 0x1700 /* VPU assist exception */
|
||||||
|
/* End of exception vectors area */
|
||||||
|
#define EXCP_PPC_MAX 0x4000
|
||||||
|
/* Qemu exceptions: special cases we want to stop translation */
|
||||||
|
#define EXCP_MTMSR 0x11000 /* mtmsr instruction: */
|
||||||
/* may change privilege level */
|
/* may change privilege level */
|
||||||
EXCP_BRANCH = 0x108, /* branch instruction */
|
#define EXCP_BRANCH 0x11001 /* branch instruction */
|
||||||
EXCP_RFI = 0x10C, /* return from interrupt */
|
#define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */
|
||||||
EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */
|
#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ */
|
||||||
};
|
|
||||||
/* Error codes */
|
/* Error codes */
|
||||||
enum {
|
enum {
|
||||||
/* Exception subtypes for EXCP_DSI */
|
|
||||||
EXCP_DSI_TRANSLATE = 0x01, /* Data address can't be translated */
|
|
||||||
EXCP_DSI_NOTSUP = 0x02, /* Access type not supported */
|
|
||||||
EXCP_DSI_PROT = 0x03, /* Memory protection violation */
|
|
||||||
EXCP_DSI_EXTERNAL = 0x04, /* External access disabled */
|
|
||||||
EXCP_DSI_DABR = 0x05, /* Data address breakpoint */
|
|
||||||
/* flags for EXCP_DSI */
|
|
||||||
EXCP_DSI_DIRECT = 0x10,
|
|
||||||
EXCP_DSI_STORE = 0x20,
|
|
||||||
EXCP_DSI_ECXW = 0x40,
|
|
||||||
/* Exception subtypes for EXCP_ISI */
|
|
||||||
EXCP_ISI_TRANSLATE = 0x01, /* Code address can't be translated */
|
|
||||||
EXCP_ISI_NOEXEC = 0x02, /* Try to fetch from a data segment */
|
|
||||||
EXCP_ISI_GUARD = 0x03, /* Fetch from guarded memory */
|
|
||||||
EXCP_ISI_PROT = 0x04, /* Memory protection violation */
|
|
||||||
EXCP_ISI_DIRECT = 0x05, /* Trying to fetch from *
|
|
||||||
* a direct store segment */
|
|
||||||
/* Exception subtypes for EXCP_ALIGN */
|
/* Exception subtypes for EXCP_ALIGN */
|
||||||
EXCP_ALIGN_FP = 0x01, /* FP alignment exception */
|
EXCP_ALIGN_FP = 0x01, /* FP alignment exception */
|
||||||
EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */
|
EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */
|
||||||
|
|
|
@ -22,8 +22,6 @@
|
||||||
//#define DEBUG_MMU
|
//#define DEBUG_MMU
|
||||||
//#define DEBUG_BATS
|
//#define DEBUG_BATS
|
||||||
//#define DEBUG_EXCEPTIONS
|
//#define DEBUG_EXCEPTIONS
|
||||||
/* accurate but slower TLB flush in exceptions */
|
|
||||||
//#define ACCURATE_TLB_FLUSH
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* PowerPC MMU emulation */
|
/* PowerPC MMU emulation */
|
||||||
|
@ -524,20 +522,25 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case -1:
|
case -1:
|
||||||
/* No matches in page tables */
|
/* No matches in page tables */
|
||||||
error_code = EXCP_ISI_TRANSLATE;
|
error_code = 0x40000000;
|
||||||
break;
|
break;
|
||||||
case -2:
|
case -2:
|
||||||
/* Access rights violation */
|
/* Access rights violation */
|
||||||
error_code = EXCP_ISI_PROT;
|
error_code = 0x08000000;
|
||||||
break;
|
break;
|
||||||
case -3:
|
case -3:
|
||||||
/* No execute protection violation */
|
/* No execute protection violation */
|
||||||
error_code = EXCP_ISI_NOEXEC;
|
error_code = 0x10000000;
|
||||||
break;
|
break;
|
||||||
case -4:
|
case -4:
|
||||||
/* Direct store exception */
|
/* Direct store exception */
|
||||||
/* No code fetch is allowed in direct-store areas */
|
/* No code fetch is allowed in direct-store areas */
|
||||||
error_code = EXCP_ISI_DIRECT;
|
error_code = 0x10000000;
|
||||||
|
break;
|
||||||
|
case -5:
|
||||||
|
/* No match in segment table */
|
||||||
|
exception = EXCP_ISEG;
|
||||||
|
error_code = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -545,11 +548,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case -1:
|
case -1:
|
||||||
/* No matches in page tables */
|
/* No matches in page tables */
|
||||||
error_code = EXCP_DSI_TRANSLATE;
|
error_code = 0x40000000;
|
||||||
break;
|
break;
|
||||||
case -2:
|
case -2:
|
||||||
/* Access rights violation */
|
/* Access rights violation */
|
||||||
error_code = EXCP_DSI_PROT;
|
error_code = 0x08000000;
|
||||||
break;
|
break;
|
||||||
case -4:
|
case -4:
|
||||||
/* Direct store exception */
|
/* Direct store exception */
|
||||||
|
@ -561,14 +564,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||||
break;
|
break;
|
||||||
case ACCESS_RES:
|
case ACCESS_RES:
|
||||||
/* lwarx, ldarx or srwcx. */
|
/* lwarx, ldarx or srwcx. */
|
||||||
exception = EXCP_DSI;
|
error_code = 0x04000000;
|
||||||
error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT;
|
|
||||||
break;
|
break;
|
||||||
case ACCESS_EXT:
|
case ACCESS_EXT:
|
||||||
/* eciwx or ecowx */
|
/* eciwx or ecowx */
|
||||||
exception = EXCP_DSI;
|
error_code = 0x04100000;
|
||||||
error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT |
|
|
||||||
EXCP_DSI_ECXW;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("DSI: invalid exception (%d)\n", ret);
|
printf("DSI: invalid exception (%d)\n", ret);
|
||||||
|
@ -576,11 +576,17 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||||
error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
|
error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case -5:
|
||||||
|
/* No match in segment table */
|
||||||
|
exception = EXCP_DSEG;
|
||||||
|
error_code = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (rw)
|
if (rw)
|
||||||
error_code |= EXCP_DSI_STORE;
|
error_code |= 0x02000000;
|
||||||
/* Store fault address */
|
/* Store fault address */
|
||||||
env->spr[SPR_DAR] = address;
|
env->spr[SPR_DAR] = address;
|
||||||
|
env->spr[SPR_DSISR] = error_code;
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
printf("%s: set exception to %d %02x\n",
|
printf("%s: set exception to %d %02x\n",
|
||||||
|
@ -985,119 +991,107 @@ static void dump_syscall(CPUState *env)
|
||||||
|
|
||||||
void do_interrupt (CPUState *env)
|
void do_interrupt (CPUState *env)
|
||||||
{
|
{
|
||||||
uint32_t msr;
|
target_ulong msr, *srr_0, *srr_1, tmp;
|
||||||
int excp;
|
int excp;
|
||||||
|
|
||||||
excp = env->exception_index;
|
excp = env->exception_index;
|
||||||
msr = do_load_msr(env);
|
msr = do_load_msr(env);
|
||||||
|
/* The default is to use SRR0 & SRR1 to save the exception context */
|
||||||
|
srr_0 = &env->spr[SPR_SRR0];
|
||||||
|
srr_1 = &env->spr[SPR_SRR1];
|
||||||
#if defined (DEBUG_EXCEPTIONS)
|
#if defined (DEBUG_EXCEPTIONS)
|
||||||
if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1)
|
if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) {
|
||||||
{
|
if (loglevel != 0) {
|
||||||
if (loglevel > 0) {
|
fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
|
||||||
fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n",
|
(unsigned long)env->nip, excp, env->error_code);
|
||||||
env->nip, excp << 8, env->error_code);
|
cpu_dump_state(env, logfile, fprintf, 0);
|
||||||
}
|
}
|
||||||
if (loglevel > 0)
|
|
||||||
cpu_dump_state(env, logfile, fprintf, 0);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (loglevel & CPU_LOG_INT) {
|
if (loglevel & CPU_LOG_INT) {
|
||||||
fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n",
|
fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
|
||||||
env->nip, excp << 8, env->error_code);
|
(unsigned long)env->nip, excp, env->error_code);
|
||||||
}
|
}
|
||||||
|
msr_pow = 0;
|
||||||
/* Generate informations in save/restore registers */
|
/* Generate informations in save/restore registers */
|
||||||
switch (excp) {
|
switch (excp) {
|
||||||
case EXCP_NONE:
|
/* Generic PowerPC exceptions */
|
||||||
/* Do nothing */
|
case EXCP_RESET: /* 0x0100 */
|
||||||
#if defined (DEBUG_EXCEPTIONS)
|
if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) {
|
||||||
printf("%s: escape EXCP_NONE\n", __func__);
|
if (msr_ip)
|
||||||
#endif
|
excp += 0xFFC00;
|
||||||
return;
|
excp |= 0xFFC00000;
|
||||||
case EXCP_RESET:
|
} else {
|
||||||
if (msr_ip)
|
srr_0 = &env->spr[SPR_40x_SRR2];
|
||||||
excp += 0xFFC00;
|
srr_1 = &env->spr[SPR_40x_SRR3];
|
||||||
|
}
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case EXCP_MACHINE_CHECK:
|
case EXCP_MACHINE_CHECK: /* 0x0200 */
|
||||||
if (msr_me == 0) {
|
if (msr_me == 0) {
|
||||||
cpu_abort(env, "Machine check exception while not allowed\n");
|
cpu_abort(env, "Machine check exception while not allowed\n");
|
||||||
}
|
}
|
||||||
|
if (PPC_EXCP(env) == PPC_FLAGS_EXCP_40x) {
|
||||||
|
srr_0 = &env->spr[SPR_40x_SRR2];
|
||||||
|
srr_1 = &env->spr[SPR_40x_SRR3];
|
||||||
|
}
|
||||||
msr_me = 0;
|
msr_me = 0;
|
||||||
break;
|
break;
|
||||||
case EXCP_DSI:
|
case EXCP_DSI: /* 0x0300 */
|
||||||
/* Store exception cause */
|
/* Store exception cause */
|
||||||
/* data location address has been stored
|
/* data location address has been stored
|
||||||
* when the fault has been detected
|
* when the fault has been detected
|
||||||
*/
|
*/
|
||||||
msr &= ~0xFFFF0000;
|
msr &= ~0xFFFF0000;
|
||||||
env->spr[SPR_DSISR] = 0;
|
|
||||||
if ((env->error_code & 0x0f) == EXCP_DSI_TRANSLATE)
|
|
||||||
env->spr[SPR_DSISR] |= 0x40000000;
|
|
||||||
else if ((env->error_code & 0x0f) == EXCP_DSI_PROT)
|
|
||||||
env->spr[SPR_DSISR] |= 0x08000000;
|
|
||||||
else if ((env->error_code & 0x0f) == EXCP_DSI_NOTSUP) {
|
|
||||||
env->spr[SPR_DSISR] |= 0x80000000;
|
|
||||||
if (env->error_code & EXCP_DSI_DIRECT)
|
|
||||||
env->spr[SPR_DSISR] |= 0x04000000;
|
|
||||||
}
|
|
||||||
if (env->error_code & EXCP_DSI_STORE)
|
|
||||||
env->spr[SPR_DSISR] |= 0x02000000;
|
|
||||||
if ((env->error_code & 0xF) == EXCP_DSI_DABR)
|
|
||||||
env->spr[SPR_DSISR] |= 0x00400000;
|
|
||||||
if (env->error_code & EXCP_DSI_ECXW)
|
|
||||||
env->spr[SPR_DSISR] |= 0x00100000;
|
|
||||||
#if defined (DEBUG_EXCEPTIONS)
|
#if defined (DEBUG_EXCEPTIONS)
|
||||||
if (loglevel) {
|
if (loglevel) {
|
||||||
fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
|
fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
|
||||||
env->spr[SPR_DSISR], env->spr[SPR_DAR]);
|
env->spr[SPR_DSISR], env->spr[SPR_DAR]);
|
||||||
} else {
|
} else {
|
||||||
printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n",
|
printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
|
||||||
env->spr[SPR_DSISR], env->spr[SPR_DAR], env->nip);
|
env->spr[SPR_DSISR], env->spr[SPR_DAR]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case EXCP_ISI:
|
case EXCP_ISI: /* 0x0400 */
|
||||||
/* Store exception cause */
|
/* Store exception cause */
|
||||||
msr &= ~0xFFFF0000;
|
msr &= ~0xFFFF0000;
|
||||||
if (env->error_code == EXCP_ISI_TRANSLATE)
|
msr |= env->error_code;
|
||||||
msr |= 0x40000000;
|
|
||||||
else if (env->error_code == EXCP_ISI_NOEXEC ||
|
|
||||||
env->error_code == EXCP_ISI_GUARD ||
|
|
||||||
env->error_code == EXCP_ISI_DIRECT)
|
|
||||||
msr |= 0x10000000;
|
|
||||||
else
|
|
||||||
msr |= 0x08000000;
|
|
||||||
#if defined (DEBUG_EXCEPTIONS)
|
#if defined (DEBUG_EXCEPTIONS)
|
||||||
if (loglevel) {
|
if (loglevel != 0) {
|
||||||
fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
|
fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
|
||||||
msr, env->nip);
|
msr, env->nip);
|
||||||
} else {
|
|
||||||
printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n",
|
|
||||||
msr, env->nip, env->spr[V_TBL]);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case EXCP_EXTERNAL:
|
case EXCP_EXTERNAL: /* 0x0500 */
|
||||||
if (msr_ee == 0) {
|
if (msr_ee == 0) {
|
||||||
#if defined (DEBUG_EXCEPTIONS)
|
#if defined (DEBUG_EXCEPTIONS)
|
||||||
if (loglevel > 0) {
|
if (loglevel > 0) {
|
||||||
fprintf(logfile, "Skipping hardware interrupt\n");
|
fprintf(logfile, "Skipping hardware interrupt\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Requeue it */
|
/* Requeue it */
|
||||||
do_raise_exception(EXCP_EXTERNAL);
|
env->interrupt_request |= CPU_INTERRUPT_HARD;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case EXCP_ALIGN:
|
case EXCP_ALIGN: /* 0x0600 */
|
||||||
/* Store exception cause */
|
if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) {
|
||||||
/* Get rS/rD and rA from faulting opcode */
|
/* Store exception cause */
|
||||||
env->spr[SPR_DSISR] |=
|
/* Get rS/rD and rA from faulting opcode */
|
||||||
(ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
|
env->spr[SPR_DSISR] |=
|
||||||
/* data location address has been stored
|
(ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
|
||||||
* when the fault has been detected
|
/* data location address has been stored
|
||||||
*/
|
* when the fault has been detected
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
/* IO error exception on PowerPC 601 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"601 IO error exception is not implemented yet !\n");
|
||||||
|
}
|
||||||
goto store_current;
|
goto store_current;
|
||||||
case EXCP_PROGRAM:
|
case EXCP_PROGRAM: /* 0x0700 */
|
||||||
msr &= ~0xFFFF0000;
|
msr &= ~0xFFFF0000;
|
||||||
switch (env->error_code & ~0xF) {
|
switch (env->error_code & ~0xF) {
|
||||||
case EXCP_FP:
|
case EXCP_FP:
|
||||||
|
@ -1131,17 +1125,19 @@ void do_interrupt (CPUState *env)
|
||||||
}
|
}
|
||||||
msr |= 0x00010000;
|
msr |= 0x00010000;
|
||||||
goto store_current;
|
goto store_current;
|
||||||
case EXCP_NO_FP:
|
case EXCP_NO_FP: /* 0x0800 */
|
||||||
msr &= ~0xFFFF0000;
|
msr &= ~0xFFFF0000;
|
||||||
goto store_current;
|
goto store_current;
|
||||||
case EXCP_DECR:
|
case EXCP_DECR:
|
||||||
if (msr_ee == 0) {
|
if (msr_ee == 0) {
|
||||||
|
#if 1
|
||||||
/* Requeue it */
|
/* Requeue it */
|
||||||
do_raise_exception(EXCP_DECR);
|
env->interrupt_request |= CPU_INTERRUPT_TIMER;
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case EXCP_SYSCALL:
|
case EXCP_SYSCALL: /* 0x0C00 */
|
||||||
/* NOTE: this is a temporary hack to support graphics OSI
|
/* NOTE: this is a temporary hack to support graphics OSI
|
||||||
calls from the MOL driver */
|
calls from the MOL driver */
|
||||||
if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
|
if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
|
||||||
|
@ -1153,35 +1149,332 @@ void do_interrupt (CPUState *env)
|
||||||
dump_syscall(env);
|
dump_syscall(env);
|
||||||
}
|
}
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case EXCP_TRACE:
|
case EXCP_TRACE: /* 0x0D00 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "Trace exception is not implemented yet !\n");
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case EXCP_FP_ASSIST:
|
case EXCP_PERF: /* 0x0F00 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"Performance counter exception is not implemented yet !\n");
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case EXCP_MTMSR:
|
/* 32 bits PowerPC specific exceptions */
|
||||||
/* Nothing to do */
|
case EXCP_FP_ASSIST: /* 0x0E00 */
|
||||||
return;
|
/* XXX: TODO */
|
||||||
case EXCP_BRANCH:
|
cpu_abort(env, "Floating point assist exception "
|
||||||
/* Nothing to do */
|
"is not implemented yet !\n");
|
||||||
return;
|
goto store_next;
|
||||||
case EXCP_RFI:
|
/* 64 bits PowerPC exceptions */
|
||||||
/* Restore user-mode state */
|
case EXCP_DSEG: /* 0x0380 */
|
||||||
#if defined (DEBUG_EXCEPTIONS)
|
/* XXX: TODO */
|
||||||
if (msr_pr == 1)
|
cpu_abort(env, "Data segment exception is not implemented yet !\n");
|
||||||
printf("Return from exception => 0x%08x\n", (uint32_t)env->nip);
|
goto store_next;
|
||||||
|
case EXCP_ISEG: /* 0x0480 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"Instruction segment exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case EXCP_HDECR: /* 0x0980 */
|
||||||
|
if (msr_ee == 0) {
|
||||||
|
#if 1
|
||||||
|
/* Requeue it */
|
||||||
|
env->interrupt_request |= CPU_INTERRUPT_TIMER;
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
cpu_abort(env,
|
||||||
|
"Hypervisor decrementer exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
/* Implementation specific exceptions */
|
||||||
|
case 0x0A00:
|
||||||
|
if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) {
|
||||||
|
/* Critical interrupt on G2 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "G2 critical interrupt is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
} else {
|
||||||
|
cpu_abort(env, "Invalid exception 0x0A00 !\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x0F20:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_40x:
|
||||||
|
/* APU unavailable on 405 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"APU unavailable exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_74xx:
|
||||||
|
/* Altivec unavailable */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "Altivec unavailable exception "
|
||||||
|
"is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x0F20 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1000:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_40x:
|
||||||
|
/* PIT on 4xx */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "40x PIT exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_602:
|
||||||
|
case PPC_FLAGS_EXCP_603:
|
||||||
|
/* ITLBMISS on 602/603 */
|
||||||
|
msr &= ~0xF00F0000;
|
||||||
|
msr_tgpr = 1;
|
||||||
|
goto store_gprs;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1000 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1010:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_40x:
|
||||||
|
/* FIT on 4xx */
|
||||||
|
cpu_abort(env, "40x FIT exception is not implemented yet !\n");
|
||||||
|
/* XXX: TODO */
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1010 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1020:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_40x:
|
||||||
|
/* Watchdog on 4xx */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"40x watchdog exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1020 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1100:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_40x:
|
||||||
|
/* DTLBMISS on 4xx */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"40x DTLBMISS exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_602:
|
||||||
|
case PPC_FLAGS_EXCP_603:
|
||||||
|
/* DLTLBMISS on 602/603 */
|
||||||
|
msr &= ~0xF00F0000;
|
||||||
|
msr_tgpr = 1;
|
||||||
|
goto store_gprs;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1100 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1200:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_40x:
|
||||||
|
/* ITLBMISS on 4xx */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"40x ITLBMISS exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_602:
|
||||||
|
case PPC_FLAGS_EXCP_603:
|
||||||
|
/* DSTLBMISS on 602/603 */
|
||||||
|
msr &= ~0xF00F0000;
|
||||||
|
msr_tgpr = 1;
|
||||||
|
store_gprs:
|
||||||
|
#if defined (DEBUG_SOFTWARE_TLB)
|
||||||
|
if (loglevel != 0) {
|
||||||
|
fprintf(logfile, "6xx %sTLB miss: IM %08x DM %08x IC %08x "
|
||||||
|
"DC %08x H1 %08x H2 %08x %08x\n",
|
||||||
|
excp == 0x1000 ? "I" : excp == 0x1100 ? "DL" : "DS",
|
||||||
|
env->spr[SPR_IMISS], env->spr[SPR_DMISS],
|
||||||
|
env->spr[SPR_ICMP], env->spr[SPR_DCMP],
|
||||||
|
env->spr[SPR_DHASH1], env->spr[SPR_DHASH2],
|
||||||
|
env->error_code);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* Swap temporary saved registers with GPRs */
|
||||||
|
tmp = env->gpr[0];
|
||||||
|
env->gpr[0] = env->tgpr[0];
|
||||||
|
env->tgpr[0] = tmp;
|
||||||
|
tmp = env->gpr[1];
|
||||||
|
env->gpr[1] = env->tgpr[1];
|
||||||
|
env->tgpr[1] = tmp;
|
||||||
|
tmp = env->gpr[2];
|
||||||
|
env->gpr[2] = env->tgpr[2];
|
||||||
|
env->tgpr[2] = tmp;
|
||||||
|
tmp = env->gpr[3];
|
||||||
|
env->gpr[3] = env->tgpr[3];
|
||||||
|
env->tgpr[3] = tmp;
|
||||||
|
msr |= env->crf[0] << 28;
|
||||||
|
msr |= env->error_code; /* key, D/I, S/L bits */
|
||||||
|
/* Set way using a LRU mechanism */
|
||||||
|
msr |= (env->last_way ^ 1) << 17;
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1200 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1300:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_601:
|
||||||
|
case PPC_FLAGS_EXCP_602:
|
||||||
|
case PPC_FLAGS_EXCP_603:
|
||||||
|
case PPC_FLAGS_EXCP_604:
|
||||||
|
case PPC_FLAGS_EXCP_7x0:
|
||||||
|
case PPC_FLAGS_EXCP_7x5:
|
||||||
|
/* IABR on 6xx/7xx */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "IABR exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1300 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1400:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_601:
|
||||||
|
case PPC_FLAGS_EXCP_602:
|
||||||
|
case PPC_FLAGS_EXCP_603:
|
||||||
|
case PPC_FLAGS_EXCP_604:
|
||||||
|
case PPC_FLAGS_EXCP_7x0:
|
||||||
|
case PPC_FLAGS_EXCP_7x5:
|
||||||
|
/* SMI on 6xx/7xx */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "SMI exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1400 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1500:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_602:
|
||||||
|
/* Watchdog on 602 */
|
||||||
|
cpu_abort(env,
|
||||||
|
"602 watchdog exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_970:
|
||||||
|
/* Soft patch exception on 970 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"970 soft-patch exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_74xx:
|
||||||
|
/* VPU assist on 74xx */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "VPU assist exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1500 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1600:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_602:
|
||||||
|
/* Emulation trap on 602 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "602 emulation trap exception "
|
||||||
|
"is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_970:
|
||||||
|
/* Maintenance exception on 970 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"970 maintenance exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1600 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1700:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_7x0:
|
||||||
|
case PPC_FLAGS_EXCP_7x5:
|
||||||
|
/* Thermal management interrupt on G3 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "G3 thermal management exception "
|
||||||
|
"is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_970:
|
||||||
|
/* VPU assist on 970 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"970 VPU assist exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1700 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1800:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_970:
|
||||||
|
/* Thermal exception on 970 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "970 thermal management exception "
|
||||||
|
"is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1800 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x2000:
|
||||||
|
switch (PPC_EXCP(env)) {
|
||||||
|
case PPC_FLAGS_EXCP_40x:
|
||||||
|
/* DEBUG on 4xx */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env, "40x debug exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
case PPC_FLAGS_EXCP_601:
|
||||||
|
/* Run mode exception on 601 */
|
||||||
|
/* XXX: TODO */
|
||||||
|
cpu_abort(env,
|
||||||
|
"601 run mode exception is not implemented yet !\n");
|
||||||
|
goto store_next;
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception 0x1800 !\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
/* Other exceptions */
|
||||||
|
/* Qemu internal exceptions:
|
||||||
|
* we should never come here with those values: abort execution
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
cpu_abort(env, "Invalid exception: code %d (%04x)\n", excp, excp);
|
||||||
|
return;
|
||||||
store_current:
|
store_current:
|
||||||
/* SRR0 is set to current instruction */
|
/* save current instruction location */
|
||||||
env->spr[SPR_SRR0] = (uint32_t)env->nip - 4;
|
*srr_0 = (env->nip - 4) & 0xFFFFFFFFULL;
|
||||||
break;
|
break;
|
||||||
store_next:
|
store_next:
|
||||||
/* SRR0 is set to next instruction */
|
/* save next instruction location */
|
||||||
env->spr[SPR_SRR0] = (uint32_t)env->nip;
|
*srr_0 = env->nip & 0xFFFFFFFFULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
env->spr[SPR_SRR1] = msr;
|
/* Save msr */
|
||||||
|
*srr_1 = msr;
|
||||||
|
/* If we disactivated any translation, flush TLBs */
|
||||||
|
if (msr_ir || msr_dr) {
|
||||||
|
tlb_flush(env, 1);
|
||||||
|
}
|
||||||
/* reload MSR with correct bits */
|
/* reload MSR with correct bits */
|
||||||
msr_pow = 0;
|
|
||||||
msr_ee = 0;
|
msr_ee = 0;
|
||||||
msr_pr = 0;
|
msr_pr = 0;
|
||||||
msr_fp = 0;
|
msr_fp = 0;
|
||||||
|
@ -1193,14 +1486,11 @@ void do_interrupt (CPUState *env)
|
||||||
msr_dr = 0;
|
msr_dr = 0;
|
||||||
msr_ri = 0;
|
msr_ri = 0;
|
||||||
msr_le = msr_ile;
|
msr_le = msr_ile;
|
||||||
|
msr_sf = msr_isf;
|
||||||
do_compute_hflags(env);
|
do_compute_hflags(env);
|
||||||
/* Jump to handler */
|
/* Jump to handler */
|
||||||
env->nip = excp << 8;
|
env->nip = excp;
|
||||||
env->exception_index = EXCP_NONE;
|
env->exception_index = EXCP_NONE;
|
||||||
/* Invalidate all TLB as we may have changed translation mode */
|
|
||||||
#ifdef ACCURATE_TLB_FLUSH
|
|
||||||
tlb_flush(env, 1);
|
|
||||||
#endif
|
|
||||||
/* 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 */
|
||||||
#ifdef __sparc__
|
#ifdef __sparc__
|
||||||
|
@ -1208,6 +1498,6 @@ void do_interrupt (CPUState *env)
|
||||||
#else
|
#else
|
||||||
T0 = 0;
|
T0 = 0;
|
||||||
#endif
|
#endif
|
||||||
env->exception_index = -1;
|
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||||
}
|
}
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
|
|
|
@ -204,16 +204,6 @@ PPC_OP(update_nip)
|
||||||
env->nip = PARAM(1);
|
env->nip = PARAM(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PPC_OP(debug)
|
|
||||||
{
|
|
||||||
env->nip = PARAM(1);
|
|
||||||
#if defined (DEBUG_OP)
|
|
||||||
dump_state();
|
|
||||||
#endif
|
|
||||||
do_raise_exception(EXCP_DEBUG);
|
|
||||||
RETURN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Segment registers load and store with immediate index */
|
/* Segment registers load and store with immediate index */
|
||||||
PPC_OP(load_srin)
|
PPC_OP(load_srin)
|
||||||
{
|
{
|
||||||
|
@ -1384,14 +1374,10 @@ PPC_OP(check_reservation)
|
||||||
/* Return from interrupt */
|
/* Return from interrupt */
|
||||||
PPC_OP(rfi)
|
PPC_OP(rfi)
|
||||||
{
|
{
|
||||||
regs->nip = regs->spr[SPR_SRR0] & ~0x00000003;
|
env->nip = env->spr[SPR_SRR0] & ~0x00000003;
|
||||||
#if 1 // TRY
|
T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
|
||||||
T0 = regs->spr[SPR_SRR1] & ~0xFFF00000;
|
|
||||||
#else
|
|
||||||
T0 = regs->spr[SPR_SRR1] & ~0xFFFF0000;
|
|
||||||
#endif
|
|
||||||
do_store_msr(env, T0);
|
do_store_msr(env, T0);
|
||||||
do_raise_exception(EXCP_RFI);
|
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,12 +42,6 @@ void do_raise_exception_err (uint32_t exception, int error_code)
|
||||||
printf("Raise exception %3x code : %d\n", exception, error_code);
|
printf("Raise exception %3x code : %d\n", exception, error_code);
|
||||||
#endif
|
#endif
|
||||||
switch (exception) {
|
switch (exception) {
|
||||||
case EXCP_EXTERNAL:
|
|
||||||
case EXCP_DECR:
|
|
||||||
printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n");
|
|
||||||
if (msr_ee == 0)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
case EXCP_PROGRAM:
|
case EXCP_PROGRAM:
|
||||||
if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
|
if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -179,6 +179,12 @@ static inline void RET_STOP (DisasContext *ctx)
|
||||||
RET_EXCP(ctx, EXCP_MTMSR, 0);
|
RET_EXCP(ctx, EXCP_MTMSR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void RET_CHG_FLOW (DisasContext *ctx)
|
||||||
|
{
|
||||||
|
gen_op_raise_exception_err(EXCP_MTMSR, 0);
|
||||||
|
ctx->exception = EXCP_MTMSR;
|
||||||
|
}
|
||||||
|
|
||||||
#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
|
#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
|
||||||
static void gen_##name (DisasContext *ctx); \
|
static void gen_##name (DisasContext *ctx); \
|
||||||
GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \
|
GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \
|
||||||
|
@ -1895,7 +1901,7 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gen_op_rfi();
|
gen_op_rfi();
|
||||||
RET_EXCP(ctx, EXCP_RFI, 0);
|
RET_CHG_FLOW(ctx);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2555,7 +2561,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
|
||||||
(msr_se && (ctx.nip < 0x100 ||
|
(msr_se && (ctx.nip < 0x100 ||
|
||||||
ctx.nip > 0xF00 ||
|
ctx.nip > 0xF00 ||
|
||||||
(ctx.nip & 0xFC) != 0x04) &&
|
(ctx.nip & 0xFC) != 0x04) &&
|
||||||
ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI &&
|
ctx.exception != EXCP_SYSCALL &&
|
||||||
|
ctx.exception != EXCP_SYSCALL_USER &&
|
||||||
ctx.exception != EXCP_TRAP)) {
|
ctx.exception != EXCP_TRAP)) {
|
||||||
RET_EXCP(ctxp, EXCP_TRACE, 0);
|
RET_EXCP(ctxp, EXCP_TRACE, 0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue