diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index b0934d9be4..012677965f 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -174,6 +174,33 @@ enum {
     POWERPC_EXCP_TRAP          = 0x40,
 };
 
+typedef struct PPCInterrupt PPCInterrupt;
+typedef struct ppc_intr_args ppc_intr_args;
+typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCInterrupt *intr,
+                              int excp_model, ppc_intr_args *regs,
+                              bool *ignore);
+
+struct ppc_intr_args {
+    target_ulong nip;
+    target_ulong msr;
+    target_ulong new_nip;
+    target_ulong new_msr;
+    int sprn_srr0;
+    int sprn_srr1;
+    int sprn_asrr0;
+    int sprn_asrr1;
+    int lev;
+};
+
+struct PPCInterrupt {
+    Object parent;
+
+    int id;
+    const char *name;
+    target_ulong addr;
+    ppc_intr_fn_t setup_regs;
+};
+
 #define PPC_INPUT(env) ((env)->bus_model)
 
 /*****************************************************************************/
@@ -1115,7 +1142,7 @@ struct CPUPPCState {
     uint32_t irq_input_state;
     void **irq_inputs;
 
-    target_ulong excp_vectors[POWERPC_EXCP_NB]; /* Exception vectors */
+    PPCInterrupt entry_points[POWERPC_EXCP_NB];
     target_ulong excp_prefix;
     target_ulong ivor_mask;
     target_ulong ivpr_mask;
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index d0411e7302..d91183357d 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -46,6 +46,7 @@
 #include "helper_regs.h"
 #include "internal.h"
 #include "spr_tcg.h"
+#include "ppc_intr.h"
 
 /* #define PPC_DEBUG_SPR */
 /* #define USE_APPLE_GDB */
@@ -2132,16 +2133,16 @@ static void register_8xx_sprs(CPUPPCState *env)
 static void init_excp_4xx_real(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
-    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_PIT);
+    ppc_intr_add(env, 0x00001010, POWERPC_EXCP_FIT);
+    ppc_intr_add(env, 0x00001020, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_DEBUG);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2152,20 +2153,20 @@ static void init_excp_4xx_real(CPUPPCState *env)
 static void init_excp_4xx_softmmu(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
-    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_PIT);
+    ppc_intr_add(env, 0x00001010, POWERPC_EXCP_FIT);
+    ppc_intr_add(env, 0x00001020, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_ITLB);
+    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_DEBUG);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2176,21 +2177,21 @@ static void init_excp_4xx_softmmu(CPUPPCState *env)
 static void init_excp_MPC5xx(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
-    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DABR]     = 0x00001C00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001C00;
-    env->excp_vectors[POWERPC_EXCP_MEXTBR]   = 0x00001E00;
-    env->excp_vectors[POWERPC_EXCP_NMEXTBR]  = 0x00001F00;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_FPA);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_EMUL);
+    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_DABR);
+    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001E00, POWERPC_EXCP_MEXTBR);
+    ppc_intr_add(env, 0x00001F00, POWERPC_EXCP_NMEXTBR);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2201,27 +2202,27 @@ static void init_excp_MPC5xx(CPUPPCState *env)
 static void init_excp_MPC8xx(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
-    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_ITLBE]    = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_DTLBE]    = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_DABR]     = 0x00001C00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001C00;
-    env->excp_vectors[POWERPC_EXCP_MEXTBR]   = 0x00001E00;
-    env->excp_vectors[POWERPC_EXCP_NMEXTBR]  = 0x00001F00;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_FPA);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_EMUL);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_ITLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_ITLBE);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_DTLBE);
+    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_DABR);
+    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001E00, POWERPC_EXCP_MEXTBR);
+    ppc_intr_add(env, 0x00001F00, POWERPC_EXCP_NMEXTBR);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2232,23 +2233,23 @@ static void init_excp_MPC8xx(CPUPPCState *env)
 static void init_excp_G2(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000A00;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2257,26 +2258,26 @@ static void init_excp_G2(CPUPPCState *env)
 static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000FFC;
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_SPEU]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_EFPDI]    = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_EFPRI]    = 0x00000000;
+    ppc_intr_add(env, 0x00000FFC, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_APU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FIT);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DTLB);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ITLB);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DEBUG);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SPEU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EFPDI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EFPRI);
     env->ivor_mask = 0x0000FFF7UL;
     env->ivpr_mask = ivpr_mask;
     /* Hardware reset vector */
@@ -2287,22 +2288,22 @@ static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
 static void init_excp_BookE(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_APU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FIT);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DTLB);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ITLB);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DEBUG);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2313,18 +2314,18 @@ static void init_excp_BookE(CPUPPCState *env)
 static void init_excp_601(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_IO]       = 0x00000A00;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_RUNM]     = 0x00002000;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_IO);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_RUNM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2334,24 +2335,24 @@ static void init_excp_602(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
     /* XXX: exception prefix has a special behavior on 602 */
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001500;
-    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001600;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001500, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_EMUL);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2360,22 +2361,22 @@ static void init_excp_602(CPUPPCState *env)
 static void init_excp_603(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2384,20 +2385,20 @@ static void init_excp_603(CPUPPCState *env)
 static void init_excp_604(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2406,21 +2407,21 @@ static void init_excp_604(CPUPPCState *env)
 static void init_excp_7x0(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2429,20 +2430,20 @@ static void init_excp_7x0(CPUPPCState *env)
 static void init_excp_750cl(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2451,20 +2452,20 @@ static void init_excp_750cl(CPUPPCState *env)
 static void init_excp_750cx(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2474,24 +2475,24 @@ static void init_excp_750cx(CPUPPCState *env)
 static void init_excp_7x5(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2500,23 +2501,23 @@ static void init_excp_7x5(CPUPPCState *env)
 static void init_excp_7400(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_VPUA);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2525,25 +2526,25 @@ static void init_excp_7400(CPUPPCState *env)
 static void init_excp_7450(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_VPUA);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2553,26 +2554,26 @@ static void init_excp_7450(CPUPPCState *env)
 static void init_excp_970(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_MAINT]    = 0x00001600;
-    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001700;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001800;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000380, POWERPC_EXCP_DSEG);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000480, POWERPC_EXCP_ISEG);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000980, POWERPC_EXCP_HDECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_MAINT);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_VPUA);
+    ppc_intr_add(env, 0x00001800, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x0000000000000100ULL;
 #endif
@@ -2581,27 +2582,27 @@ static void init_excp_970(CPUPPCState *env)
 static void init_excp_POWER7(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_HDSI]     = 0x00000E00;
-    env->excp_vectors[POWERPC_EXCP_HISI]     = 0x00000E20;
-    env->excp_vectors[POWERPC_EXCP_HV_EMU]   = 0x00000E40;
-    env->excp_vectors[POWERPC_EXCP_HV_MAINT] = 0x00000E60;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
-    env->excp_vectors[POWERPC_EXCP_VSXU]     = 0x00000F40;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000380, POWERPC_EXCP_DSEG);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000480, POWERPC_EXCP_ISEG);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000980, POWERPC_EXCP_HDECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_HDSI);
+    ppc_intr_add(env, 0x00000E20, POWERPC_EXCP_HISI);
+    ppc_intr_add(env, 0x00000E40, POWERPC_EXCP_HV_EMU);
+    ppc_intr_add(env, 0x00000E60, POWERPC_EXCP_HV_MAINT);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
+    ppc_intr_add(env, 0x00000F40, POWERPC_EXCP_VSXU);
     /* Hardware reset vector */
     env->hreset_vector = 0x0000000000000100ULL;
 #endif
