All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] target/ppc: powerpc_excp improvements - part I
@ 2021-06-01 21:46 Fabiano Rosas
  2021-06-01 21:46 ` [RFC PATCH 1/5] target/ppc: powerpc_excp: Move lpes code to where it is used Fabiano Rosas
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Fabiano Rosas @ 2021-06-01 21:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-ppc, groug, david

This is my attempt at reducing the size of powerpc_excp and cleaning
it up a bit. It has two parts:

part I (this series) tackles the big switch statement that runs the
interrupt emulation code. Each interrupt now gets its own callback
function that is kept within QOM. The per-processor code still
registers the interrupts in a similar manner to what is done today and
powerpc_excp replaces its switch statement for a function call.

part II (still WIP: https://github.com/farosas/qemu/commits/powerpc_excp)
tries to make powerpc_excp processor agnostic by removing the excp_model
checks and moving processor-specific interrupt properties to
per-processor QOM classes.

I think it would be nice if we could at the end have separate
interrupts and interrupt model implementations. That way we could
start moving things into well defined per-processor files, CONFIGs,
etc.

(So far tested on x86 emulating P9 and compile-only 32-bit and
linux-user. I still need to gather some command lines for the older
cpus.)

Based-on: eb22196316ee653178ae517de83b490ad3636b91 # ppc-for-6.1

Fabiano Rosas (5):
  target/ppc: powerpc_excp: Move lpes code to where it is used
  target/ppc: powerpc_excp: Remove dump_syscall_vectored
  target/ppc: powerpc_excp: Consolidade TLB miss code
  target/ppc: powerpc_excp: Standardize arguments to interrupt code
  target/ppc: powerpc_excp: Move interrupt raising code to QOM

 target/ppc/cpu.h         |  29 +-
 target/ppc/cpu_init.c    | 640 +++++++++++++++++++------------------
 target/ppc/excp_helper.c | 670 +++++----------------------------------
 target/ppc/interrupts.c  | 638 +++++++++++++++++++++++++++++++++++++
 target/ppc/machine.c     |   2 +-
 target/ppc/meson.build   |   1 +
 target/ppc/ppc_intr.h    |  55 ++++
 target/ppc/translate.c   |   3 +-
 8 files changed, 1117 insertions(+), 921 deletions(-)
 create mode 100644 target/ppc/interrupts.c
 create mode 100644 target/ppc/ppc_intr.h

--
2.29.2


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC PATCH 1/5] target/ppc: powerpc_excp: Move lpes code to where it is used
  2021-06-01 21:46 [RFC PATCH 0/5] target/ppc: powerpc_excp improvements - part I Fabiano Rosas
@ 2021-06-01 21:46 ` Fabiano Rosas
  2021-06-02  7:37   ` David Gibson
  2021-06-01 21:46 ` [RFC PATCH 2/5] target/ppc: powerpc_excp: Remove dump_syscall_vectored Fabiano Rosas
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Fabiano Rosas @ 2021-06-01 21:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-ppc, groug, david

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/excp_helper.c | 47 +++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 04418054f5..5ea8503b46 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -333,7 +333,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     CPUPPCState *env = &cpu->env;
     target_ulong msr, new_msr, vector;
     int srr0, srr1, asrr0, asrr1, lev = -1;
-    bool lpes0;
 
     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
@@ -365,27 +364,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
     }
 
-    /*
-     * 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;
-    }
-
     /*
      * Hypervisor emulation assistance interrupt only exists on server
      * arch 2.05 server or later. We also don't want to generate it if
@@ -473,8 +451,32 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         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) {
             new_msr |= (target_ulong)MSR_HVB;
             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
@@ -486,6 +488,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
         }
         break;
+    }
     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
         /* Get rS/rD and rA from faulting opcode */
         /*
-- 
2.29.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 2/5] target/ppc: powerpc_excp: Remove dump_syscall_vectored
  2021-06-01 21:46 [RFC PATCH 0/5] target/ppc: powerpc_excp improvements - part I Fabiano Rosas
  2021-06-01 21:46 ` [RFC PATCH 1/5] target/ppc: powerpc_excp: Move lpes code to where it is used Fabiano Rosas
@ 2021-06-01 21:46 ` Fabiano Rosas
  2021-06-02  7:37   ` David Gibson
  2021-06-01 21:46 ` [RFC PATCH 3/5] target/ppc: powerpc_excp: Consolidade TLB miss code Fabiano Rosas
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Fabiano Rosas @ 2021-06-01 21:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-ppc, groug, david

This function is identical to dump_syscall, so use the latter for
system call vectored as well.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/excp_helper.c | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 5ea8503b46..9e3aae1c96 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -70,18 +70,6 @@ static inline void dump_syscall(CPUPPCState *env)
                   ppc_dump_gpr(env, 8), env->nip);
 }
 
-static inline void dump_syscall_vectored(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
@@ -564,7 +552,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         break;
     case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
         lev = env->error_code;
-        dump_syscall_vectored(env);
+        dump_syscall(env);
         env->nip += 4;
         new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-- 
2.29.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 3/5] target/ppc: powerpc_excp: Consolidade TLB miss code
  2021-06-01 21:46 [RFC PATCH 0/5] target/ppc: powerpc_excp improvements - part I Fabiano Rosas
  2021-06-01 21:46 ` [RFC PATCH 1/5] target/ppc: powerpc_excp: Move lpes code to where it is used Fabiano Rosas
  2021-06-01 21:46 ` [RFC PATCH 2/5] target/ppc: powerpc_excp: Remove dump_syscall_vectored Fabiano Rosas
@ 2021-06-01 21:46 ` Fabiano Rosas
  2021-06-02  7:37   ` David Gibson
  2021-06-01 21:46 ` [RFC PATCH 4/5] target/ppc: powerpc_excp: Standardize arguments to interrupt code Fabiano Rosas
  2021-06-01 21:46 ` [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM Fabiano Rosas
  4 siblings, 1 reply; 15+ messages in thread
From: Fabiano Rosas @ 2021-06-01 21:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-ppc, groug, david

The only difference in the code for Instruction fetch, Data load and
Data store TLB miss errors is that when called from an unsupported
processor (i.e. not one of 602, 603, 603e, G2, 7x5 or 74xx), they
abort with a message specific to the operation type (insn fetch, data
load/store).

If a processor does not support those interrupts we should not be
registering them in init_excp_<proc> to begin with, so that error
message would never be used.

I'm leaving the message in for completeness, but making it generic and
consolidating the three interrupts into the same case statement body.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/excp_helper.c | 37 ++-----------------------------------
 1 file changed, 2 insertions(+), 35 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 9e3aae1c96..fd147e2a37 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -689,52 +689,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
                   "is not implemented yet !\n");
         break;
     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
-        switch (excp_model) {
-        case POWERPC_EXCP_602:
-        case POWERPC_EXCP_603:
-        case POWERPC_EXCP_603E:
-        case POWERPC_EXCP_G2:
-            goto tlb_miss_tgpr;
-        case POWERPC_EXCP_7x5:
-            goto tlb_miss;
-        case POWERPC_EXCP_74xx:
-            goto tlb_miss_74xx;
-        default:
-            cpu_abort(cs, "Invalid instruction TLB miss exception\n");
-            break;
-        }
-        break;
     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
-        switch (excp_model) {
-        case POWERPC_EXCP_602:
-        case POWERPC_EXCP_603:
-        case POWERPC_EXCP_603E:
-        case POWERPC_EXCP_G2:
-            goto tlb_miss_tgpr;
-        case POWERPC_EXCP_7x5:
-            goto tlb_miss;
-        case POWERPC_EXCP_74xx:
-            goto tlb_miss_74xx;
-        default:
-            cpu_abort(cs, "Invalid data load TLB miss exception\n");
-            break;
-        }
-        break;
     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:
-        tlb_miss_tgpr:
             /* Swap temporary saved registers with GPRs */
             if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
                 new_msr |= (target_ulong)1 << MSR_TGPR;
                 hreg_swap_gpr_tgpr(env);
             }
-            goto tlb_miss;
+            /* fall through */
         case POWERPC_EXCP_7x5:
-        tlb_miss:
 #if defined(DEBUG_SOFTWARE_TLB)
             if (qemu_log_enabled()) {
                 const char *es;
@@ -769,7 +737,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
             break;
         case POWERPC_EXCP_74xx:
-        tlb_miss_74xx:
 #if defined(DEBUG_SOFTWARE_TLB)
             if (qemu_log_enabled()) {
                 const char *es;
@@ -799,7 +766,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             msr |= env->error_code; /* key bit */
             break;
         default:
-            cpu_abort(cs, "Invalid data store TLB miss exception\n");
+            cpu_abort(cs, "Invalid TLB miss exception\n");
             break;
         }
         break;
-- 
2.29.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 4/5] target/ppc: powerpc_excp: Standardize arguments to interrupt code
  2021-06-01 21:46 [RFC PATCH 0/5] target/ppc: powerpc_excp improvements - part I Fabiano Rosas
                   ` (2 preceding siblings ...)
  2021-06-01 21:46 ` [RFC PATCH 3/5] target/ppc: powerpc_excp: Consolidade TLB miss code Fabiano Rosas
