diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2005-07-02 22:09:27 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2005-07-02 22:09:27 +0000 |
commit | 2be0071f22f5719eb5e2800f070547227ba37e5a (patch) | |
tree | 099300f6f83480d280a2b2b10846cd245a45c816 | |
parent | f68c781c2d08fec54ae460749b76b422c2a1921f (diff) |
simplified PowerPC exception handling (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1492 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | cpu-defs.h | 6 | ||||
-rw-r--r-- | linux-user/main.c | 45 | ||||
-rw-r--r-- | target-ppc/cpu.h | 116 | ||||
-rw-r--r-- | target-ppc/helper.c | 502 | ||||
-rw-r--r-- | target-ppc/op.c | 20 | ||||
-rw-r--r-- | target-ppc/op_helper.c | 6 | ||||
-rw-r--r-- | target-ppc/translate.c | 11 |
7 files changed, 482 insertions, 224 deletions
diff --git a/cpu-defs.h b/cpu-defs.h index c58d271391..83d1748e21 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -68,9 +68,9 @@ typedef uint64_t target_phys_addr_t; #define HOST_LONG_SIZE (HOST_LONG_BITS / 8) -#define EXCP_INTERRUPT 256 /* async interruption */ -#define EXCP_HLT 257 /* hlt instruction reached */ -#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ +#define EXCP_INTERRUPT 0x10000 /* async interruption */ +#define EXCP_HLT 0x10001 /* hlt instruction reached */ +#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ #define MAX_BREAKPOINTS 32 diff --git a/linux-user/main.c b/linux-user/main.c index d8fd0e4087..856147f049 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -706,28 +706,22 @@ void cpu_loop(CPUPPCState *env) fprintf(logfile, "Invalid data memory access: 0x%08x\n", env->spr[SPR_DAR]); } - switch (env->error_code & 0xF) { - case EXCP_DSI_TRANSLATE: + switch (env->error_code & 0xFF000000) { + case 0x40000000: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; break; - case EXCP_DSI_NOTSUP: - case EXCP_DSI_EXTERNAL: + case 0x04000000: info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLADR; break; - case EXCP_DSI_PROT: + case 0x08000000: 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", @@ -748,19 +742,14 @@ void cpu_loop(CPUPPCState *env) fprintf(stderr, "Invalid instruction fetch\n"); if (loglevel) fprintf(logfile, "Invalid instruction fetch\n"); - switch (env->error_code) { - case EXCP_ISI_TRANSLATE: + switch (env->error_code & 0xFF000000) { + case 0x40000000: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; 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: + case 0x10000000: + case 0x08000000: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_ACCERR; @@ -930,18 +919,6 @@ void cpu_loop(CPUPPCState *env) 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 */ - /* 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: /* Do nothing: we use this to trace execution */ break; @@ -963,12 +940,6 @@ void cpu_loop(CPUPPCState *env) 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; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index a7b4051e1e..7fc79434a1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -924,62 +924,72 @@ enum { /*****************************************************************************/ /* Exceptions */ -enum { - EXCP_NONE = -1, - /* PowerPC hardware exceptions : exception vector / 0x100 */ - EXCP_RESET = 0x01, /* System reset */ - EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */ - EXCP_DSI = 0x03, /* Impossible memory access */ - EXCP_ISI = 0x04, /* Impossible instruction fetch */ - EXCP_EXTERNAL = 0x05, /* External interruption */ - EXCP_ALIGN = 0x06, /* Alignment exception */ - EXCP_PROGRAM = 0x07, /* Program exception */ - EXCP_NO_FP = 0x08, /* No floating point */ - EXCP_DECR = 0x09, /* Decrementer exception */ - EXCP_RESA = 0x0A, /* Implementation specific */ - EXCP_RESB = 0x0B, /* Implementation specific */ - EXCP_SYSCALL = 0x0C, /* System call */ - EXCP_TRACE = 0x0D, /* Trace exception (optional) */ - EXCP_FP_ASSIST = 0x0E, /* Floating-point assist (optional) */ - /* MPC740/745/750 & IBM 750 */ - EXCP_PERF = 0x0F, /* Performance monitor */ - EXCP_IABR = 0x13, /* Instruction address breakpoint */ - EXCP_SMI = 0x14, /* System management interrupt */ - EXCP_THRM = 0x15, /* Thermal management interrupt */ - /* MPC755 */ - EXCP_TLBMISS = 0x10, /* Instruction TLB miss */ - EXCP_TLBMISS_DL = 0x11, /* Data TLB miss for load */ - EXCP_TLBMISS_DS = 0x12, /* Data TLB miss for store */ - EXCP_PPC_MAX = 0x16, - /* Qemu exception */ - EXCP_OFCALL = 0x20, /* Call open-firmware emulator */ - EXCP_RTASCALL = 0x21, /* Call RTAS emulator */ - /* Special cases where we want to stop translation */ - EXCP_MTMSR = 0x104, /* mtmsr instruction: */ +#define EXCP_NONE -1 +/* PowerPC hardware exceptions : exception vectors defined in PowerPC book 3 */ +#define EXCP_RESET 0x0100 /* System reset */ +#define EXCP_MACHINE_CHECK 0x0200 /* Machine check exception */ +#define EXCP_DSI 0x0300 /* Data storage exception */ +#define EXCP_DSEG 0x0380 /* Data segment exception */ +#define EXCP_ISI 0x0400 /* Instruction storage exception */ +#define EXCP_ISEG 0x0480 /* Instruction segment exception */ +#define EXCP_EXTERNAL 0x0500 /* External interruption */ +#define EXCP_ALIGN 0x0600 /* Alignment exception */ +#define EXCP_PROGRAM 0x0700 /* Program exception */ +#define EXCP_NO_FP 0x0800 /* Floating point unavailable exception */ +#define EXCP_DECR 0x0900 /* Decrementer exception */ +#define EXCP_HDECR 0x0980 /* Hypervisor decrementer exception */ +#define EXCP_SYSCALL 0x0C00 /* System call */ +#define EXCP_TRACE 0x0D00 /* Trace exception */ +#define EXCP_PERF 0x0F00 /* Performance monitor exception */ +/* Exceptions defined in PowerPC 32 bits programming environment manual */ +#define EXCP_FP_ASSIST 0x0E00 /* Floating-point assist */ +/* Implementation specific exceptions */ +/* 40x exceptions */ +#define EXCP_40x_PIT 0x1000 /* Programmable interval timer interrupt */ +#define EXCP_40x_FIT 0x1010 /* Fixed interval timer interrupt */ +#define EXCP_40x_WATCHDOG 0x1020 /* Watchdog timer exception */ +#define EXCP_40x_DTLBMISS 0x1100 /* Data TLB miss exception */ +#define EXCP_40x_ITLBMISS 0x1200 /* Instruction TLB miss exception */ +#define EXCP_40x_DEBUG 0x2000 /* Debug exception */ +/* 405 specific exceptions */ +#define EXCP_405_APU 0x0F20 /* APU unavailable exception */ +/* TLB assist exceptions (602/603) */ +#define EXCP_I_TLBMISS 0x1000 /* Instruction TLB miss */ +#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 */ - EXCP_BRANCH = 0x108, /* branch instruction */ - EXCP_RFI = 0x10C, /* return from interrupt */ - EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */ -}; +#define EXCP_BRANCH 0x11001 /* branch instruction */ +#define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */ +#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ */ + /* Error codes */ 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 */ EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 6ddc0f47ff..fbecb76d02 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -22,8 +22,6 @@ //#define DEBUG_MMU //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS -/* accurate but slower TLB flush in exceptions */ -//#define ACCURATE_TLB_FLUSH /*****************************************************************************/ /* PowerPC MMU emulation */ @@ -524,20 +522,25 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, switch (ret) { case -1: /* No matches in page tables */ - error_code = EXCP_ISI_TRANSLATE; + error_code = 0x40000000; break; case -2: /* Access rights violation */ - error_code = EXCP_ISI_PROT; + error_code = 0x08000000; break; case -3: /* No execute protection violation */ - error_code = EXCP_ISI_NOEXEC; + error_code = 0x10000000; break; case -4: /* Direct store exception */ /* 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; } } else { @@ -545,11 +548,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, switch (ret) { case -1: /* No matches in page tables */ - error_code = EXCP_DSI_TRANSLATE; + error_code = 0x40000000; break; case -2: /* Access rights violation */ - error_code = EXCP_DSI_PROT; + error_code = 0x08000000; break; case -4: /* Direct store exception */ @@ -561,14 +564,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, break; case ACCESS_RES: /* lwarx, ldarx or srwcx. */ - exception = EXCP_DSI; - error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT; + error_code = 0x04000000; break; case ACCESS_EXT: /* eciwx or ecowx */ - exception = EXCP_DSI; - error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | - EXCP_DSI_ECXW; + error_code = 0x04100000; break; default: 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; break; } + case -5: + /* No match in segment table */ + exception = EXCP_DSEG; + error_code = 0; + break; } if (rw) - error_code |= EXCP_DSI_STORE; + error_code |= 0x02000000; /* Store fault address */ env->spr[SPR_DAR] = address; + env->spr[SPR_DSISR] = error_code; } #if 0 printf("%s: set exception to %d %02x\n", @@ -985,119 +991,107 @@ static void dump_syscall(CPUState *env) void do_interrupt (CPUState *env) { - uint32_t msr; + target_ulong msr, *srr_0, *srr_1, tmp; int excp; excp = env->exception_index; 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 ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) - { - if (loglevel > 0) { - fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", - env->nip, excp << 8, env->error_code); + if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { + if (loglevel != 0) { + fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n", + (unsigned long)env->nip, excp, env->error_code); + cpu_dump_state(env, logfile, fprintf, 0); } - if (loglevel > 0) - cpu_dump_state(env, logfile, fprintf, 0); } #endif if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", - env->nip, excp << 8, env->error_code); + fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n", + (unsigned long)env->nip, excp, env->error_code); } + msr_pow = 0; /* Generate informations in save/restore registers */ switch (excp) { - case EXCP_NONE: - /* Do nothing */ -#if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_NONE\n", __func__); -#endif - return; - case EXCP_RESET: - if (msr_ip) - excp += 0xFFC00; + /* Generic PowerPC exceptions */ + case EXCP_RESET: /* 0x0100 */ + if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) { + if (msr_ip) + excp += 0xFFC00; + excp |= 0xFFC00000; + } else { + srr_0 = &env->spr[SPR_40x_SRR2]; + srr_1 = &env->spr[SPR_40x_SRR3]; + } goto store_next; - case EXCP_MACHINE_CHECK: + case EXCP_MACHINE_CHECK: /* 0x0200 */ if (msr_me == 0) { 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; break; - case EXCP_DSI: + case EXCP_DSI: /* 0x0300 */ /* Store exception cause */ /* data location address has been stored * when the fault has been detected - */ + */ 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 (loglevel) { fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } else { - printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", - env->spr[SPR_DSISR], env->spr[SPR_DAR], env->nip); + printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n", + env->spr[SPR_DSISR], env->spr[SPR_DAR]); } #endif goto store_next; - case EXCP_ISI: + case EXCP_ISI: /* 0x0400 */ /* Store exception cause */ msr &= ~0xFFFF0000; - if (env->error_code == EXCP_ISI_TRANSLATE) - 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; + msr |= env->error_code; #if defined (DEBUG_EXCEPTIONS) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", 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 goto store_next; - case EXCP_EXTERNAL: + case EXCP_EXTERNAL: /* 0x0500 */ if (msr_ee == 0) { #if defined (DEBUG_EXCEPTIONS) if (loglevel > 0) { fprintf(logfile, "Skipping hardware interrupt\n"); - } + } #endif /* Requeue it */ - do_raise_exception(EXCP_EXTERNAL); + env->interrupt_request |= CPU_INTERRUPT_HARD; return; - } + } goto store_next; - case EXCP_ALIGN: - /* Store exception cause */ - /* Get rS/rD and rA from faulting opcode */ - env->spr[SPR_DSISR] |= - (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; - /* data location address has been stored - * when the fault has been detected - */ + case EXCP_ALIGN: /* 0x0600 */ + if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) { + /* Store exception cause */ + /* Get rS/rD and rA from faulting opcode */ + env->spr[SPR_DSISR] |= + (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; + /* 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; - case EXCP_PROGRAM: + case EXCP_PROGRAM: /* 0x0700 */ msr &= ~0xFFFF0000; switch (env->error_code & ~0xF) { case EXCP_FP: @@ -1131,17 +1125,19 @@ void do_interrupt (CPUState *env) } msr |= 0x00010000; goto store_current; - case EXCP_NO_FP: + case EXCP_NO_FP: /* 0x0800 */ msr &= ~0xFFFF0000; goto store_current; case EXCP_DECR: if (msr_ee == 0) { +#if 1 /* Requeue it */ - do_raise_exception(EXCP_DECR); + env->interrupt_request |= CPU_INTERRUPT_TIMER; +#endif return; } goto store_next; - case EXCP_SYSCALL: + case EXCP_SYSCALL: /* 0x0C00 */ /* NOTE: this is a temporary hack to support graphics OSI calls from the MOL driver */ if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && @@ -1153,35 +1149,332 @@ void do_interrupt (CPUState *env) dump_syscall(env); } 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; + case EXCP_PERF: /* 0x0F00 */ + /* XXX: TODO */ + cpu_abort(env, + "Performance counter exception is not implemented yet !\n"); + goto store_next; + /* 32 bits PowerPC specific exceptions */ + case EXCP_FP_ASSIST: /* 0x0E00 */ + /* XXX: TODO */ + cpu_abort(env, "Floating point assist exception " + "is not implemented yet !\n"); + goto store_next; + /* 64 bits PowerPC exceptions */ + case EXCP_DSEG: /* 0x0380 */ + /* XXX: TODO */ + cpu_abort(env, "Data segment exception is not implemented yet !\n"); goto store_next; - case EXCP_FP_ASSIST: + case EXCP_ISEG: /* 0x0480 */ + /* XXX: TODO */ + cpu_abort(env, + "Instruction segment exception is not implemented yet !\n"); goto store_next; - case EXCP_MTMSR: - /* Nothing to do */ + case EXCP_HDECR: /* 0x0980 */ + if (msr_ee == 0) { +#if 1 + /* Requeue it */ + env->interrupt_request |= CPU_INTERRUPT_TIMER; +#endif return; - case EXCP_BRANCH: - /* Nothing to do */ + } + 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 EXCP_RFI: - /* Restore user-mode state */ -#if defined (DEBUG_EXCEPTIONS) - if (msr_pr == 1) - printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); + 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: - /* SRR0 is set to current instruction */ - env->spr[SPR_SRR0] = (uint32_t)env->nip - 4; + /* save current instruction location */ + *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL; break; store_next: - /* SRR0 is set to next instruction */ - env->spr[SPR_SRR0] = (uint32_t)env->nip; + /* save next instruction location */ + *srr_0 = env->nip & 0xFFFFFFFFULL; 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 */ - msr_pow = 0; msr_ee = 0; msr_pr = 0; msr_fp = 0; @@ -1193,14 +1486,11 @@ void do_interrupt (CPUState *env) msr_dr = 0; msr_ri = 0; msr_le = msr_ile; + msr_sf = msr_isf; do_compute_hflags(env); /* Jump to handler */ - env->nip = excp << 8; + env->nip = excp; 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 the program flow was changed */ #ifdef __sparc__ @@ -1208,6 +1498,6 @@ void do_interrupt (CPUState *env) #else T0 = 0; #endif - env->exception_index = -1; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/op.c b/target-ppc/op.c index 38ed13aa13..c7953662be 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -204,16 +204,6 @@ PPC_OP(update_nip) 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 */ PPC_OP(load_srin) { @@ -1384,14 +1374,10 @@ PPC_OP(check_reservation) /* Return from interrupt */ PPC_OP(rfi) { - regs->nip = regs->spr[SPR_SRR0] & ~0x00000003; -#if 1 // TRY - T0 = regs->spr[SPR_SRR1] & ~0xFFF00000; -#else - T0 = regs->spr[SPR_SRR1] & ~0xFFFF0000; -#endif + env->nip = env->spr[SPR_SRR0] & ~0x00000003; + T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL; do_store_msr(env, T0); - do_raise_exception(EXCP_RFI); + env->interrupt_request |= CPU_INTERRUPT_EXITTB; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 670e278947..e57fbe461c 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -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); #endif 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: if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) return; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 52a28def14..70f88637df 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -179,6 +179,12 @@ static inline void RET_STOP (DisasContext *ctx) 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) \ static void gen_##name (DisasContext *ctx); \ GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \ @@ -1895,7 +1901,7 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) return; } gen_op_rfi(); - RET_EXCP(ctx, EXCP_RFI, 0); + RET_CHG_FLOW(ctx); #endif } @@ -2555,7 +2561,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, (msr_se && (ctx.nip < 0x100 || ctx.nip > 0xF00 || (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)) { RET_EXCP(ctxp, EXCP_TRACE, 0); } |