@@ -2612,10 +2613,10 @@ static void init_excp_POWER8(CPUPPCState *env)
     init_excp_POWER7(env);
 
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_SDOOR]    = 0x00000A00;
-    env->excp_vectors[POWERPC_EXCP_FU]       = 0x00000F60;
-    env->excp_vectors[POWERPC_EXCP_HV_FU]    = 0x00000F80;
-    env->excp_vectors[POWERPC_EXCP_SDOOR_HV] = 0x00000E80;
+    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_SDOOR);
+    ppc_intr_add(env, 0x00000F60, POWERPC_EXCP_FU);
+    ppc_intr_add(env, 0x00000F80, POWERPC_EXCP_HV_FU);
+    ppc_intr_add(env, 0x00000E80, POWERPC_EXCP_SDOOR_HV);
 #endif
 }
 
@@ -2624,8 +2625,8 @@ static void init_excp_POWER9(CPUPPCState *env)
     init_excp_POWER8(env);
 
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_HVIRT]    = 0x00000EA0;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00017000;
+    ppc_intr_add(env, 0x00000EA0, POWERPC_EXCP_HVIRT);
+    ppc_intr_add(env, 0x00017000, POWERPC_EXCP_SYSCALL_VECTORED);
 #endif
 }
 
@@ -8375,13 +8376,8 @@ static void init_ppc_proc(PowerPCCPU *cpu)
     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
     CPUPPCState *env = &cpu->env;
 #if !defined(CONFIG_USER_ONLY)
-    int i;
 
     env->irq_inputs = NULL;
-    /* Set all exception vectors to an invalid address */
-    for (i = 0; i < POWERPC_EXCP_NB; i++) {
-        env->excp_vectors[i] = (target_ulong)(-1ULL);
-    }
     env->ivor_mask = 0x00000000;
     env->ivpr_mask = 0x00000000;
     /* Default MMU definitions */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 12bf829c8f..26cbfab923 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -29,14 +29,6 @@
 #endif
 
 /* #define DEBUG_OP */
-/* #define DEBUG_SOFTWARE_TLB */
-/* #define DEBUG_EXCEPTIONS */
-
-#ifdef DEBUG_EXCEPTIONS
-#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
-#else
-#  define LOG_EXCP(...) do { } while (0)
-#endif
 
 /*****************************************************************************/
 /* Exception processing */
@@ -58,32 +50,6 @@ static void ppc_hw_interrupt(CPUPPCState *env)
     env->error_code = 0;
 }
 #else /* defined(CONFIG_USER_ONLY) */
-static inline void dump_syscall(CPUPPCState *env)
-{
-    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
-                  " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
-                  " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
-                  " nip=" TARGET_FMT_lx "\n",
-                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
-                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
-                  ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
-                  ppc_dump_gpr(env, 8), env->nip);
-}
-
-static inline void dump_hcall(CPUPPCState *env)
-{
-    qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
-                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
-                  " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
-                  " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
-                  " nip=" TARGET_FMT_lx "\n",
-                  ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
-                  ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
-                  ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
-                  ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
-                  ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
-                  env->nip);
-}
 
 static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
                                 target_ulong *msr)
@@ -311,17 +277,6 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
     check_tlb_flush(env, false);
 }
 
-struct ppc_intr_args {
-    target_ulong nip;
-    target_ulong msr;
-    target_ulong new_nip;
-    target_ulong new_msr;
-    int sprn_srr0;
-    int sprn_srr1;
-    int sprn_asrr0;
-    int sprn_asrr1;
-};
-
 /*
  * Note that this function should be greatly optimized when called
  * with a constant excp, from ppc_hw_interrupt
@@ -331,11 +286,21 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     struct ppc_intr_args regs;
-    int lev = -1;
+    PPCInterrupt *intr;
+    bool ignore = false;
 
     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
 
+    if (excp == POWERPC_EXCP_NONE) {
+        return;
+    }
+
+    if (excp < POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
+        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+        return;
+    }
+
     /* new srr1 value excluding must-be-zero bits */
     if (excp_model == POWERPC_EXCP_BOOKE) {
         regs.msr = env->msr;
@@ -380,469 +345,21 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         excp = POWERPC_EXCP_PROGRAM;
     }
 