@ 2021-06-01 21:46 ` Fabiano Rosas
  2021-06-07  3:55   ` David Gibson
  2021-06-01 21:46 ` [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM Fabiano Rosas
  4 siblings, 1 reply; 15+ messages in thread
From: Fabiano Rosas @ 2021-06-01 21:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-ppc, groug, david

The next patches will split the big switch statement in powerpc_excp
into individual functions so it would be cleaner if all variables are
already grouped in a structure and their names consistent.

This patch makes it so that the old values for MSR and NIP (from env)
are saved at the beginning as regs.msr and regs.nip and all
modifications are done over this regs version. At the end of the
function regs.msr and regs.nip are saved in the SRRs and regs.new_msr
and regs.new_nip are written to env.

There are two points of interest here:

- The system call code has a particularity where it needs to use
env->nip because it might return early and the modification needs to
be seen by the virtual hypervisor hypercall code. I have added a
comment making this clear.

- The MSR filter at the beginning is being applied to the old MSR value
only, i.e. the one that goes into SRR1. The new_msr is taken from
env->msr without filtering the reserved bits. This might be a bug in
the existing code. I'm also adding a comment to point that out.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/excp_helper.c | 231 +++++++++++++++++++++------------------
 1 file changed, 125 insertions(+), 106 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index fd147e2a37..12bf829c8f 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -186,7 +186,7 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
 static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
                                       target_ulong msr,
                                       target_ulong *new_msr,
-                                      target_ulong *vector)
+                                      target_ulong *new_nip)
 {
 #if defined(TARGET_PPC64)
     CPUPPCState *env = &cpu->env;
@@ -263,9 +263,9 @@ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
 
     if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
         if (ail == 2) {
-            *vector |= 0x0000000000018000ull;
+            *new_nip |= 0x0000000000018000ull;
         } else if (ail == 3) {
-            *vector |= 0xc000000000004000ull;
+            *new_nip |= 0xc000000000004000ull;
         }
     } else {
         /*
@@ -273,15 +273,15 @@ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
          * only the MSR. AIL=3 replaces the 0x17000 base with 0xc...3000.
          */
         if (ail == 3) {
-            *vector &= ~0x0000000000017000ull; /* Un-apply the base offset */
-            *vector |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
+            *new_nip &= ~0x0000000000017000ull; /* Un-apply the base offset */
+            *new_nip |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
         }
     }
 #endif
 }
 
-static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
-                                          target_ulong vector, target_ulong msr)
+static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
+                                          target_ulong new_msr)
 {
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
@@ -294,9 +294,9 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
      * will prevent setting of the HV bit which some exceptions might need
      * to do.
      */
-    env->msr = msr & env->msr_mask;
+    env->msr = new_msr & env->msr_mask;
     hreg_compute_hflags(env);
-    env->nip = vector;
+    env->nip = new_nip;
     /* Reset exception state */
     cs->exception_index = POWERPC_EXCP_NONE;
     env->error_code = 0;
@@ -311,6 +311,17 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
     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
@@ -319,37 +330,40 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 {
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
-    target_ulong msr, new_msr, vector;
-    int srr0, srr1, asrr0, asrr1, lev = -1;
+    struct ppc_intr_args regs;
+    int lev = -1;
 
     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
 
     /* new srr1 value excluding must-be-zero bits */
     if (excp_model == POWERPC_EXCP_BOOKE) {
-        msr = env->msr;
+        regs.msr = env->msr;
     } else {
-        msr = env->msr & ~0x783f0000ULL;
+        regs.msr = env->msr & ~0x783f0000ULL;
     }
+    regs.nip = env->nip;
 
     /*
      * new interrupt handler msr preserves existing HV and ME unless
      * explicitly overriden
+     *
+     * XXX: should this use the filtered MSR (regs.msr) from above
+     * instead of the unfiltered env->msr?
      */
-    new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
+    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
 
-    /* target registers */
-    srr0 = SPR_SRR0;
-    srr1 = SPR_SRR1;
-    asrr0 = -1;
-    asrr1 = -1;
+    regs.sprn_srr0 = SPR_SRR0;
+    regs.sprn_srr1 = SPR_SRR1;
+    regs.sprn_asrr0 = -1;
+    regs.sprn_asrr1 = -1;
 
     /*
      * check for special resume at 0x100 from doze/nap/sleep/winkle on
      * P7/P8/P9
      */
     if (env->resume_as_sreset) {
-        excp = powerpc_reset_wakeup(cs, env, excp, &msr);
+        excp = powerpc_reset_wakeup(cs, env, excp, &regs.msr);
     }
 
     /*
@@ -373,12 +387,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
         switch (excp_model) {
         case POWERPC_EXCP_40x:
-            srr0 = SPR_40x_SRR2;
-            srr1 = SPR_40x_SRR3;
+            regs.sprn_srr0 = SPR_40x_SRR2;
+            regs.sprn_srr1 = SPR_40x_SRR3;
             break;
         case POWERPC_EXCP_BOOKE:
-            srr0 = SPR_BOOKE_CSRR0;
-            srr1 = SPR_BOOKE_CSRR1;
+            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
+            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
             break;
         case POWERPC_EXCP_G2:
             break;
@@ -406,24 +420,24 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
              * ISA specifies HV, but can be delivered to guest with HV
              * clear (e.g., see FWNMI in PAPR).
              */
-            new_msr |= (target_ulong)MSR_HVB;
+            regs.new_msr |= (target_ulong)MSR_HVB;
         }
 
         /* machine check exceptions don't have ME set */
-        new_msr &= ~((target_ulong)1 << MSR_ME);
+        regs.new_msr &= ~((target_ulong)1 << MSR_ME);
 
         /* XXX: should also have something loaded in DAR / DSISR */
         switch (excp_model) {
         case POWERPC_EXCP_40x:
-            srr0 = SPR_40x_SRR2;
-            srr1 = SPR_40x_SRR3;
+            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 */
-            srr0 = SPR_BOOKE_MCSRR0;
-            srr1 = SPR_BOOKE_MCSRR1;
-            asrr0 = SPR_BOOKE_CSRR0;
-            asrr1 = SPR_BOOKE_CSRR1;
+            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;
@@ -435,8 +449,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         break;
     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
         LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
-                 "\n", msr, env->nip);
-        msr |= env->error_code;
+                 "\n", regs.msr, regs.nip);
+        regs.msr |= env->error_code;
         break;
     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
     {
@@ -466,10 +480,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         }
 
         if (!lpes0) {
-            new_msr |= (target_ulong)MSR_HVB;
-            new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-            srr0 = SPR_HSRR0;
-            srr1 = SPR_HSRR1;
+            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 */
@@ -501,20 +515,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
              * instruction, so always use store_next and claim we are
              * precise in the MSR.
              */
-            msr |= 0x00100000;
+            regs.msr |= 0x00100000;
             env->spr[SPR_BOOKE_ESR] = ESR_FP;
             break;
         case POWERPC_EXCP_INVAL:
-            LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
-            msr |= 0x00080000;
+            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:
-            msr |= 0x00040000;
+            regs.msr |= 0x00040000;
             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
             break;
         case POWERPC_EXCP_TRAP:
-            msr |= 0x00020000;
+            regs.msr |= 0x00020000;
             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
             break;
         default:
@@ -535,9 +549,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 
         /*
          * We need to correct the NIP which in this case is supposed
-         * to point to the next instruction
+         * 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.
          */
-        env->nip += 4;
+        regs.nip += 4;
+        env->nip = regs.nip;
 
         /* "PAPR mode" built-in hypercall emulation */
         if ((lev == 1) && cpu->vhyp) {
@@ -546,16 +563,17 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             vhc->hypercall(cpu->vhyp, cpu);
             return;
         }
+
         if (lev == 1) {
-            new_msr |= (target_ulong)MSR_HVB;
+            regs.new_msr |= (target_ulong)MSR_HVB;
         }
         break;
     case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
         lev = env->error_code;
         dump_syscall(env);
-        env->nip += 4;
-        new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
-        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        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          */
@@ -569,8 +587,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         LOG_EXCP("WDT exception\n");
         switch (excp_model) {
         case POWERPC_EXCP_BOOKE:
-            srr0 = SPR_BOOKE_CSRR0;
-            srr1 = SPR_BOOKE_CSRR1;
+            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
+            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
             break;
         default:
             break;
@@ -582,10 +600,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
         if (env->flags & POWERPC_FLAG_DE) {
             /* FIXME: choose one or the other based on CPU type */
-            srr0 = SPR_BOOKE_DSRR0;
-            srr1 = SPR_BOOKE_DSRR1;
-            asrr0 = SPR_BOOKE_CSRR0;
-            asrr1 = SPR_BOOKE_CSRR1;
+            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");
@@ -614,22 +632,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
         break;
     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
-        srr0 = SPR_BOOKE_CSRR0;
-        srr1 = SPR_BOOKE_CSRR1;
+        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 */
-            msr |= 0x10000;
-            new_msr |= ((target_ulong)1 << MSR_ME);
+            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).
              */
-            new_msr |= (target_ulong)MSR_HVB;
+            regs.new_msr |= (target_ulong)MSR_HVB;
         } else {
             if (msr_pow) {
                 cpu_abort(cs, "Trying to deliver power-saving system reset "
@@ -642,7 +660,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
         break;
     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
-        msr |= env->error_code;
+        regs.msr |= env->error_code;
         /* fall through */
     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
@@ -651,10 +669,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
     case POWERPC_EXCP_HV_EMU:
     case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
-        srr0 = SPR_HSRR0;
-        srr1 = SPR_HSRR1;
-        new_msr |= (target_ulong)MSR_HVB;
-        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        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               */
@@ -666,10 +684,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
 #ifdef TARGET_PPC64
         env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
-        srr0 = SPR_HSRR0;
-        srr1 = SPR_HSRR1;
-        new_msr |= (target_ulong)MSR_HVB;
-        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        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    */
@@ -697,8 +715,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         case POWERPC_EXCP_603E:
         case POWERPC_EXCP_G2:
             /* Swap temporary saved registers with GPRs */
-            if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
-                new_msr |= (target_ulong)1 << MSR_TGPR;
+            if (!(regs.new_msr & ((target_ulong)1 << MSR_TGPR))) {
+                regs.new_msr |= (target_ulong)1 << MSR_TGPR;
                 hreg_swap_gpr_tgpr(env);
             }
             /* fall through */
@@ -731,10 +749,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
                          env->error_code);
             }
 #endif
-            msr |= env->crf[0] << 28;
-            msr |= env->error_code; /* key, D/I, S/L bits */
+            regs.msr |= env->crf[0] << 28;
+            regs.msr |= env->error_code; /* key, D/I, S/L bits */
             /* Set way using a LRU mechanism */
-            msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+            regs.msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
             break;
         case POWERPC_EXCP_74xx:
 #if defined(DEBUG_SOFTWARE_TLB)
@@ -763,7 +781,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
                          env->error_code);
             }
 #endif
-            msr |= env->error_code; /* key bit */
+            regs.msr |= env->error_code; /* key bit */
             break;
         default:
             cpu_abort(cs, "Invalid TLB miss exception\n");
@@ -829,11 +847,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 
     /* Sanity check */
     if (!(env->msr_mask & MSR_HVB)) {
-        if (new_msr & MSR_HVB) {
+        if (regs.new_msr & MSR_HVB) {
             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
                       "no HV support\n", excp);
         }
-        if (srr0 == SPR_HSRR0) {
+        if (regs.sprn_srr0 == SPR_HSRR0) {
             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
                       "no HV support\n", excp);
         }
@@ -845,88 +863,89 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
      */
 #ifdef TARGET_PPC64
     if (excp_model == POWERPC_EXCP_POWER7) {
-        if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
-            new_msr |= (target_ulong)1 << MSR_LE;
+        if (!(regs.new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
+            regs.new_msr |= (target_ulong)1 << MSR_LE;
         }
     } else if (excp_model == POWERPC_EXCP_POWER8) {
-        if (new_msr & MSR_HVB) {
+        if (regs.new_msr & MSR_HVB) {
             if (env->spr[SPR_HID0] & HID0_HILE) {
-                new_msr |= (target_ulong)1 << MSR_LE;
+                regs.new_msr |= (target_ulong)1 << MSR_LE;
             }
         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
-            new_msr |= (target_ulong)1 << MSR_LE;
+            regs.new_msr |= (target_ulong)1 << MSR_LE;
         }
     } else if (excp_model == POWERPC_EXCP_POWER9 ||
                excp_model == POWERPC_EXCP_POWER10) {
-        if (new_msr & MSR_HVB) {
+        if (regs.new_msr & MSR_HVB) {
             if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
-                new_msr |= (target_ulong)1 << MSR_LE;
+                regs.new_msr |= (target_ulong)1 << MSR_LE;
             }
         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
-            new_msr |= (target_ulong)1 << MSR_LE;
+            regs.new_msr |= (target_ulong)1 << MSR_LE;
         }
     } else if (msr_ile) {
-        new_msr |= (target_ulong)1 << MSR_LE;
+        regs.new_msr |= (target_ulong)1 << MSR_LE;
     }
 #else
     if (msr_ile) {
-        new_msr |= (target_ulong)1 << MSR_LE;
+        regs.new_msr |= (target_ulong)1 << MSR_LE;
     }
 #endif
 
-    vector = env->excp_vectors[excp];
-    if (vector == (target_ulong)-1ULL) {
+    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);
     }
 
-    vector |= env->excp_prefix;
+    regs.new_nip |= env->excp_prefix;
 
     /* If any alternate SRR register are defined, duplicate saved values */
-    if (asrr0 != -1) {
-        env->spr[asrr0] = env->nip;
+    if (regs.sprn_asrr0 != -1) {
+        env->spr[regs.sprn_asrr0] = regs.nip;
     }
-    if (asrr1 != -1) {
-        env->spr[asrr1] = msr;
+    if (regs.sprn_asrr1 != -1) {
+        env->spr[regs.sprn_asrr1] = regs.msr;
     }
 
 #if defined(TARGET_PPC64)
     if (excp_model == POWERPC_EXCP_BOOKE) {
         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
             /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
-            new_msr |= (target_ulong)1 << MSR_CM;
+            regs.new_msr |= (target_ulong)1 << MSR_CM;
         } else {
-            vector = (uint32_t)vector;
+            regs.new_nip = (uint32_t)regs.new_nip;
         }
     } else {
         if (!msr_isf && !mmu_is_64bit(env->mmu_model)) {
-            vector = (uint32_t)vector;
+            regs.new_nip = (uint32_t)regs.new_nip;
         } else {
-            new_msr |= (target_ulong)1 << MSR_SF;
+            regs.new_msr |= (target_ulong)1 << MSR_SF;
         }
     }
 #endif
 
     if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
         /* Save PC */
-        env->spr[srr0] = env->nip;
+        env->spr[regs.sprn_srr0] = regs.nip;
 
         /* Save MSR */
-        env->spr[srr1] = msr;
+        env->spr[regs.sprn_srr1] = regs.msr;
 
 #if defined(TARGET_PPC64)
     } else {
-        vector += lev * 0x20;
+        regs.new_nip += lev * 0x20;
 
-        env->lr = env->nip;
-        env->ctr = msr;
+        env->lr = regs.nip;
+        env->ctr = regs.msr;
 #endif
     }
 
-    /* This can update new_msr and vector if AIL applies */
-    ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
+    /* 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,
+                       &regs.new_nip);
 
-    powerpc_set_excp_state(cpu, vector, new_msr);
+    powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
 }
 
 void ppc_cpu_do_interrupt(CPUState *cs)
-- 
2.29.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM
  2021-06-01 21:46 [RFC PATCH 0/5] target/ppc: powerpc_excp improvements - part I Fabiano Rosas
                   ` (3 preceding siblings ...)
  2021-06-01 21:46 ` [RFC PATCH 4/5] target/ppc: powerpc_excp: Standardize arguments to interrupt code Fabiano Rosas
@ 2021-06-01 21:46 ` Fabiano Rosas
  2021-06-02 12:31   ` Bruno Piazera Larsen
  2021-06-07  3:58   ` David Gibson
  4 siblings, 2 replies; 15+ messages in thread
