summary refs log tree commit diff stats
path: root/target-ppc/excp_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc/excp_helper.c')
-rw-r--r--target-ppc/excp_helper.c203
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