-    switch (excp) {
-    case POWERPC_EXCP_NONE:
-        /* Should never happen */
-        return;
-    case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
-        switch (excp_model) {
-        case POWERPC_EXCP_40x:
-            regs.sprn_srr0 = SPR_40x_SRR2;
-            regs.sprn_srr1 = SPR_40x_SRR3;
-            break;
-        case POWERPC_EXCP_BOOKE:
-            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
-            break;
-        case POWERPC_EXCP_G2:
-            break;
-        default:
-            goto excp_invalid;
-        }
-        break;
-    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
-        if (msr_me == 0) {
-            /*
-             * Machine check exception is not enabled.  Enter
-             * checkstop state.
-             */
-            fprintf(stderr, "Machine check while not allowed. "
-                    "Entering checkstop state\n");
-            if (qemu_log_separate()) {
-                qemu_log("Machine check while not allowed. "
-                        "Entering checkstop state\n");
-            }
-            cs->halted = 1;
-            cpu_interrupt_exittb(cs);
-        }
-        if (env->msr_mask & MSR_HVB) {
-            /*
-             * ISA specifies HV, but can be delivered to guest with HV
-             * clear (e.g., see FWNMI in PAPR).
-             */
-            regs.new_msr |= (target_ulong)MSR_HVB;
-        }
-
-        /* machine check exceptions don't have ME set */
-        regs.new_msr &= ~((target_ulong)1 << MSR_ME);
-
-        /* XXX: should also have something loaded in DAR / DSISR */
-        switch (excp_model) {
-        case POWERPC_EXCP_40x:
-            regs.sprn_srr0 = SPR_40x_SRR2;
-            regs.sprn_srr1 = SPR_40x_SRR3;
-            break;
-        case POWERPC_EXCP_BOOKE:
-            /* FIXME: choose one or the other based on CPU type */
-            regs.sprn_srr0 = SPR_BOOKE_MCSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_MCSRR1;
-            regs.sprn_asrr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_asrr1 = SPR_BOOKE_CSRR1;
-            break;
-        default:
-            break;
-        }
-        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]);
-        break;
-    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
-        LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
-                 "\n", regs.msr, regs.nip);
-        regs.msr |= env->error_code;
-        break;
-    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
-    {
-        bool lpes0;
-
-        cs = CPU(cpu);
-
-        /*
-         * Exception targeting modifiers
-         *
-         * LPES0 is supported on POWER7/8/9
-         * LPES1 is not supported (old iSeries mode)
-         *
-         * On anything else, we behave as if LPES0 is 1
-         * (externals don't alter MSR:HV)
-         */
-#if defined(TARGET_PPC64)
-        if (excp_model == POWERPC_EXCP_POWER7 ||
-            excp_model == POWERPC_EXCP_POWER8 ||
-            excp_model == POWERPC_EXCP_POWER9 ||
-            excp_model == POWERPC_EXCP_POWER10) {
-            lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
-        } else
-#endif /* defined(TARGET_PPC64) */
-        {
-            lpes0 = true;
-        }
-
-        if (!lpes0) {
-            regs.new_msr |= (target_ulong)MSR_HVB;
-            regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-            regs.sprn_srr0 = SPR_HSRR0;
-            regs.sprn_srr1 = SPR_HSRR1;
-        }
-        if (env->mpic_proxy) {
-            /* IACK the IRQ on delivery */
-            env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
-        }
-        break;
+    intr = &env->entry_points[excp];
+    if (!intr->setup_regs) {
+        cpu_abort(cs, "Raised an exception without defined vector %d\n",
+                  excp);
     }
-    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
-        /* Get rS/rD and rA from faulting opcode */
-        /*
-         * 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:
-            if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
-                LOG_EXCP("Ignore floating point exception\n");
-                cs->exception_index = POWERPC_EXCP_NONE;
-                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.
-             */
-            regs.msr |= 0x00100000;
-            env->spr[SPR_BOOKE_ESR] = ESR_FP;
-            break;
-        case POWERPC_EXCP_INVAL:
-            LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", regs.nip);
-            regs.msr |= 0x00080000;
-            env->spr[SPR_BOOKE_ESR] = ESR_PIL;
-            break;
-        case POWERPC_EXCP_PRIV:
-            regs.msr |= 0x00040000;
-            env->spr[SPR_BOOKE_ESR] = ESR_PPR;
-            break;
-        case POWERPC_EXCP_TRAP:
-            regs.msr |= 0x00020000;
-            env->spr[SPR_BOOKE_ESR] = ESR_PTR;
-            break;
-        default:
-            /* Should never occur */
-            cpu_abort(cs, "Invalid program exception %d. Aborting\n",
-                      env->error_code);
-            break;
-        }
-        break;
-    case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
-        lev = env->error_code;
-
-        if ((lev == 1) && cpu->vhyp) {
-            dump_hcall(env);
-        } else {
-            dump_syscall(env);
-        }
+    regs.new_nip = intr->addr | env->excp_prefix;
+    intr->setup_regs(cpu, intr, excp_model, &regs, &ignore);
 