From: Fabiano Rosas @ 2021-06-01 21:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-ppc, groug, david

This patch introduces a new way to dispatch the emulated interrupts in
powerpc_excp. It leverages the QEMU object model to store the
implementations for each interrupt and link them to their identifier
from POWERPC_EXCP enum. The processor-specific code then uses this
identifier to register which interrupts it supports.

Interrupts now come out of the big switch in powerpc_excp into their
own functions:

  static void ppc_intr_system_reset(<args>)
  {
      /*
       * Interrupt code. Sets any specific registers and MSR bits.
       */
  }
  PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");

  ^This line registers the interrupt with QOM.

When we initialize the emulated processor, the correct set of
interrupts is instantiated (pretty much like we already do):

  static void init_excp_POWER9(CPUPPCState *env)
  {
      ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
      (...)
  }

When it comes the time to inject the interrupt:

  static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
  {
      (...)

      intr = &env->entry_points[excp];
      intr->setup_regs(<args>);    <-- ppc_intr_system_reset function

      (...)
      env->spr[srr0] = nip;
      env->spr[srr1] = msr;

      env->nip = intr->addr;
      env->msr = new_msr;
  }

Some points to notice:

- The structure for the new PPCInterrupt class object is stored
  directly inside of CPUPPCState (env) so the translation code can
  still access it linearly at an offset.

