diff options
Diffstat (limited to 'target-ppc/excp_helper.c')
-rw-r--r-- | target-ppc/excp_helper.c | 203 |
1 files changed, 97 insertions, 106 deletions
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index d6e1678a63..04ed4da1f4 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -198,7 +198,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) default: goto excp_invalid; } - goto store_next; + break; case POWERPC_EXCP_MCHECK: /* Machine check exception */ if (msr_me == 0) { /* Machine check exception is not enabled. @@ -235,16 +235,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) default: break; } - goto store_next; + break; case POWERPC_EXCP_DSI: /* Data storage exception */ LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); - goto store_next; + break; case POWERPC_EXCP_ISI: /* Instruction storage exception */ LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx "\n", msr, env->nip); msr |= env->error_code; - goto store_next; + break; case POWERPC_EXCP_EXTERNAL: /* External input */ cs = CPU(cpu); @@ -258,13 +258,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) /* IACK the IRQ on delivery */ env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); } - goto store_next; + break; case POWERPC_EXCP_ALIGN: /* Alignment exception */ - /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ - env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4)) - & 0x03FF0000) >> 16; - goto store_next; + /* Note: the opcode fields will not be set properly for a direct + * store load/store, but nobody cares as nobody actually uses + * direct store segments. + */ + env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; + break; case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: @@ -274,11 +276,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) env->error_code = 0; return; } + + /* FP exceptions always have NIP pointing to the faulting + * instruction, so always use store_next and claim we are + * precise in the MSR. + */ msr |= 0x00100000; - if (msr_fe0 == msr_fe1) { - goto store_next; - } - msr |= 0x00010000; break; case POWERPC_EXCP_INVAL: LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); @@ -299,19 +302,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) env->error_code); break; } - goto store_current; - case POWERPC_EXCP_HV_EMU: - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_current; - case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ - goto store_current; + break; case POWERPC_EXCP_SYSCALL: /* System call exception */ dump_syscall(env); lev = env->error_code; + /* We need to correct the NIP which in this case is supposed + * to point to the next instruction + */ + env->nip += 4; + /* "PAPR mode" built-in hypercall emulation */ if ((lev == 1) && cpu_ppc_hypercall) { cpu_ppc_hypercall(cpu); @@ -320,15 +320,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) if (lev == 1) { new_msr |= (target_ulong)MSR_HVB; } - goto store_next; + break; + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ - goto store_current; case POWERPC_EXCP_DECR: /* Decrementer exception */ - goto store_next; + break; case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ /* FIT on 4xx */ LOG_EXCP("FIT exception\n"); - goto store_next; + break; case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ LOG_EXCP("WDT exception\n"); switch (excp_model) { @@ -339,11 +339,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) default: break; } - goto store_next; + break; case POWERPC_EXCP_DTLB: /* Data TLB error */ - goto store_next; case POWERPC_EXCP_ITLB: /* Instruction TLB error */ - goto store_next; + break; case POWERPC_EXCP_DEBUG: /* Debug interrupt */ switch (excp_model) { case POWERPC_EXCP_BOOKE: @@ -358,33 +357,33 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } /* XXX: TODO */ cpu_abort(cs, "Debug exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_current; + break; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ /* XXX: TODO */ cpu_abort(cs, "Embedded floating point data exception " "is not implemented yet !\n"); env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_next; + break; case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ /* XXX: TODO */ cpu_abort(cs, "Embedded floating point round exception " "is not implemented yet !\n"); env->spr[SPR_BOOKE_ESR] = ESR_SPV; - goto store_next; + break; case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ /* XXX: TODO */ cpu_abort(cs, "Performance counter exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ - goto store_next; + break; case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ srr0 = SPR_BOOKE_CSRR0; srr1 = SPR_BOOKE_CSRR1; - goto store_next; + break; case POWERPC_EXCP_RESET: /* System reset exception */ if (msr_pow) { /* indicate that we resumed from power save mode */ @@ -395,65 +394,42 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) new_msr |= (target_ulong)MSR_HVB; ail = 0; - goto store_next; + break; case POWERPC_EXCP_DSEG: /* Data segment exception */ - goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ - goto store_next; - case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; case POWERPC_EXCP_TRACE: /* Trace exception */ - goto store_next; + break; + case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ - srr0 = SPR_HSRR0; - srr1 = SPR_HSRR1; - new_msr |= (target_ulong)MSR_HVB; - new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ + case POWERPC_EXCP_HV_EMU: srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; new_msr |= (target_ulong)MSR_HVB; new_msr |= env->msr & ((target_ulong)1 << MSR_RI); - goto store_next; + break; case POWERPC_EXCP_VPU: /* Vector unavailable exception */ - goto store_current; case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ - goto store_current; case POWERPC_EXCP_FU: /* Facility unavailable exception */ - goto store_current; + break; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ LOG_EXCP("PIT exception\n"); - goto store_next; + break; case POWERPC_EXCP_IO: /* IO error exception */ /* XXX: TODO */ cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_RUNM: /* Run mode exception */ /* XXX: TODO */ cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_EMUL: /* Emulation trap exception */ /* XXX: TODO */ cpu_abort(cs, "602 emulation trap exception " "is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ switch (excp_model) { case POWERPC_EXCP_602: @@ -568,71 +544,67 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) cpu_abort(cs, "Invalid data store TLB miss exception\n"); break; } - goto store_next; + break; case POWERPC_EXCP_FPA: /* Floating-point assist exception */ /* XXX: TODO */ cpu_abort(cs, "Floating point assist exception " "is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_DABR: /* Data address breakpoint */ /* XXX: TODO */ cpu_abort(cs, "DABR exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ /* XXX: TODO */ cpu_abort(cs, "IABR exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_SMI: /* System management interrupt */ /* XXX: TODO */ cpu_abort(cs, "SMI exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_THERM: /* Thermal interrupt */ /* XXX: TODO */ cpu_abort(cs, "Thermal management exception " "is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ /* XXX: TODO */ cpu_abort(cs, "Performance counter exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_VPUA: /* Vector assist exception */ /* XXX: TODO */ cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_SOFTP: /* Soft patch exception */ /* XXX: TODO */ cpu_abort(cs, "970 soft-patch exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_MAINT: /* Maintenance exception */ /* XXX: TODO */ cpu_abort(cs, "970 maintenance exception is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ /* XXX: TODO */ cpu_abort(cs, "Maskable external exception " "is not implemented yet !\n"); - goto store_next; + break; case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ /* XXX: TODO */ cpu_abort(cs, "Non maskable external exception " "is not implemented yet !\n"); - goto store_next; + break; default: excp_invalid: cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); break; - store_current: - /* save current instruction location */ - env->spr[srr0] = env->nip - 4; - break; - store_next: - /* save next instruction location */ - env->spr[srr0] = env->nip; - break; } + + /* Save PC */ + env->spr[srr0] = env->nip; + /* Save MSR */ env->spr[srr1] = msr; @@ -898,34 +870,53 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr) /*****************************************************************************/ /* Exceptions processing helpers */ -void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, - uint32_t error_code) +void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, + uint32_t error_code, uintptr_t raddr) { CPUState *cs = CPU(ppc_env_get_cpu(env)); -#if 0 - printf("Raise exception %3x code : %d\n", exception, error_code); -#endif cs->exception_index = exception; env->error_code = error_code; - cpu_loop_exit(cs); + cpu_loop_exit_restore(cs, raddr); +} + +void raise_exception_err(CPUPPCState *env, uint32_t exception, + uint32_t error_code) +{ + raise_exception_err_ra(env, exception, error_code, 0); +} + +void raise_exception(CPUPPCState *env, uint32_t exception) +{ + raise_exception_err_ra(env, exception, 0, 0); +} + +void raise_exception_ra(CPUPPCState *env, uint32_t exception, + uintptr_t raddr) +{ + raise_exception_err_ra(env, exception, 0, raddr); +} + +void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, + uint32_t error_code) +{ + raise_exception_err_ra(env, exception, error_code, 0); } void helper_raise_exception(CPUPPCState *env, uint32_t exception) { - helper_raise_exception_err(env, exception, 0); + raise_exception_err_ra(env, exception, 0, 0); } #if !defined(CONFIG_USER_ONLY) void helper_store_msr(CPUPPCState *env, target_ulong val) { - CPUState *cs; + uint32_t excp = hreg_store_msr(env, val, 0); - val = hreg_store_msr(env, val, 0); - if (val != 0) { - cs = CPU(ppc_env_get_cpu(env)); + if (excp != 0) { + CPUState *cs = CPU(ppc_env_get_cpu(env)); cs->interrupt_request |= CPU_INTERRUPT_EXITTB; - helper_raise_exception(env, val); + raise_exception(env, excp); } } @@ -951,7 +942,7 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) * but this doesn't seem to be a problem. */ env->msr |= (1ull << MSR_EE); - helper_raise_exception(env, EXCP_HLT); + raise_exception(env, EXCP_HLT); } #endif /* defined(TARGET_PPC64) */ @@ -1041,8 +1032,8 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_TRAP); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_TRAP, GETPC()); } } @@ -1055,8 +1046,8 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { - helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_TRAP); + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_TRAP, GETPC()); } } #endif |