+    if (ignore) {
         /*
-         * We need to correct the NIP which in this case is supposed
-         * to point to the next instruction. We also set env->nip here
-         * because the modification needs to be accessible by the
-         * virtual hypervisor code below.
+         * The interrupt was ignored or delivered by other means
+         * (e.g. vhyp).
          */
-        regs.nip += 4;
-        env->nip = regs.nip;
-
-        /* "PAPR mode" built-in hypercall emulation */
-        if ((lev == 1) && cpu->vhyp) {
-            PPCVirtualHypervisorClass *vhc =
-                PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
-            vhc->hypercall(cpu->vhyp, cpu);
-            return;
-        }
-
-        if (lev == 1) {
-            regs.new_msr |= (target_ulong)MSR_HVB;
-        }
-        break;
-    case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
-        lev = env->error_code;
-        dump_syscall(env);
-        regs.nip += 4;
-        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
-        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        break;
-    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
-    case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
-    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
-        break;
-    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
-        /* FIT on 4xx */
-        LOG_EXCP("FIT exception\n");
-        break;
-    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
-        LOG_EXCP("WDT exception\n");
-        switch (excp_model) {
-        case POWERPC_EXCP_BOOKE:
-            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
-            break;
-        default:
-            break;
-        }
-        break;
-    case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
-    case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
-        break;
-    case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
-        if (env->flags & POWERPC_FLAG_DE) {
-            /* FIXME: choose one or the other based on CPU type */
-            regs.sprn_srr0 = SPR_BOOKE_DSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_DSRR1;
-            regs.sprn_asrr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_asrr1 = SPR_BOOKE_CSRR1;
-            /* DBSR already modified by caller */
-        } else {
-            cpu_abort(cs, "Debug exception triggered on unsupported model\n");
-        }
-        break;
-    case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
-        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-        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;
-        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;
-        break;
-    case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "Performance counter exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
-        break;
-    case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
-        regs.sprn_srr0 = SPR_BOOKE_CSRR0;
-        regs.sprn_srr1 = SPR_BOOKE_CSRR1;
-        break;
-    case POWERPC_EXCP_RESET:     /* System reset exception                   */
-        /* A power-saving exception sets ME, otherwise it is unchanged */
-        if (msr_pow) {
-            /* indicate that we resumed from power save mode */
-            regs.msr |= 0x10000;
-            regs.new_msr |= ((target_ulong)1 << MSR_ME);
-        }
-        if (env->msr_mask & MSR_HVB) {
-            /*
-             * ISA specifies HV, but can be delivered to guest with HV
-             * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
-             */
-            regs.new_msr |= (target_ulong)MSR_HVB;
-        } else {
-            if (msr_pow) {
-                cpu_abort(cs, "Trying to deliver power-saving system reset "
-                          "exception %d with no HV support\n", excp);
-            }
-        }
-        break;
-    case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
-    case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
-    case POWERPC_EXCP_TRACE:     /* Trace exception                          */
-        break;
-    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
-        regs.msr |= env->error_code;
-        /* fall through */
-    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
-    case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
-    case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
-    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
-    case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
-    case POWERPC_EXCP_HV_EMU:
-    case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
-        regs.sprn_srr0 = SPR_HSRR0;
-        regs.sprn_srr1 = SPR_HSRR1;
-        regs.new_msr |= (target_ulong)MSR_HVB;
-        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        break;
-    case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
-    case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
-    case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
-#ifdef TARGET_PPC64
-        env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
-#endif
-        break;
-    case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
-#ifdef TARGET_PPC64
-        env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
-        regs.sprn_srr0 = SPR_HSRR0;
-        regs.sprn_srr1 = SPR_HSRR1;
-        regs.new_msr |= (target_ulong)MSR_HVB;
-        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-#endif
-        break;
-    case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
-        LOG_EXCP("PIT exception\n");
-        break;
-    case POWERPC_EXCP_IO:        /* IO error exception                       */
-        /* XXX: TODO */
-        cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
-        /* XXX: TODO */
-        cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
-        /* XXX: TODO */
-        cpu_abort(cs, "602 emulation trap exception "
-                  "is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
-    case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
-    case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
-        switch (excp_model) {
-        case POWERPC_EXCP_602:
-        case POWERPC_EXCP_603:
-        case POWERPC_EXCP_603E:
-        case POWERPC_EXCP_G2:
-            /* Swap temporary saved registers with GPRs */
-            if (!(regs.new_msr & ((target_ulong)1 << MSR_TGPR))) {
-                regs.new_msr |= (target_ulong)1 << MSR_TGPR;
-                hreg_swap_gpr_tgpr(env);
-            }
-            /* fall through */
-        case POWERPC_EXCP_7x5:
-#if defined(DEBUG_SOFTWARE_TLB)
-            if (qemu_log_enabled()) {
-                const char *es;
-                target_ulong *miss, *cmp;
-                int en;
-
-                if (excp == POWERPC_EXCP_IFTLB) {
-                    es = "I";
-                    en = 'I';
-                    miss = &env->spr[SPR_IMISS];
-                    cmp = &env->spr[SPR_ICMP];
-                } else {
-                    if (excp == POWERPC_EXCP_DLTLB) {
-                        es = "DL";
-                    } else {
-                        es = "DS";
-                    }
-                    en = 'D';
-                    miss = &env->spr[SPR_DMISS];
-                    cmp = &env->spr[SPR_DCMP];
-                }
-                qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
-                         TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
-                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
-                         env->spr[SPR_HASH1], env->spr[SPR_HASH2],
-                         env->error_code);
-            }
-#endif
-            regs.msr |= env->crf[0] << 28;
-            regs.msr |= env->error_code; /* key, D/I, S/L bits */
-            /* Set way using a LRU mechanism */
-            regs.msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
-            break;
-        case POWERPC_EXCP_74xx:
-#if defined(DEBUG_SOFTWARE_TLB)
-            if (qemu_log_enabled()) {
-                const char *es;
-                target_ulong *miss, *cmp;
-                int en;
-
-                if (excp == POWERPC_EXCP_IFTLB) {
-                    es = "I";
-                    en = 'I';
-                    miss = &env->spr[SPR_TLBMISS];
-                    cmp = &env->spr[SPR_PTEHI];
-                } else {
-                    if (excp == POWERPC_EXCP_DLTLB) {
-                        es = "DL";
-                    } else {
-                        es = "DS";
-                    }
-                    en = 'D';
-                    miss = &env->spr[SPR_TLBMISS];
-                    cmp = &env->spr[SPR_PTEHI];
-                }
-                qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
-                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
-                         env->error_code);
-            }
-#endif
-            regs.msr |= env->error_code; /* key bit */
-            break;
-        default:
-            cpu_abort(cs, "Invalid TLB miss exception\n");
-            break;
-        }
-        break;
-    case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
-        /* XXX: TODO */
-        cpu_abort(cs, "Floating point assist exception "
-                  "is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
-        /* XXX: TODO */
-        cpu_abort(cs, "DABR exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
-        /* XXX: TODO */
-        cpu_abort(cs, "IABR exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_SMI:       /* System management interrupt              */
-        /* XXX: TODO */
-        cpu_abort(cs, "SMI exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
-        /* XXX: TODO */
-        cpu_abort(cs, "Thermal management exception "
-                  "is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "Performance counter exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
-        /* XXX: TODO */
-        cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "970 soft-patch exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "970 maintenance exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
-        /* XXX: TODO */
-        cpu_abort(cs, "Maskable external exception "
-                  "is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
-        /* XXX: TODO */
-        cpu_abort(cs, "Non maskable external exception "
-                  "is not implemented yet !\n");
-        break;
-    default:
-    excp_invalid:
-        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
-        break;
+        return;
     }
 
     /* Sanity check */
@@ -892,14 +409,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     }
 #endif
 
-    regs.new_nip = env->excp_vectors[excp];
-    if (regs.new_nip == (target_ulong)-1ULL) {
-        cpu_abort(cs, "Raised an exception without defined vector %d\n",
-                  excp);
-    }
-
-    regs.new_nip |= env->excp_prefix;
-
     /* If any alternate SRR register are defined, duplicate saved values */
     if (regs.sprn_asrr0 != -1) {
         env->spr[regs.sprn_asrr0] = regs.nip;
@@ -925,24 +434,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     }
 #endif
 
-    if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
+    if (intr->id != POWERPC_EXCP_SYSCALL_VECTORED) {
         /* Save PC */
         env->spr[regs.sprn_srr0] = regs.nip;
 
         /* Save MSR */
         env->spr[regs.sprn_srr1] = regs.msr;
-
-#if defined(TARGET_PPC64)
-    } else {
-        regs.new_nip += lev * 0x20;
-
-        env->lr = regs.nip;
-        env->ctr = regs.msr;
-#endif
     }
 
     /* This can update regs.new_msr and regs.new_nip if AIL applies */
-    ppc_excp_apply_ail(cpu, excp_model, excp, regs.msr, &regs.new_msr,
+    ppc_excp_apply_ail(cpu, excp_model, intr->id, regs.msr, &regs.new_msr,
                        &regs.new_nip);
 
     powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
new file mode 100644
index 0000000000..31faea84c5
--- /dev/null
+++ b/target/ppc/interrupts.c
@@ -0,0 +1,638 @@
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "ppc_intr.h"
+
+/* for hreg_swap_gpr_tgpr */
+#include "helper_regs.h"
+
+/* #define DEBUG_SOFTWARE_TLB */
+/* #define DEBUG_EXCEPTIONS */
+
+#ifdef DEBUG_EXCEPTIONS
+#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_EXCP(...) do { } while (0)
+#endif
+
+void __ppc_intr_add(CPUPPCState *env, target_ulong addr, int id,
+                   const char *intr_name)
+{
+    PPCInterrupt *intr = &env->entry_points[id];
+
+    object_initialize(intr, sizeof(*intr), intr_name);
+    intr->addr = addr;
+}
+
+static const TypeInfo ppc_interrupt_info = {
+    .name = TYPE_PPC_INTERRUPT,
+    .parent = TYPE_OBJECT,
+    .abstract = true,
+};
+
+static void ppc_interrupt_register_types(void)
+{
+    type_register_static(&ppc_interrupt_info);
+}
+type_init(ppc_interrupt_register_types);
+
+
+
+static void ppc_intr_def_log(PowerPCCPU *cpu, PPCInterrupt *intr,
+                             int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    LOG_EXCP("%s interrupt\n", intr->name);
+}
+
+static void ppc_intr_def_not_impl(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+
+    cpu_abort(cs, "%s interrupt not implemented yet.\n", intr->name);
+}
+
+static void ppc_intr_def_no_op(PowerPCCPU *cpu, PPCInterrupt *intr,
+                               int excp_model, ppc_intr_args *regs,
+                               bool *ignore)
+{
+}
+
+/* Default implementation for interrupts that set the MSR_HV bit */
+static void ppc_intr_def_hv(PowerPCCPU *cpu, PPCInterrupt *intr, int excp_model,
+                            ppc_intr_args *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    regs->sprn_srr0 = SPR_HSRR0;
+    regs->sprn_srr1 = SPR_HSRR1;
+    regs->new_msr |= (target_ulong)MSR_HVB;
+    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+/* Default implementation for Facility Unavailable interrupts */
+static void ppc_intr_def_fac_unavail_64(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                        int excp_model, ppc_intr_args *regs,
+                                        bool *ignore)
+{
+#ifdef TARGET_PPC64
+    CPUPPCState *env = &cpu->env;
+    env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
+#endif
+}
+
+static void ppc_debug_software_tlb(CPUPPCState *env, int excp, int excp_model,
+                                   int imiss_sprn, int icmp_sprn,
+                                   int dmiss_sprn, int dcmp_sprn)
+{
+#if defined(DEBUG_SOFTWARE_TLB)
+    if (qemu_log_enabled()) {
+        const char *es;
+        target_ulong *miss, *cmp;
+        int en;
+
+        if (excp == POWERPC_EXCP_IFTLB) {
+            es = "I";
+            en = 'I';
+            miss = &env->spr[imiss_sprn];
+            cmp = &env->spr[icmp_sprn];
+        } else {
+            if (excp == POWERPC_EXCP_DLTLB) {
+                es = "DL";
+            } else {
+                es = "DS";
+            }
+            en = 'D';
+            miss = &env->spr[dmiss_sprn];
+            cmp = &env->spr[dcmp_srpn];
+        }
+
+        if (excp_model == POWERPC_EXCP_74xx) {
+            qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+                     TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+                     env->error_code);
+        } else {
+            qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+                     TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
+                     TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+                     env->spr[SPR_HASH1], env->spr[SPR_HASH2],
+                     env->error_code);
+        }
+    }
+#endif
+}
+
+static void ppc_intr_def_tlb_miss(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    switch (excp_model) {
+    case POWERPC_EXCP_602:
+    case POWERPC_EXCP_603:
+    case POWERPC_EXCP_603E:
+    case POWERPC_EXCP_G2:
+        /* Swap temporary saved registers with GPRs */
+        if (!(regs->new_msr & ((target_ulong)1 << MSR_TGPR))) {
+            regs->new_msr |= (target_ulong)1 << MSR_TGPR;
+            hreg_swap_gpr_tgpr(env);
+        }
+
+        ppc_debug_software_tlb(env, intr->id, excp_model,
+                               SPR_IMISS, SPR_ICMP,
+                               SPR_DMISS, SPR_DCMP);
+
+        /* fall through */
+    case POWERPC_EXCP_7x5:
+        regs->msr |= env->crf[0] << 28;
+        regs->msr |= env->error_code; /* key, D/I, S/L bits */
+
+        /* Set way using a LRU mechanism */
+        regs->msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+
+        break;
+    case POWERPC_EXCP_74xx:
+        ppc_debug_software_tlb(env, intr->id, excp_model,
+                               SPR_TLBMISS, SPR_PTEHI,
+                               SPR_TLBMISS, SPR_PTEHI);
+
+        regs->msr |= env->error_code; /* key bit */
+        break;
+    default:
+        cpu_abort(cs, "Invalid instruction TLB miss exception\n");
+        break;
+    }
+}
+
+static void ppc_intr_critical(PowerPCCPU *cpu, PPCInterrupt *intr,
+                              int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+
+    switch (excp_model) {
+    case POWERPC_EXCP_40x:
+        regs->sprn_srr0 = SPR_40x_SRR2;
+        regs->sprn_srr1 = SPR_40x_SRR3;
+        break;
+    case POWERPC_EXCP_BOOKE:
+        regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+        break;
+    case POWERPC_EXCP_G2:
+        break;
+    default:
+        cpu_abort(cs, "Invalid Critical interrupt for model %d. Aborting\n",
+                  excp_model);
+        break;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_CRITICAL, critical, "Critical input");
+
+static void ppc_intr_machine_check(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                   int excp_model, ppc_intr_args *regs,
+                                   bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    if (msr_me == 0) {
+        /*
+         * Machine check exception is not enabled.  Enter
+         * checkstop state.
+         */
+        fprintf(stderr, "Machine check while not allowed. "
+                "Entering checkstop state\n");
+        if (qemu_log_separate()) {
+            qemu_log("Machine check while not allowed. "
+                     "Entering checkstop state\n");
+        }
+        cs->halted = 1;
+        cpu_interrupt_exittb(cs);
+    }
+    if (env->msr_mask & MSR_HVB) {
+        /*
+         * ISA specifies HV, but can be delivered to guest with HV
+         * clear (e.g., see FWNMI in PAPR).
+         */
+        regs->new_msr |= (target_ulong)MSR_HVB;
+    }
+
+    /* machine check exceptions don't have ME set */
+    regs->new_msr &= ~((target_ulong)1 << MSR_ME);
+
+    /* XXX: should also have something loaded in DAR / DSISR */
+    switch (excp_model) {
+    case POWERPC_EXCP_40x:
+        regs->sprn_srr0 = SPR_40x_SRR2;
+        regs->sprn_srr1 = SPR_40x_SRR3;
+        break;
+    case POWERPC_EXCP_BOOKE:
+        /* FIXME: choose one or the other based on CPU type */
+        regs->sprn_srr0 = SPR_BOOKE_MCSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_MCSRR1;
+        regs->sprn_asrr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_asrr1 = SPR_BOOKE_CSRR1;
+        break;
+    default:
+        break;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_MCHECK, machine_check, "Machine check");
+
+static void ppc_intr_data_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
+             "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_DSI, data_storage, "Data storage");
+
+static void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
+             "\n", regs->msr, regs->nip);
+    regs->msr |= env->error_code;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_ISI, insn_storage, "Instruction storage");
+
+static void ppc_intr_external(PowerPCCPU *cpu, PPCInterrupt *intr,
+                              int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    bool lpes0;
+
+    /*
+     * Exception targeting modifiers
+     *
+     * LPES0 is supported on POWER7/8/9
+     * LPES1 is not supported (old iSeries mode)
+     *
+     * On anything else, we behave as if LPES0 is 1
+     * (externals don't alter MSR:HV)
+     */
+#if defined(TARGET_PPC64)
+    if (excp_model == POWERPC_EXCP_POWER7 ||
+        excp_model == POWERPC_EXCP_POWER8 ||
+        excp_model == POWERPC_EXCP_POWER9 ||
+        excp_model == POWERPC_EXCP_POWER10) {
+        lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+    } else
+#endif /* defined(TARGET_PPC64) */
+    {
+        lpes0 = true;
+    }
+
+    if (!lpes0) {
+        regs->new_msr |= (target_ulong)MSR_HVB;
+        regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        regs->sprn_srr0 = SPR_HSRR0;
+        regs->sprn_srr1 = SPR_HSRR1;
+    }
+    if (env->mpic_proxy) {
+        /* IACK the IRQ on delivery */
+        env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_EXTERNAL, external, "External");
+
+static void ppc_intr_alignment(PowerPCCPU *cpu, PPCInterrupt *intr,
+                               int excp_model, ppc_intr_args *regs,
+                               bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    /* Get rS/rD and rA from faulting opcode */
+    /*
+     * 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;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_ALIGN, alignment, "Alignment");
+
+static void ppc_intr_program(PowerPCCPU *cpu, PPCInterrupt *intr,
+                             int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    switch (env->error_code & ~0xF) {
+    case POWERPC_EXCP_FP:
+        if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+            LOG_EXCP("Ignore floating point exception\n");
+            cs->exception_index = POWERPC_EXCP_NONE;
+            env->error_code = 0;
+
+            *ignore = true;
+            return;
+        }
+
+        /*
+         * FP exceptions always have NIP pointing to the faulting
+         * instruction, so always use store_next and claim we are
+         * precise in the MSR.
+         */
+        regs->msr |= 0x00100000;
+        env->spr[SPR_BOOKE_ESR] = ESR_FP;
+        break;
+    case POWERPC_EXCP_INVAL:
+        LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", regs->nip);
+        regs->msr |= 0x00080000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PIL;
+        break;
+    case POWERPC_EXCP_PRIV:
+        regs->msr |= 0x00040000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PPR;
+        break;
+    case POWERPC_EXCP_TRAP:
+        regs->msr |= 0x00020000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PTR;
+        break;
+    default:
+        /* Should never occur */
+        cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+                  env->error_code);
+        break;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_PROGRAM, program, "Program");
+
+
+static inline void dump_syscall(CPUPPCState *env)
+{
+    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
+                  " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
+                  " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
+                  " nip=" TARGET_FMT_lx "\n",
+                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
+                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
+                  ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
+                  ppc_dump_gpr(env, 8), env->nip);
+}
+
+static inline void dump_hcall(CPUPPCState *env)
+{
+    qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
+                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
+                  " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
+                  " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
+                  " nip=" TARGET_FMT_lx "\n",
+                  ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
+                  ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
+                  ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
+                  ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
+                  ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
+                  env->nip);
+}
+
+
+static void ppc_intr_system_call(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                 int excp_model, ppc_intr_args *regs,
+                                 bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int lev;
+
+    lev = env->error_code;
+
+    if ((lev == 1) && cpu->vhyp) {
+        dump_hcall(env);
+    } else {
+        dump_syscall(env);
+    }
+
+    /*
+     * We need to correct the NIP which in this case is supposed
+     * to point to the next instruction. We also set env->nip here
+     * because the modification needs to be accessible by the
+     * virtual hypervisor code below.
+     */
+    regs->nip += 4;
+    env->nip = regs->nip;
+
+    /* "PAPR mode" built-in hypercall emulation */
+    if ((lev == 1) && cpu->vhyp) {
+        PPCVirtualHypervisorClass *vhc =
+            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+        vhc->hypercall(cpu->vhyp, cpu);
+
+        *ignore = true;
+        return;
+    }
+
+    if (lev == 1) {
+        regs->new_msr |= (target_ulong)MSR_HVB;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_SYSCALL, system_call, "System call");
+
+static void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                          int excp_model, ppc_intr_args *regs,
+                                          bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int lev;
+
+    lev = env->error_code;
+    dump_syscall(env);
+
+    regs->nip += 4;
+    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
+    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+    regs->new_nip += lev * 0x20;
+
+    env->lr = regs->nip;
+    env->ctr = regs->msr;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_SYSCALL_VECTORED, system_call_vectored,
+                     "System call vectored");
+
+static void ppc_intr_watchdog(PowerPCCPU *cpu, PPCInterrupt *intr,
+                              int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    LOG_EXCP("WDT exception\n");
+    switch (excp_model) {
+    case POWERPC_EXCP_BOOKE:
+        regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+        break;
+    default:
+        break;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_WDT, watchdog, "Watchdog timer");
+
+static void ppc_intr_debug(PowerPCCPU *cpu, PPCInterrupt *intr, int excp_model,
+                           ppc_intr_args *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    if (env->flags & POWERPC_FLAG_DE) {
+        /* FIXME: choose one or the other based on CPU type */
+        regs->sprn_srr0 = SPR_BOOKE_DSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_DSRR1;
+        regs->sprn_asrr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_asrr1 = SPR_BOOKE_CSRR1;
+        /* DBSR already modified by caller */
+    } else {
+        cpu_abort(cs, "Debug exception triggered on unsupported model\n");
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_DEBUG, debug, "Debug");
+
+static void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                     int excp_model, ppc_intr_args *regs,
+                                     bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_SPEU, spe_unavailable,
+                     "SPE/embedded floating-point unavailable");
+
+static void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                      int excp_model, ppc_intr_args *regs,
+                                      bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    ppc_intr_def_not_impl(cpu, intr, excp_model, regs, ignore);
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_EFPDI, embedded_fp_data,
+                     "Embedded floating-point data");
+
+static void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                       int excp_model, ppc_intr_args *regs,
+                                       bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    ppc_intr_def_not_impl(cpu, intr, excp_model, regs, ignore);
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_EFPRI, embedded_fp_round,
+                     "Embedded floating-point round");
+
+static void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                            int excp_model, ppc_intr_args *regs,
+                                            bool *ignore)
+{
+    regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+    regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_DOORCI, embedded_doorbell_crit,
+                     "Embedded doorbell critical");
+
+static void ppc_intr_system_reset(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    /* A power-saving exception sets ME, otherwise it is unchanged */
+    if (msr_pow) {
+        /* indicate that we resumed from power save mode */
+        regs->msr |= 0x10000;
+        regs->new_msr |= ((target_ulong)1 << MSR_ME);
+    }
+    if (env->msr_mask & MSR_HVB) {
+        /*
+         * ISA specifies HV, but can be delivered to guest with HV
+         * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
+         */
+        regs->new_msr |= (target_ulong)MSR_HVB;
+    } else {
+        if (msr_pow) {
+            cpu_abort(cs, "Trying to deliver power-saving system reset "
+                      "exception with no HV support\n");
+        }
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");
+
+static void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                     int excp_model, ppc_intr_args *regs,
+                                     bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    regs->msr |= env->error_code;
+    ppc_intr_def_hv(cpu, intr, excp_model, regs, ignore);
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_HISI, hv_insn_storage,
+                     "Hypervisor instruction storage");
+
+static void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                         int excp_model, ppc_intr_args *regs,
+                                         bool *ignore)
+{
+#ifdef TARGET_PPC64
+    ppc_intr_def_fac_unavail_64(cpu, intr, excp_model, regs, ignore);
+    ppc_intr_def_hv(cpu, intr, excp_model, regs, ignore);
+#endif
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_HV_FU, hv_facility_unavail,
+                "Hypervisor facility unavailable");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_HDECR,    def_hv, "Hypervisor decrementer");
+PPC_DEFINE_INTR(POWERPC_EXCP_HDSI,     def_hv, "Hypervisor data storage");
+PPC_DEFINE_INTR(POWERPC_EXCP_HDSEG,    def_hv, "Hypervisor data segment");
+PPC_DEFINE_INTR(POWERPC_EXCP_HISEG,    def_hv, "Hypervisor insn segment");
+PPC_DEFINE_INTR(POWERPC_EXCP_SDOOR_HV, def_hv, "Hypervisor doorbell");
+PPC_DEFINE_INTR(POWERPC_EXCP_HV_EMU,   def_hv, "Hypervisor emulation assist");
+PPC_DEFINE_INTR(POWERPC_EXCP_HVIRT,    def_hv, "Hypervisor virtualization");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_VPU,  def_fac_unavail_64, "Vector unavailable");
+PPC_DEFINE_INTR(POWERPC_EXCP_VSXU, def_fac_unavail_64, "VSX unavailable");
+PPC_DEFINE_INTR(POWERPC_EXCP_FU,   def_fac_unavail_64, "Facility unavailable");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_IFTLB, def_tlb_miss, "Insn fetch TLB error");
+PPC_DEFINE_INTR(POWERPC_EXCP_DLTLB, def_tlb_miss, "Data load TLB error");
+PPC_DEFINE_INTR(POWERPC_EXCP_DSTLB, def_tlb_miss, "Data store TLB error");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_FIT, def_log, "Fixed-interval timer");
+PPC_DEFINE_INTR(POWERPC_EXCP_PIT, def_log, "Programmable interval timer");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_FPU,   def_no_op, "Floating-point unavailable");
+PPC_DEFINE_INTR(POWERPC_EXCP_APU,   def_no_op, "Aux. processor unavailable");
+PPC_DEFINE_INTR(POWERPC_EXCP_DECR,  def_no_op, "Decrementer");
+PPC_DEFINE_INTR(POWERPC_EXCP_DTLB,  def_no_op, "Data TLB error");
+PPC_DEFINE_INTR(POWERPC_EXCP_ITLB,  def_no_op, "Instruction TLB error");
+PPC_DEFINE_INTR(POWERPC_EXCP_DOORI, def_no_op, "Embedded doorbell");
+PPC_DEFINE_INTR(POWERPC_EXCP_DSEG,  def_no_op, "Data segment");
+PPC_DEFINE_INTR(POWERPC_EXCP_ISEG,  def_no_op, "Instruction segment");
+PPC_DEFINE_INTR(POWERPC_EXCP_TRACE, def_no_op, "Trace");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_EPERFM,  def_not_impl, "Embedded perf. monitor");
+PPC_DEFINE_INTR(POWERPC_EXCP_IO,      def_not_impl, "IO error");
+PPC_DEFINE_INTR(POWERPC_EXCP_RUNM,    def_not_impl, "Run mode");
+PPC_DEFINE_INTR(POWERPC_EXCP_EMUL,    def_not_impl, "Emulation trap");
+PPC_DEFINE_INTR(POWERPC_EXCP_FPA,     def_not_impl, "Floating-point assist");
+PPC_DEFINE_INTR(POWERPC_EXCP_DABR,    def_not_impl, "Data address breakpoint");
+PPC_DEFINE_INTR(POWERPC_EXCP_IABR,    def_not_impl, "Insn address breakpoint");
+PPC_DEFINE_INTR(POWERPC_EXCP_SMI,     def_not_impl, "System management");
+PPC_DEFINE_INTR(POWERPC_EXCP_THERM,   def_not_impl, "Thermal management");
+PPC_DEFINE_INTR(POWERPC_EXCP_PERFM,   def_not_impl, "Performance counter");
+PPC_DEFINE_INTR(POWERPC_EXCP_VPUA,    def_not_impl, "Vector assist");
+PPC_DEFINE_INTR(POWERPC_EXCP_SOFTP,   def_not_impl, "Soft patch");
+PPC_DEFINE_INTR(POWERPC_EXCP_MAINT,   def_not_impl, "Maintenance");
+PPC_DEFINE_INTR(POWERPC_EXCP_MEXTBR,  def_not_impl, "Maskable external");
+PPC_DEFINE_INTR(POWERPC_EXCP_NMEXTBR, def_not_impl, "Non-maskable external");
+
+/* These are used by P7 and P8 but were never implemented */
+PPC_DEFINE_INTR(POWERPC_EXCP_SDOOR, def_not_impl, "Server doorbell");
+PPC_DEFINE_INTR(POWERPC_EXCP_HV_MAINT, def_not_impl, "Hypervisor maintenance");
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 93972df58e..3927359c7b 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -115,7 +115,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
     qemu_get_be32s(f, &env->pending_interrupts);
     qemu_get_be32s(f, &env->irq_input_state);
     for (i = 0; i < POWERPC_EXCP_NB; i++) {
-        qemu_get_betls(f, &env->excp_vectors[i]);
+        qemu_get_betls(f, &env->entry_points[i].addr);
     }
     qemu_get_betls(f, &env->excp_prefix);
     qemu_get_betls(f, &env->ivor_mask);
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index a6a53a8d5c..740eac25f7 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -30,6 +30,7 @@ ppc_softmmu_ss.add(files(
   'mmu-hash32.c',
   'mmu_helper.c',
   'monitor.c',
+  'interrupts.c',
 ))
 ppc_softmmu_ss.add(when: 'CONFIG_TCG', if_false: files(
   'tcg-stub.c'
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
new file mode 100644
index 0000000000..e588736c6d
--- /dev/null
+++ b/target/ppc/ppc_intr.h
@@ -0,0 +1,55 @@
+#ifndef PPC_INTR_H
+#define PPC_INTR_H
+
+#include "qom/object.h"
+#include "cpu-qom.h"
+
+#define TYPE_PPC_INTERRUPT "ppc-interrupt"
+OBJECT_DECLARE_SIMPLE_TYPE(PPCInterrupt, PPC_INTERRUPT)
+
+void __ppc_intr_add(CPUPPCState *env, target_ulong addr, int id,
+                    const char *intr_name);
+
+#define ppc_intr_add(_env, _addr, _id)                  \
+    do {                                                \
+        QEMU_BUILD_BUG_ON(_id <= POWERPC_EXCP_NONE);    \
+        QEMU_BUILD_BUG_ON(_id >= POWERPC_EXCP_NB);      \
+        __ppc_intr_add(_env, _addr, _id, #_id);         \
+    } while (0)                                         \
+
+/*
+ * Registers an interrupt callback as a class. This makes it so that
+ * the interrupt callback implementation is stored on QOM and we can
+ * instantiate only the ones needed for a specific processor later.
+ *
+ * @_id: The interrupt id as in the POWERPC_EXCP_* enum. This will be
+ *   the QOM hash table key for the type.
+ * @_sym: The interrupt name as a valid C identifier. This will be
+ *   used to compose the symbol name for the callback to be invoked
+ *   for this interrupt.
+ * @_name: The interrupt name as a string for display.
+ */
+#define PPC_DEFINE_INTR(_id, _sym, _name)       \
+                                                \
+    static void __##_id##_init(Object *obj)     \
+    {                                           \
+        PPCInterrupt *pi = PPC_INTERRUPT(obj);  \
+                                                \
+        pi->id = _id;                           \
+        pi->name = _name;                       \
+        pi->setup_regs = ppc_intr_##_sym;       \
+    }                                           \
+                                                \
+    static const TypeInfo __##_id##_info = {    \
+        .parent = TYPE_PPC_INTERRUPT,           \
+        .name = #_id,                           \
+        .instance_init = __##_id##_init,        \
+    };                                          \
+                                                \
+    static void __##_id##_register_types(void)  \
+    {                                           \
+        type_register_static(&__##_id##_info);  \
+    }                                           \
+    type_init(__##_id##_register_types);        \
+
+#endif /* PPC_INTR_H */
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index e16a2721e2..2c82bda8cc 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -951,7 +951,8 @@ void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn)
     TCGv t0 = tcg_temp_new();
     tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask));
     tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
-    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs]));
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, entry_points[sprn_offs]) +
+                  offsetof(PPCInterrupt, addr));
     gen_store_spr(sprn, t0);
     tcg_temp_free(t0);
 }