- Some interrupts were being registered for P7/8/9/10 but were never
  implemented (i.e. not in the powerpc_excp switch statement). They
  are likely never triggered. We now get the benefit of QOM warning in
  such cases:

  qemu-system-ppc64: missing object type 'POWERPC_EXCP_SDOOR'
  qemu-system-ppc64: missing object type 'POWERPC_EXCP_HV_MAINT'

- The code currently allows for Program interrupts to be ignored and
  System call interrupts to be directed to the vhyp hypercall code. I
  have added an 'ignore' flag to deal with these two cases and return
  early from powerpc_excp.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/cpu.h         |  29 +-
 target/ppc/cpu_init.c    | 640 +++++++++++++++++++--------------------
 target/ppc/excp_helper.c | 545 ++-------------------------------
 target/ppc/interrupts.c  | 638 ++++++++++++++++++++++++++++++++++++++
 target/ppc/machine.c     |   2 +-
 target/ppc/meson.build   |   1 +
 target/ppc/ppc_intr.h    |  55 ++++
 target/ppc/translate.c   |   3 +-
 8 files changed, 1066 insertions(+), 847 deletions(-)
 create mode 100644 target/ppc/interrupts.c
 create mode 100644 target/ppc/ppc_intr.h

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);
 }
-- 
2.29.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 1/5] target/ppc: powerpc_excp: Move lpes code to where it is used
  2021-06-01 21:46 ` [RFC PATCH 1/5] target/ppc: powerpc_excp: Move lpes code to where it is used Fabiano Rosas
@ 2021-06-02  7:37   ` David Gibson
  0 siblings, 0 replies; 15+ messages in thread
From: David Gibson @ 2021-06-02  7:37 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 3633 bytes --]

On Tue, Jun 01, 2021 at 06:46:45PM -0300, Fabiano Rosas wrote:
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>

Applied to ppc-for-6.1.

> ---
>  target/ppc/excp_helper.c | 47 +++++++++++++++++++++-------------------
>  1 file changed, 25 insertions(+), 22 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 04418054f5..5ea8503b46 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -333,7 +333,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      CPUPPCState *env = &cpu->env;
>      target_ulong msr, new_msr, vector;
>      int srr0, srr1, asrr0, asrr1, lev = -1;
> -    bool lpes0;
>  
>      qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
>                    " => %08x (%02x)\n", env->nip, excp, env->error_code);
> @@ -365,27 +364,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          excp = powerpc_reset_wakeup(cs, env, excp, &msr);
>      }
>  
> -    /*
> -     * 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;
> -    }
> -
>      /*
>       * Hypervisor emulation assistance interrupt only exists on server
>       * arch 2.05 server or later. We also don't want to generate it if
> @@ -473,8 +451,32 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          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) {
>              new_msr |= (target_ulong)MSR_HVB;
>              new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> @@ -486,6 +488,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
>          }
>          break;
> +    }
>      case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
>          /* Get rS/rD and rA from faulting opcode */
>          /*

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 2/5] target/ppc: powerpc_excp: Remove dump_syscall_vectored
  2021-06-01 21:46 ` [RFC PATCH 2/5] target/ppc: powerpc_excp: Remove dump_syscall_vectored Fabiano Rosas
@ 2021-06-02  7:37   ` David Gibson
  0 siblings, 0 replies; 15+ messages in thread
From: David Gibson @ 2021-06-02  7:37 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 2059 bytes --]

On Tue, Jun 01, 2021 at 06:46:46PM -0300, Fabiano Rosas wrote:
> This function is identical to dump_syscall, so use the latter for
> system call vectored as well.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>

Applied to ppc-for-6.1, thanks.

> ---
>  target/ppc/excp_helper.c | 14 +-------------
>  1 file changed, 1 insertion(+), 13 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 5ea8503b46..9e3aae1c96 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -70,18 +70,6 @@ static inline void dump_syscall(CPUPPCState *env)
>                    ppc_dump_gpr(env, 8), env->nip);
>  }
>  
> -static inline void dump_syscall_vectored(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
> @@ -564,7 +552,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          break;
>      case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
>          lev = env->error_code;
> -        dump_syscall_vectored(env);
> +        dump_syscall(env);
>          env->nip += 4;
>          new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
>          new_msr |= env->msr & ((target_ulong)1 << MSR_RI);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 3/5] target/ppc: powerpc_excp: Consolidade TLB miss code
  2021-06-01 21:46 ` [RFC PATCH 3/5] target/ppc: powerpc_excp: Consolidade TLB miss code Fabiano Rosas
@ 2021-06-02  7:37   ` David Gibson
  0 siblings, 0 replies; 15+ messages in thread
From: David Gibson @ 2021-06-02  7:37 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 4187 bytes --]

On Tue, Jun 01, 2021 at 06:46:47PM -0300, Fabiano Rosas wrote:
> The only difference in the code for Instruction fetch, Data load and
> Data store TLB miss errors is that when called from an unsupported
> processor (i.e. not one of 602, 603, 603e, G2, 7x5 or 74xx), they
> abort with a message specific to the operation type (insn fetch, data
> load/store).
> 
> If a processor does not support those interrupts we should not be
> registering them in init_excp_<proc> to begin with, so that error
> message would never be used.
> 
> I'm leaving the message in for completeness, but making it generic and
> consolidating the three interrupts into the same case statement body.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>

Wow, what a mess that was.

Applied to ppc-for-6.1.

> ---
>  target/ppc/excp_helper.c | 37 ++-----------------------------------
>  1 file changed, 2 insertions(+), 35 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 9e3aae1c96..fd147e2a37 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -689,52 +689,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>                    "is not implemented yet !\n");
>          break;
>      case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
> -        switch (excp_model) {
> -        case POWERPC_EXCP_602:
> -        case POWERPC_EXCP_603:
> -        case POWERPC_EXCP_603E:
> -        case POWERPC_EXCP_G2:
> -            goto tlb_miss_tgpr;
> -        case POWERPC_EXCP_7x5:
> -            goto tlb_miss;
> -        case POWERPC_EXCP_74xx:
> -            goto tlb_miss_74xx;
> -        default:
> -            cpu_abort(cs, "Invalid instruction TLB miss exception\n");
> -            break;
> -        }
> -        break;
>      case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
> -        switch (excp_model) {
> -        case POWERPC_EXCP_602:
> -        case POWERPC_EXCP_603:
> -        case POWERPC_EXCP_603E:
> -        case POWERPC_EXCP_G2:
> -            goto tlb_miss_tgpr;
> -        case POWERPC_EXCP_7x5:
> -            goto tlb_miss;
> -        case POWERPC_EXCP_74xx:
> -            goto tlb_miss_74xx;
> -        default:
> -            cpu_abort(cs, "Invalid data load TLB miss exception\n");
> -            break;
> -        }
> -        break;
>      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:
> -        tlb_miss_tgpr:
>              /* Swap temporary saved registers with GPRs */
>              if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
>                  new_msr |= (target_ulong)1 << MSR_TGPR;
>                  hreg_swap_gpr_tgpr(env);
>              }
> -            goto tlb_miss;
> +            /* fall through */
>          case POWERPC_EXCP_7x5:
> -        tlb_miss:
>  #if defined(DEBUG_SOFTWARE_TLB)
>              if (qemu_log_enabled()) {
>                  const char *es;
> @@ -769,7 +737,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
>              break;
>          case POWERPC_EXCP_74xx:
> -        tlb_miss_74xx:
>  #if defined(DEBUG_SOFTWARE_TLB)
>              if (qemu_log_enabled()) {
>                  const char *es;
> @@ -799,7 +766,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              msr |= env->error_code; /* key bit */
>              break;
>          default:
> -            cpu_abort(cs, "Invalid data store TLB miss exception\n");
> +            cpu_abort(cs, "Invalid TLB miss exception\n");
>              break;
>          }
>          break;

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM
  2021-06-01 21:46 ` [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM Fabiano Rosas
@ 2021-06-02 12:31   ` Bruno Piazera Larsen
  2021-06-02 15:11     ` Fabiano Rosas
  2021-06-07  3:58   ` David Gibson
  1 sibling, 1 reply; 15+ messages in thread
From: Bruno Piazera Larsen @ 2021-06-02 12:31 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: qemu-ppc, groug, david

[-- Attachment #1: Type: text/plain, Size: 9203 bytes --]


On 01/06/2021 18:46, Fabiano Rosas wrote:
> This patch introduces a new way to dispatch the emulated interrupts in
> powerpc_excp. It leverages the QEMU object model to store the
> implementations for each interrupt and link them to their identifier
> from POWERPC_EXCP enum. The processor-specific code then uses this
> identifier to register which interrupts it supports.
>
> Interrupts now come out of the big switch in powerpc_excp into their
> own functions:
>
>    static void ppc_intr_system_reset(<args>)
>    {
>        /*
>         * Interrupt code. Sets any specific registers and MSR bits.
>         */
>    }
>    PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");
>
>    ^This line registers the interrupt with QOM.
>
> When we initialize the emulated processor, the correct set of
> interrupts is instantiated (pretty much like we already do):
>
>    static void init_excp_POWER9(CPUPPCState *env)
>    {
>        ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
>        (...)
>    }
>
> When it comes the time to inject the interrupt:
>
>    static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>    {
>        (...)
>
>        intr = &env->entry_points[excp];
>        intr->setup_regs(<args>);    <-- ppc_intr_system_reset function
>
>        (...)
>        env->spr[srr0] = nip;
>        env->spr[srr1] = msr;
>
>        env->nip = intr->addr;
>        env->msr = new_msr;
>    }
>
> Some points to notice:
>
> - The structure for the new PPCInterrupt class object is stored
>    directly inside of CPUPPCState (env) so the translation code can
>    still access it linearly at an offset.
>
> - Some interrupts were being registered for P7/8/9/10 but were never
>    implemented (i.e. not in the powerpc_excp switch statement). They
>    are likely never triggered. We now get the benefit of QOM warning in
>    such cases:
>
>    qemu-system-ppc64: missing object type 'POWERPC_EXCP_SDOOR'
>    qemu-system-ppc64: missing object type 'POWERPC_EXCP_HV_MAINT'
>
> - The code currently allows for Program interrupts to be ignored and
>    System call interrupts to be directed to the vhyp hypercall code. I
>    have added an 'ignore' flag to deal with these two cases and return
>    early from powerpc_excp.
>
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
> ---

I don't see anything really wrong with the code itself, but this patch 
should probably be broken up into at least 2, one for the code motion 
and another for the ppc_intr'ification of the exception model.

>   target/ppc/cpu.h         |  29 +-
>   target/ppc/cpu_init.c    | 640 +++++++++++++++++++--------------------
>   target/ppc/excp_helper.c | 545 ++-------------------------------
>   target/ppc/interrupts.c  | 638 ++++++++++++++++++++++++++++++++++++++
>   target/ppc/machine.c     |   2 +-
>   target/ppc/meson.build   |   1 +
>   target/ppc/ppc_intr.h    |  55 ++++
>   target/ppc/translate.c   |   3 +-
>   8 files changed, 1066 insertions(+), 847 deletions(-)
>   create mode 100644 target/ppc/interrupts.c
>   create mode 100644 target/ppc/ppc_intr.h
>
> 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;
> +};
> +
This part also has me a bit confused. Why define it first in 
excp_helper.c in the last patch just to move it to here now?
> +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 */
<snip>
> @@ -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
>   }
Not sure if this is possible, but if this bit can be done separately as 
an earlier patch, it would make reviewing a lot easier.
>   
> @@ -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);
> -    }
We don't need to use this to set invalid values?
>       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 */
<snip>
> 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);
>   }
Other than that, from what I can see, looks ok
-- 
Bruno Piazera Larsen
Instituto de Pesquisas ELDORADO 
<https://www.eldorado.org.br/?utm_campaign=assinatura_de_e-mail&utm_medium=email&utm_source=RD+Station>
Departamento Computação Embarcada
Analista de Software Trainee
Aviso Legal - Disclaimer <https://www.eldorado.org.br/disclaimer.html>

[-- Attachment #2: Type: text/html, Size: 10402 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM
  2021-06-02 12:31   ` Bruno Piazera Larsen
@ 2021-06-02 15:11     ` Fabiano Rosas
  0 siblings, 0 replies; 15+ messages in thread
From: Fabiano Rosas @ 2021-06-02 15:11 UTC (permalink / raw)
  To: Bruno Piazera Larsen, qemu-devel; +Cc: qemu-ppc, groug, david

Bruno Piazera Larsen <bruno.larsen@eldorado.org.br> writes:

> On 01/06/2021 18:46, Fabiano Rosas wrote:

<snip>

>> +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;
>> +};
>> +
> This part also has me a bit confused. Why define it first in 
> excp_helper.c in the last patch just to move it to here now?

Because back then it wasn't used outside of excp_helper.c. People would
probably ask: "why put this in a common header if it is not used
anywhere else?" =)

>> +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 */
> <snip>
>> @@ -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
>>   }
> Not sure if this is possible, but if this bit can be done separately as 
> an earlier patch, it would make reviewing a lot easier.

It could, but then it would be a synthetic change with not much purpose
on its own. We probably wouldn't want to merge a change that adds a
function that only writes an array position.

But I agree that this patch is on the verge of being too large. I had
another version split into more patches and it felt that we'd need to
keep going back and forth to understand the real impact of the
change. I'll think some more about it for a v2.

>>   
>> @@ -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);
>> -    }
> We don't need to use this to set invalid values?

I'm now using the interrupt callback pointer for this. So if the
processor has not registered the interrupt, the pointer will be NULL.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 4/5] target/ppc: powerpc_excp: Standardize arguments to interrupt code
  2021-06-01 21:46 ` [RFC PATCH 4/5] target/ppc: powerpc_excp: Standardize arguments to interrupt code Fabiano Rosas
@ 2021-06-07  3:55   ` David Gibson
  0 siblings, 0 replies; 15+ messages in thread
From: David Gibson @ 2021-06-07  3:55 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 24399 bytes --]

On Tue, Jun 01, 2021 at 06:46:48PM -0300, Fabiano Rosas wrote:
> The next patches will split the big switch statement in powerpc_excp
> into individual functions so it would be cleaner if all variables are
> already grouped in a structure and their names consistent.
> 
> This patch makes it so that the old values for MSR and NIP (from env)
> are saved at the beginning as regs.msr and regs.nip and all
> modifications are done over this regs version. At the end of the
> function regs.msr and regs.nip are saved in the SRRs and regs.new_msr
> and regs.new_nip are written to env.
> 
> There are two points of interest here:
> 
> - The system call code has a particularity where it needs to use
> env->nip because it might return early and the modification needs to
> be seen by the virtual hypervisor hypercall code. I have added a
> comment making this clear.
> 
> - The MSR filter at the beginning is being applied to the old MSR value
> only, i.e. the one that goes into SRR1. The new_msr is taken from
> env->msr without filtering the reserved bits. This might be a bug in
> the existing code. I'm also adding a comment to point that out.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
> ---
>  target/ppc/excp_helper.c | 231 +++++++++++++++++++++------------------
>  1 file changed, 125 insertions(+), 106 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index fd147e2a37..12bf829c8f 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -186,7 +186,7 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
>  static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
>                                        target_ulong msr,
>                                        target_ulong *new_msr,
> -                                      target_ulong *vector)
> +                                      target_ulong *new_nip)
>  {
>  #if defined(TARGET_PPC64)
>      CPUPPCState *env = &cpu->env;
> @@ -263,9 +263,9 @@ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
>  
>      if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
>          if (ail == 2) {
> -            *vector |= 0x0000000000018000ull;
> +            *new_nip |= 0x0000000000018000ull;
>          } else if (ail == 3) {
> -            *vector |= 0xc000000000004000ull;
> +            *new_nip |= 0xc000000000004000ull;
>          }
>      } else {
>          /*
> @@ -273,15 +273,15 @@ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
>           * only the MSR. AIL=3 replaces the 0x17000 base with 0xc...3000.
>           */
>          if (ail == 3) {
> -            *vector &= ~0x0000000000017000ull; /* Un-apply the base offset */
> -            *vector |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
> +            *new_nip &= ~0x0000000000017000ull; /* Un-apply the base offset */
> +            *new_nip |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
>          }
>      }
>  #endif
>  }
>  
> -static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
> -                                          target_ulong vector, target_ulong msr)
> +static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
> +                                          target_ulong new_msr)
>  {
>      CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
> @@ -294,9 +294,9 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
>       * will prevent setting of the HV bit which some exceptions might need
>       * to do.
>       */
> -    env->msr = msr & env->msr_mask;
> +    env->msr = new_msr & env->msr_mask;
>      hreg_compute_hflags(env);
> -    env->nip = vector;
> +    env->nip = new_nip;
>      /* Reset exception state */
>      cs->exception_index = POWERPC_EXCP_NONE;
>      env->error_code = 0;
> @@ -311,6 +311,17 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
>      check_tlb_flush(env, false);
>  }
>  
> +struct ppc_intr_args {

Please use qemu coding style convetions for type names (CamelCase and
a typedef).

> +    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
> @@ -319,37 +330,40 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>  {
>      CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
> -    target_ulong msr, new_msr, vector;
> -    int srr0, srr1, asrr0, asrr1, lev = -1;
> +    struct ppc_intr_args regs;
> +    int lev = -1;
>  
>      qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
>                    " => %08x (%02x)\n", env->nip, excp, env->error_code);
>  
>      /* new srr1 value excluding must-be-zero bits */
>      if (excp_model == POWERPC_EXCP_BOOKE) {
> -        msr = env->msr;
> +        regs.msr = env->msr;
>      } else {
> -        msr = env->msr & ~0x783f0000ULL;
> +        regs.msr = env->msr & ~0x783f0000ULL;
>      }
> +    regs.nip = env->nip;
>  
>      /*
>       * new interrupt handler msr preserves existing HV and ME unless
>       * explicitly overriden
> +     *
> +     * XXX: should this use the filtered MSR (regs.msr) from above
> +     * instead of the unfiltered env->msr?
>       */
> -    new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
> +    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
>  
> -    /* target registers */
> -    srr0 = SPR_SRR0;
> -    srr1 = SPR_SRR1;
> -    asrr0 = -1;
> -    asrr1 = -1;
> +    regs.sprn_srr0 = SPR_SRR0;
> +    regs.sprn_srr1 = SPR_SRR1;
> +    regs.sprn_asrr0 = -1;
> +    regs.sprn_asrr1 = -1;
>  
>      /*
>       * check for special resume at 0x100 from doze/nap/sleep/winkle on
>       * P7/P8/P9
>       */
>      if (env->resume_as_sreset) {
> -        excp = powerpc_reset_wakeup(cs, env, excp, &msr);
> +        excp = powerpc_reset_wakeup(cs, env, excp, &regs.msr);
>      }
>  
>      /*
> @@ -373,12 +387,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
>          switch (excp_model) {
>          case POWERPC_EXCP_40x:
> -            srr0 = SPR_40x_SRR2;
> -            srr1 = SPR_40x_SRR3;
> +            regs.sprn_srr0 = SPR_40x_SRR2;
> +            regs.sprn_srr1 = SPR_40x_SRR3;
>              break;
>          case POWERPC_EXCP_BOOKE:
> -            srr0 = SPR_BOOKE_CSRR0;
> -            srr1 = SPR_BOOKE_CSRR1;
> +            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
> +            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
>              break;
>          case POWERPC_EXCP_G2:
>              break;
> @@ -406,24 +420,24 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>               * ISA specifies HV, but can be delivered to guest with HV
>               * clear (e.g., see FWNMI in PAPR).
>               */
> -            new_msr |= (target_ulong)MSR_HVB;
> +            regs.new_msr |= (target_ulong)MSR_HVB;
>          }
>  
>          /* machine check exceptions don't have ME set */
> -        new_msr &= ~((target_ulong)1 << MSR_ME);
> +        regs.new_msr &= ~((target_ulong)1 << MSR_ME);
>  
>          /* XXX: should also have something loaded in DAR / DSISR */
>          switch (excp_model) {
>          case POWERPC_EXCP_40x:
> -            srr0 = SPR_40x_SRR2;
> -            srr1 = SPR_40x_SRR3;
> +            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 */
> -            srr0 = SPR_BOOKE_MCSRR0;
> -            srr1 = SPR_BOOKE_MCSRR1;
> -            asrr0 = SPR_BOOKE_CSRR0;
> -            asrr1 = SPR_BOOKE_CSRR1;
> +            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;
> @@ -435,8 +449,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          break;
>      case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
>          LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
> -                 "\n", msr, env->nip);
> -        msr |= env->error_code;
> +                 "\n", regs.msr, regs.nip);
> +        regs.msr |= env->error_code;
>          break;
>      case POWERPC_EXCP_EXTERNAL:  /* External input                           */
>      {
> @@ -466,10 +480,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          }
>  
>          if (!lpes0) {
> -            new_msr |= (target_ulong)MSR_HVB;
> -            new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -            srr0 = SPR_HSRR0;
> -            srr1 = SPR_HSRR1;
> +            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 */
> @@ -501,20 +515,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>               * instruction, so always use store_next and claim we are
>               * precise in the MSR.
>               */
> -            msr |= 0x00100000;
> +            regs.msr |= 0x00100000;
>              env->spr[SPR_BOOKE_ESR] = ESR_FP;
>              break;
>          case POWERPC_EXCP_INVAL:
> -            LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
> -            msr |= 0x00080000;
> +            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:
> -            msr |= 0x00040000;
> +            regs.msr |= 0x00040000;
>              env->spr[SPR_BOOKE_ESR] = ESR_PPR;
>              break;
>          case POWERPC_EXCP_TRAP:
> -            msr |= 0x00020000;
> +            regs.msr |= 0x00020000;
>              env->spr[SPR_BOOKE_ESR] = ESR_PTR;
>              break;
>          default:
> @@ -535,9 +549,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>  
>          /*
>           * We need to correct the NIP which in this case is supposed
> -         * to point to the next instruction
> +         * 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.
>           */
> -        env->nip += 4;
> +        regs.nip += 4;
> +        env->nip = regs.nip;
>  
>          /* "PAPR mode" built-in hypercall emulation */
>          if ((lev == 1) && cpu->vhyp) {
> @@ -546,16 +563,17 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              vhc->hypercall(cpu->vhyp, cpu);
>              return;
>          }
> +
>          if (lev == 1) {
> -            new_msr |= (target_ulong)MSR_HVB;
> +            regs.new_msr |= (target_ulong)MSR_HVB;
>          }
>          break;
>      case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
>          lev = env->error_code;
>          dump_syscall(env);
> -        env->nip += 4;
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> +        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          */
> @@ -569,8 +587,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          LOG_EXCP("WDT exception\n");
>          switch (excp_model) {
>          case POWERPC_EXCP_BOOKE:
> -            srr0 = SPR_BOOKE_CSRR0;
> -            srr1 = SPR_BOOKE_CSRR1;
> +            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
> +            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
>              break;
>          default:
>              break;
> @@ -582,10 +600,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
>          if (env->flags & POWERPC_FLAG_DE) {
>              /* FIXME: choose one or the other based on CPU type */
> -            srr0 = SPR_BOOKE_DSRR0;
> -            srr1 = SPR_BOOKE_DSRR1;
> -            asrr0 = SPR_BOOKE_CSRR0;
> -            asrr1 = SPR_BOOKE_CSRR1;
> +            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");
> @@ -614,22 +632,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
>          break;
>      case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
> -        srr0 = SPR_BOOKE_CSRR0;
> -        srr1 = SPR_BOOKE_CSRR1;
> +        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 */
> -            msr |= 0x10000;
> -            new_msr |= ((target_ulong)1 << MSR_ME);
> +            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).
>               */
> -            new_msr |= (target_ulong)MSR_HVB;
> +            regs.new_msr |= (target_ulong)MSR_HVB;
>          } else {
>              if (msr_pow) {
>                  cpu_abort(cs, "Trying to deliver power-saving system reset "
> @@ -642,7 +660,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      case POWERPC_EXCP_TRACE:     /* Trace exception                          */
>          break;
>      case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
> -        msr |= env->error_code;
> +        regs.msr |= env->error_code;
>          /* fall through */
>      case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
>      case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
> @@ -651,10 +669,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
>      case POWERPC_EXCP_HV_EMU:
>      case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
> -        srr0 = SPR_HSRR0;
> -        srr1 = SPR_HSRR1;
> -        new_msr |= (target_ulong)MSR_HVB;
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> +        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               */
> @@ -666,10 +684,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
>  #ifdef TARGET_PPC64
>          env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
> -        srr0 = SPR_HSRR0;
> -        srr1 = SPR_HSRR1;
> -        new_msr |= (target_ulong)MSR_HVB;
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> +        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    */
> @@ -697,8 +715,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          case POWERPC_EXCP_603E:
>          case POWERPC_EXCP_G2:
>              /* Swap temporary saved registers with GPRs */
> -            if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
> -                new_msr |= (target_ulong)1 << MSR_TGPR;
> +            if (!(regs.new_msr & ((target_ulong)1 << MSR_TGPR))) {
> +                regs.new_msr |= (target_ulong)1 << MSR_TGPR;
>                  hreg_swap_gpr_tgpr(env);
>              }
>              /* fall through */
> @@ -731,10 +749,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>                           env->error_code);
>              }
>  #endif
> -            msr |= env->crf[0] << 28;
> -            msr |= env->error_code; /* key, D/I, S/L bits */
> +            regs.msr |= env->crf[0] << 28;
> +            regs.msr |= env->error_code; /* key, D/I, S/L bits */
>              /* Set way using a LRU mechanism */
> -            msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
> +            regs.msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
>              break;
>          case POWERPC_EXCP_74xx:
>  #if defined(DEBUG_SOFTWARE_TLB)
> @@ -763,7 +781,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>                           env->error_code);
>              }
>  #endif
> -            msr |= env->error_code; /* key bit */
> +            regs.msr |= env->error_code; /* key bit */
>              break;
>          default:
>              cpu_abort(cs, "Invalid TLB miss exception\n");
> @@ -829,11 +847,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>  
>      /* Sanity check */
>      if (!(env->msr_mask & MSR_HVB)) {
> -        if (new_msr & MSR_HVB) {
> +        if (regs.new_msr & MSR_HVB) {
>              cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
>                        "no HV support\n", excp);
>          }
> -        if (srr0 == SPR_HSRR0) {
> +        if (regs.sprn_srr0 == SPR_HSRR0) {
>              cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
>                        "no HV support\n", excp);
>          }
> @@ -845,88 +863,89 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>       */
>  #ifdef TARGET_PPC64
>      if (excp_model == POWERPC_EXCP_POWER7) {
> -        if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
> -            new_msr |= (target_ulong)1 << MSR_LE;
> +        if (!(regs.new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
> +            regs.new_msr |= (target_ulong)1 << MSR_LE;
>          }
>      } else if (excp_model == POWERPC_EXCP_POWER8) {
> -        if (new_msr & MSR_HVB) {
> +        if (regs.new_msr & MSR_HVB) {
>              if (env->spr[SPR_HID0] & HID0_HILE) {
> -                new_msr |= (target_ulong)1 << MSR_LE;
> +                regs.new_msr |= (target_ulong)1 << MSR_LE;
>              }
>          } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
> -            new_msr |= (target_ulong)1 << MSR_LE;
> +            regs.new_msr |= (target_ulong)1 << MSR_LE;
>          }
>      } else if (excp_model == POWERPC_EXCP_POWER9 ||
>                 excp_model == POWERPC_EXCP_POWER10) {
> -        if (new_msr & MSR_HVB) {
> +        if (regs.new_msr & MSR_HVB) {
>              if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
> -                new_msr |= (target_ulong)1 << MSR_LE;
> +                regs.new_msr |= (target_ulong)1 << MSR_LE;
>              }
>          } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
> -            new_msr |= (target_ulong)1 << MSR_LE;
> +            regs.new_msr |= (target_ulong)1 << MSR_LE;
>          }
>      } else if (msr_ile) {
> -        new_msr |= (target_ulong)1 << MSR_LE;
> +        regs.new_msr |= (target_ulong)1 << MSR_LE;
>      }
>  #else
>      if (msr_ile) {
> -        new_msr |= (target_ulong)1 << MSR_LE;
> +        regs.new_msr |= (target_ulong)1 << MSR_LE;
>      }
>  #endif
>  
> -    vector = env->excp_vectors[excp];
> -    if (vector == (target_ulong)-1ULL) {
> +    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);
>      }
>  
> -    vector |= env->excp_prefix;
> +    regs.new_nip |= env->excp_prefix;
>  
>      /* If any alternate SRR register are defined, duplicate saved values */
> -    if (asrr0 != -1) {
> -        env->spr[asrr0] = env->nip;
> +    if (regs.sprn_asrr0 != -1) {
> +        env->spr[regs.sprn_asrr0] = regs.nip;
>      }
> -    if (asrr1 != -1) {
> -        env->spr[asrr1] = msr;
> +    if (regs.sprn_asrr1 != -1) {
> +        env->spr[regs.sprn_asrr1] = regs.msr;
>      }
>  
>  #if defined(TARGET_PPC64)
>      if (excp_model == POWERPC_EXCP_BOOKE) {
>          if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
>              /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
> -            new_msr |= (target_ulong)1 << MSR_CM;
> +            regs.new_msr |= (target_ulong)1 << MSR_CM;
>          } else {
> -            vector = (uint32_t)vector;
> +            regs.new_nip = (uint32_t)regs.new_nip;
>          }
>      } else {
>          if (!msr_isf && !mmu_is_64bit(env->mmu_model)) {
> -            vector = (uint32_t)vector;
> +            regs.new_nip = (uint32_t)regs.new_nip;
>          } else {
> -            new_msr |= (target_ulong)1 << MSR_SF;
> +            regs.new_msr |= (target_ulong)1 << MSR_SF;
>          }
>      }
>  #endif
>  
>      if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
>          /* Save PC */
> -        env->spr[srr0] = env->nip;
> +        env->spr[regs.sprn_srr0] = regs.nip;
>  
>          /* Save MSR */
> -        env->spr[srr1] = msr;
> +        env->spr[regs.sprn_srr1] = regs.msr;
>  
>  #if defined(TARGET_PPC64)
>      } else {
> -        vector += lev * 0x20;
> +        regs.new_nip += lev * 0x20;
>  
> -        env->lr = env->nip;
> -        env->ctr = msr;
> +        env->lr = regs.nip;
> +        env->ctr = regs.msr;
>  #endif
>      }
>  
> -    /* This can update new_msr and vector if AIL applies */
> -    ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
> +    /* 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,
> +                       &regs.new_nip);
>  
> -    powerpc_set_excp_state(cpu, vector, new_msr);
> +    powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
>  }
>  
>  void ppc_cpu_do_interrupt(CPUState *cs)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM
  2021-06-01 21:46 ` [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM Fabiano Rosas
  2021-06-02 12:31   ` Bruno Piazera Larsen
@ 2021-06-07  3:58   ` David Gibson
  2021-06-07 16:54     ` Fabiano Rosas
  1 sibling, 1 reply; 15+ messages in thread
From: David Gibson @ 2021-06-07  3:58 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 106029 bytes --]

On Tue, Jun 01, 2021 at 06:46:49PM -0300, Fabiano Rosas wrote:
> This patch introduces a new way to dispatch the emulated interrupts in
> powerpc_excp. It leverages the QEMU object model to store the
> implementations for each interrupt and link them to their identifier
> from POWERPC_EXCP enum. The processor-specific code then uses this
> identifier to register which interrupts it supports.
> 
> Interrupts now come out of the big switch in powerpc_excp into their
> own functions:
> 
>   static void ppc_intr_system_reset(<args>)
>   {
>       /*
>        * Interrupt code. Sets any specific registers and MSR bits.
>        */
>   }
>   PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");
> 
>   ^This line registers the interrupt with QOM.
> 
> When we initialize the emulated processor, the correct set of
> interrupts is instantiated (pretty much like we already do):
> 
>   static void init_excp_POWER9(CPUPPCState *env)
>   {
>       ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
>       (...)
>   }
> 
> When it comes the time to inject the interrupt:
> 
>   static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>   {
>       (...)
> 
>       intr = &env->entry_points[excp];
>       intr->setup_regs(<args>);    <-- ppc_intr_system_reset function
> 
>       (...)
>       env->spr[srr0] = nip;
>       env->spr[srr1] = msr;
> 
>       env->nip = intr->addr;
>       env->msr = new_msr;
>   }
> 
> Some points to notice:
> 
> - The structure for the new PPCInterrupt class object is stored
>   directly inside of CPUPPCState (env) so the translation code can
>   still access it linearly at an offset.
> 
> - Some interrupts were being registered for P7/8/9/10 but were never
>   implemented (i.e. not in the powerpc_excp switch statement). They
>   are likely never triggered. We now get the benefit of QOM warning in
>   such cases:
> 
>   qemu-system-ppc64: missing object type 'POWERPC_EXCP_SDOOR'
>   qemu-system-ppc64: missing object type 'POWERPC_EXCP_HV_MAINT'
> 
> - The code currently allows for Program interrupts to be ignored and
>   System call interrupts to be directed to the vhyp hypercall code. I
>   have added an 'ignore' flag to deal with these two cases and return
>   early from powerpc_excp.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
> ---
>  target/ppc/cpu.h         |  29 +-
>  target/ppc/cpu_init.c    | 640 +++++++++++++++++++--------------------
>  target/ppc/excp_helper.c | 545 ++-------------------------------
>  target/ppc/interrupts.c  | 638 ++++++++++++++++++++++++++++++++++++++
>  target/ppc/machine.c     |   2 +-
>  target/ppc/meson.build   |   1 +
>  target/ppc/ppc_intr.h    |  55 ++++
>  target/ppc/translate.c   |   3 +-
>  8 files changed, 1066 insertions(+), 847 deletions(-)
>  create mode 100644 target/ppc/interrupts.c
>  create mode 100644 target/ppc/ppc_intr.h
> 
> 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);

Hmm.  Using this signature kind of enforces that we dispatch based on
which exception *then* then the exception model.  I think that's
backwards: since what vectors exist and make sense depends on the
exception model, I think we should ideally be splitting on model
first, then exception type.

Now, a lot of the existing code is exception-then-model and changing
that is a long term project, but I don't think we should lock
ourselves further into doing it the backwards way.

> +
> +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 {

Having an info/dispatch structure for each vector makes sense..

> +    Object parent;

..but making it a QOM object really seems like overkill.  In fact
making it a QOM object at least somewhat exposes the internal
structure to the user via QMP, which I really don't think we want to
do.

> +
> +    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);
>  }

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM
  2021-06-07  3:58   ` David Gibson
@ 2021-06-07 16:54     ` Fabiano Rosas
  2021-06-15  5:56       ` David Gibson
  0 siblings, 1 reply; 15+ messages in thread
From: Fabiano Rosas @ 2021-06-07 16:54 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel, groug

David Gibson <david@gibson.dropbear.id.au> writes:

> On Tue, Jun 01, 2021 at 06:46:49PM -0300, Fabiano Rosas wrote:
>> +typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCInterrupt *intr,
>> +                              int excp_model, ppc_intr_args *regs,
>> +                              bool *ignore);
>
> Hmm.  Using this signature kind of enforces that we dispatch based on
> which exception *then* then the exception model.  I think that's
> backwards: since what vectors exist and make sense depends on the
> exception model, I think we should ideally be splitting on model
> first, then exception type.
>
> Now, a lot of the existing code is exception-then-model and changing
> that is a long term project, but I don't think we should lock
> ourselves further into doing it the backwards way.

Ok, so assuming one C file per exception model, I see three options:

 i) exception --> model (current):

 Interrupt code separate from models. One implementation for each
 interrupt that takes the model as argument. Models opt-in which
 interrupts they want (according to the ISA).

 ii) model --> exception:

 Interrupt code inside each model file. The model implements only the
 interrupts which exist (according to ISA). There would be duplication
 since several models would implement the same system reset, machine
 check, program, etc.

 iii) model --> exception w/ generic interrupts:

 Generic interrupt code separate from models. One implementation for
 each generic interrupt. Models opt-in which interrupts they want
 (according to the ISA). Models override generic implementation with
 model-specific ones.

Option (i) leads to the most code reuse; (ii) makes each model and its
interrupts into one comprehensive unit; (iii) avoids duplication of the
generic code.

>> +
>> +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 {
>
> Having an info/dispatch structure for each vector makes sense..
>
>> +    Object parent;
>
> ..but making it a QOM object really seems like overkill.  In fact
> making it a QOM object at least somewhat exposes the internal
> structure to the user via QMP, which I really don't think we want to
> do.

I'm using QOM code mainly to facilitate the id->function mapping. I'll
remove the QOM layer and implement my own.

>> +
>> +    int id;
>> +    const char *name;
>> +    target_ulong addr;
>> +    ppc_intr_fn_t setup_regs;
>> +};


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM
  2021-06-07 16:54     ` Fabiano Rosas
@ 2021-06-15  5:56       ` David Gibson
  0 siblings, 0 replies; 15+ messages in thread
From: David Gibson @ 2021-06-15  5:56 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 4322 bytes --]

On Mon, Jun 07, 2021 at 01:54:15PM -0300, Fabiano Rosas wrote:
> David Gibson <david@gibson.dropbear.id.au> writes:
> 
> > On Tue, Jun 01, 2021 at 06:46:49PM -0300, Fabiano Rosas wrote:
> >> +typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCInterrupt *intr,
> >> +                              int excp_model, ppc_intr_args *regs,
> >> +                              bool *ignore);
> >
> > Hmm.  Using this signature kind of enforces that we dispatch based on
> > which exception *then* then the exception model.  I think that's
> > backwards: since what vectors exist and make sense depends on the
> > exception model, I think we should ideally be splitting on model
> > first, then exception type.
> >
> > Now, a lot of the existing code is exception-then-model and changing
> > that is a long term project, but I don't think we should lock
> > ourselves further into doing it the backwards way.
> 
> Ok, so assuming one C file per exception model, I see three options:
> 
>  i) exception --> model (current):
> 
>  Interrupt code separate from models. One implementation for each
>  interrupt that takes the model as argument. Models opt-in which
>  interrupts they want (according to the ISA).
> 
>  ii) model --> exception:
> 
>  Interrupt code inside each model file. The model implements only the
>  interrupts which exist (according to ISA). There would be duplication
>  since several models would implement the same system reset, machine
>  check, program, etc.
> 
>  iii) model --> exception w/ generic interrupts:
> 
>  Generic interrupt code separate from models. One implementation for
>  each generic interrupt. Models opt-in which interrupts they want
>  (according to the ISA). Models override generic implementation with
>  model-specific ones.
> 
> Option (i) leads to the most code reuse;

Technically, yes, but my experience with this approach is that because
many of the interrupts have similar, but not quite identical behaviour
in different models, the "common" interrupt path is so littered with
special cases and per-model tests that they become very hard to read.
It also makes things fragile, because it's difficult to refactor or
update things for one model without risking breaking some other model
for an obscure CPU variant you barely know and aren't thinking about
at the time.

Basically the reason I think things look at mess at the moment, is
that historically we've tried to share the implementation for things
that aren't quite similar enough for that to really work well.

> (ii) makes each model and its
> interrupts into one comprehensive unit; (iii) avoids duplication of the
> generic code.

Note that with model-then-exception it's still possible and encouraged
for the model specific code to call back to a common "library"
implementation for things that really do have the same logic between
models.  For simple things like system reset the per-model versions
could well just be stubs calling back to generic code.

But for the complex MMU interrupts, which have heaps of variants and
different cases, I think model-then-exception will make following the
logic much easier.

> 
> >> +
> >> +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 {
> >
> > Having an info/dispatch structure for each vector makes sense..
> >
> >> +    Object parent;
> >
> > ..but making it a QOM object really seems like overkill.  In fact
> > making it a QOM object at least somewhat exposes the internal
> > structure to the user via QMP, which I really don't think we want to
> > do.
> 
> I'm using QOM code mainly to facilitate the id->function mapping. I'll
> remove the QOM layer and implement my own.
> 
> >> +
> >> +    int id;
> >> +    const char *name;
> >> +    target_ulong addr;
> >> +    ppc_intr_fn_t setup_regs;
> >> +};
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2021-06-15  6:27 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-01 21:46 [RFC PATCH 0/5] target/ppc: powerpc_excp improvements - part I Fabiano Rosas
2021-06-01 21:46 ` [RFC PATCH 1/5] target/ppc: powerpc_excp: Move lpes code to where it is used Fabiano Rosas
2021-06-02  7:37   ` David Gibson
2021-06-01 21:46 ` [RFC PATCH 2/5] target/ppc: powerpc_excp: Remove dump_syscall_vectored Fabiano Rosas
2021-06-02  7:37   ` David Gibson
2021-06-01 21:46 ` [RFC PATCH 3/5] target/ppc: powerpc_excp: Consolidade TLB miss code Fabiano Rosas
2021-06-02  7:37   ` David Gibson
2021-06-01 21:46 ` [RFC PATCH 4/5] target/ppc: powerpc_excp: Standardize arguments to interrupt code Fabiano Rosas
2021-06-07  3:55   ` David Gibson
2021-06-01 21:46 ` [RFC PATCH 5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM Fabiano Rosas
2021-06-02 12:31   ` Bruno Piazera Larsen
2021-06-02 15:11     ` Fabiano Rosas
2021-06-07  3:58   ` David Gibson
2021-06-07 16:54     ` Fabiano Rosas
2021-06-15  5:56       ` David Gibson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.