All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 00/12] target/ppc: powerpc_excp improvements
@ 2021-12-20 18:18 Fabiano Rosas
  2021-12-20 18:18 ` [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly Fabiano Rosas
                   ` (12 more replies)
  0 siblings, 13 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

This changed a lot since v1, basically what remains is the idea that
we want to have some sort of array of interrupts and some sort of
separation between processors.

At the end of this series we'll have:

- One file with all interrupt implementations (interrupts.c);

- Separate files for each major group of CPUs (book3s, booke,
  32bits). Only interrupt code for now, but we could bring pieces of
  cpu_init into them;

- Four separate interrupt arrays, one for each of the above groups
  plus KVM.

- powerpc_excp calls into the individual files and from there we
  dispatch according to what is available in the interrupts array.

Please comment,

Thanks.

v1:
https://lists.nongnu.org/archive/html/qemu-ppc/2021-06/msg00026.html

Fabiano Rosas (12):
  target/ppc: powerpc_excp: Set alternate SRRs directly
  target/ppc: powerpc_excp: Set vector earlier
  target/ppc: powerpc_excp: Move system call vectored code together
  target/ppc: powerpc_excp: Stop passing excp_model around
  target/ppc: powerpc_excp: Standardize arguments to interrupt code
  target/ppc: Extract interrupt routines into a new file
  target/ppc: Introduce PPCInterrupt
  target/ppc: Remove unimplemented interrupt code
  target/ppc: Use common code for Hypervisor interrupts
  target/ppc: Split powerpc_excp into book3s, booke and 32 bit
  target/ppc: Create new files for book3s, booke and ppc32 exception
    code
  target/ppc: Do not enable all interrupts when running KVM

 target/ppc/cpu.h         |   2 +
 target/ppc/excp_helper.c | 862 ++-------------------------------------
 target/ppc/interrupts.c  | 521 +++++++++++++++++++++++
 target/ppc/intr-book3s.c | 383 +++++++++++++++++
 target/ppc/intr-booke.c  | 152 +++++++
 target/ppc/intr-ppc32.c  | 159 ++++++++
 target/ppc/meson.build   |   4 +
 target/ppc/ppc_intr.h    |  62 +++
 target/ppc/tcg-stub.c    |   6 +
 9 files changed, 1323 insertions(+), 828 deletions(-)
 create mode 100644 target/ppc/interrupts.c
 create mode 100644 target/ppc/intr-book3s.c
 create mode 100644 target/ppc/intr-booke.c
 create mode 100644 target/ppc/intr-ppc32.c
 create mode 100644 target/ppc/ppc_intr.h

-- 
2.33.1



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

* [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
@ 2021-12-20 18:18 ` Fabiano Rosas
  2021-12-21 23:32   ` Richard Henderson
                     ` (2 more replies)
  2021-12-20 18:18 ` [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier Fabiano Rosas
                   ` (11 subsequent siblings)
  12 siblings, 3 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

There are currently only two interrupts that use alternate SRRs, so
let them write to them directly during the setup code.

No functional change intented.

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

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f90e616aac..8b9c6bc5a8 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -298,7 +298,7 @@ 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;
+    int srr0, srr1, lev = -1;
 
     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
@@ -319,8 +319,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     /* target registers */
     srr0 = SPR_SRR0;
     srr1 = SPR_SRR1;
-    asrr0 = -1;
-    asrr1 = -1;
 
     /*
      * check for special resume at 0x100 from doze/nap/sleep/winkle on
@@ -410,8 +408,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             /* 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;
+
+            env->spr[SPR_BOOKE_CSRR0] = env->nip;
+            env->spr[SPR_BOOKE_CSRR1] = msr;
             break;
         default:
             break;
@@ -570,8 +569,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             /* 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;
+
+            env->spr[SPR_BOOKE_CSRR0] = env->nip;
+            env->spr[SPR_BOOKE_CSRR1] = msr;
+
             /* DBSR already modified by caller */
         } else {
             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
@@ -838,14 +839,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 
     vector |= env->excp_prefix;
 
-    /* If any alternate SRR register are defined, duplicate saved values */
-    if (asrr0 != -1) {
-        env->spr[asrr0] = env->nip;
-    }
-    if (asrr1 != -1) {
-        env->spr[asrr1] = msr;
-    }
-
 #if defined(TARGET_PPC64)
     if (excp_model == POWERPC_EXCP_BOOKE) {
         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
-- 
2.33.1



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

* [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
  2021-12-20 18:18 ` [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly Fabiano Rosas
@ 2021-12-20 18:18 ` Fabiano Rosas
  2021-12-22  6:48   ` Cédric Le Goater
  2021-12-24  0:11   ` Richard Henderson
  2021-12-20 18:18 ` [RFC v2 03/12] target/ppc: powerpc_excp: Move system call vectored code together Fabiano Rosas
                   ` (10 subsequent siblings)
  12 siblings, 2 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

None of the interrupt setup code touches 'vector', so we can move it
earlier in the function. This will allow us to later move the System
Call Vectored setup that is on the top level into the
POWERPC_EXCP_SYSCALL_VECTORED code block.

This patch also moves the verification for when 'excp' does not have
an address associated with it. We now bail a little earlier when that
is the case. This should not cause any visible effects.

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

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 8b9c6bc5a8..14fd0213a0 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -352,6 +352,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     }
 #endif
 
+    vector = env->excp_vectors[excp];
+    if (vector == (target_ulong)-1ULL) {
+        cpu_abort(cs, "Raised an exception without defined vector %d\n",
+                  excp);
+    }
+
+    vector |= env->excp_prefix;
+
     switch (excp) {
     case POWERPC_EXCP_NONE:
         /* Should never happen */
@@ -831,14 +839,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     }
 #endif
 
-    vector = env->excp_vectors[excp];
-    if (vector == (target_ulong)-1ULL) {
-        cpu_abort(cs, "Raised an exception without defined vector %d\n",
-                  excp);
-    }
-
-    vector |= env->excp_prefix;
-
 #if defined(TARGET_PPC64)
     if (excp_model == POWERPC_EXCP_BOOKE) {
         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
-- 
2.33.1



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

* [RFC v2 03/12] target/ppc: powerpc_excp: Move system call vectored code together
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
  2021-12-20 18:18 ` [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly Fabiano Rosas
  2021-12-20 18:18 ` [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier Fabiano Rosas
@ 2021-12-20 18:18 ` Fabiano Rosas
  2021-12-22  6:48   ` Cédric Le Goater
  2021-12-24  0:12   ` Richard Henderson
  2021-12-20 18:18 ` [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around Fabiano Rosas
                   ` (9 subsequent siblings)
  12 siblings, 2 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

Now that 'vector' is known before calling the interrupt-specific setup
code, we can move all of the scv setup into one place.

No functional change intended.

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

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 14fd0213a0..7bdc1e8410 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -549,6 +549,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         env->nip += 4;
         new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+
+        vector += lev * 0x20;
+
+        env->lr = env->nip;
+        env->ctr = msr;
         break;
     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
@@ -862,14 +867,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 
         /* Save MSR */
         env->spr[srr1] = msr;
-
-#if defined(TARGET_PPC64)
-    } else {
-        vector += lev * 0x20;
-
-        env->lr = env->nip;
-        env->ctr = msr;
-#endif
     }
 
     /* This can update new_msr and vector if AIL applies */
-- 
2.33.1



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

* [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (2 preceding siblings ...)
  2021-12-20 18:18 ` [RFC v2 03/12] target/ppc: powerpc_excp: Move system call vectored code together Fabiano Rosas
@ 2021-12-20 18:18 ` Fabiano Rosas
  2021-12-22  6:48   ` Cédric Le Goater
                     ` (2 more replies)
  2021-12-20 18:18 ` [RFC v2 05/12] target/ppc: powerpc_excp: Standardize arguments to interrupt code Fabiano Rosas
                   ` (8 subsequent siblings)
  12 siblings, 3 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

We can just access it directly in powerpc_excp.

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

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 7bdc1e8410..45641f6d1d 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -293,10 +293,11 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
  * Note that this function should be greatly optimized when called
  * with a constant excp, from ppc_hw_interrupt
  */
-static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
+static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
 {
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
+    int excp_model = env->excp_model;
     target_ulong msr, new_msr, vector;
     int srr0, srr1, lev = -1;
 
@@ -878,9 +879,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 void ppc_cpu_do_interrupt(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
 
-    powerpc_excp(cpu, env->excp_model, cs->exception_index);
+    powerpc_excp(cpu, cs->exception_index);
 }
 
 static void ppc_hw_interrupt(CPUPPCState *env)
@@ -891,20 +891,20 @@ static void ppc_hw_interrupt(CPUPPCState *env)
     /* External reset */
     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
-        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
+        powerpc_excp(cpu, POWERPC_EXCP_RESET);
         return;
     }
     /* Machine check exception */
     if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
-        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
+        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
         return;
     }
 #if 0 /* TODO */
     /* External debug exception */
     if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
-        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
+        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
         return;
     }
 #endif
@@ -924,7 +924,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
         if ((async_deliver || msr_hv == 0) && hdice) {
             /* HDEC clears on delivery */
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
+            powerpc_excp(cpu, POWERPC_EXCP_HDECR);
             return;
         }
     }
@@ -934,7 +934,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
         /* LPCR will be clear when not supported so this will work */
         bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
         if ((async_deliver || msr_hv == 0) && hvice) {
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT);
+            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
             return;
         }
     }
@@ -946,14 +946,14 @@ static void ppc_hw_interrupt(CPUPPCState *env)
         /* HEIC blocks delivery to the hypervisor */
         if ((async_deliver && !(heic && msr_hv && !msr_pr)) ||
             (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
+            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
             return;
         }
     }
     if (msr_ce != 0) {
         /* External critical interrupt */
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
+            powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
             return;
         }
     }
@@ -961,24 +961,24 @@ static void ppc_hw_interrupt(CPUPPCState *env)
         /* Watchdog timer on embedded PowerPC */
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
+            powerpc_excp(cpu, POWERPC_EXCP_WDT);
             return;
         }
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
+            powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
             return;
         }
         /* Fixed interval timer on embedded PowerPC */
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
+            powerpc_excp(cpu, POWERPC_EXCP_FIT);
             return;
         }
         /* Programmable interval timer on embedded PowerPC */
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
+            powerpc_excp(cpu, POWERPC_EXCP_PIT);
             return;
         }
         /* Decrementer exception */
@@ -986,32 +986,32 @@ static void ppc_hw_interrupt(CPUPPCState *env)
             if (ppc_decr_clear_on_delivery(env)) {
                 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
             }
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
+            powerpc_excp(cpu, POWERPC_EXCP_DECR);
             return;
         }
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
             if (is_book3s_arch2x(env)) {
-                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR);
+                powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
             } else {
-                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
+                powerpc_excp(cpu, POWERPC_EXCP_DOORI);
             }
             return;
         }
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
+            powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
             return;
         }
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
+            powerpc_excp(cpu, POWERPC_EXCP_PERFM);
             return;
         }
         /* Thermal interrupt */
         if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
-            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
+            powerpc_excp(cpu, POWERPC_EXCP_THERM);
             return;
         }
     }
@@ -1036,9 +1036,8 @@ static void ppc_hw_interrupt(CPUPPCState *env)
 void ppc_cpu_do_system_reset(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
-    CPUPPCState *env = &cpu->env;
 
-    powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
+    powerpc_excp(cpu, POWERPC_EXCP_RESET);
 }
 
 void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
-- 
2.33.1



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

* [RFC v2 05/12] target/ppc: powerpc_excp: Standardize arguments to interrupt code
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (3 preceding siblings ...)
  2021-12-20 18:18 ` [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around Fabiano Rosas
@ 2021-12-20 18:18 ` Fabiano Rosas
  2021-12-25  6:35   ` David Gibson
  2021-12-20 18:18 ` [RFC v2 06/12] target/ppc: Extract interrupt routines into a new file Fabiano Rosas
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

In preparation to moving the interrupt code into separate functions,
create a PPCIntrArgs structure to serve as a consistent API.

No functional change intended.

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

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 45641f6d1d..f478ff8a87 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -164,7 +164,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;
@@ -241,9 +241,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 {
         /*
@@ -251,15 +251,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;
@@ -272,9 +272,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;
@@ -289,6 +289,15 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
     check_tlb_flush(env, false);
 }
 
+typedef struct PPCIntrArgs {
+    target_ulong nip;
+    target_ulong msr;
+    target_ulong new_nip;
+    target_ulong new_msr;
+    int sprn_srr0;
+    int sprn_srr1;
+} PPCIntrArgs;
+
 /*
  * Note that this function should be greatly optimized when called
  * with a constant excp, from ppc_hw_interrupt
@@ -298,35 +307,35 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     int excp_model = env->excp_model;
-    target_ulong msr, new_msr, vector;
-    int srr0, srr1, lev = -1;
+    PPCIntrArgs 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
      */
-    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;
+    regs.sprn_srr0 = SPR_SRR0;
+    regs.sprn_srr1 = SPR_SRR1;
 
     /*
      * 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);
     }
 
     /*
@@ -353,13 +362,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
     }
 #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;
 
     switch (excp) {
     case POWERPC_EXCP_NONE:
@@ -368,12 +377,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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;
@@ -401,25 +410,25 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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;
+            regs.sprn_srr0 = SPR_BOOKE_MCSRR0;
+            regs.sprn_srr1 = SPR_BOOKE_MCSRR1;
 
-            env->spr[SPR_BOOKE_CSRR0] = env->nip;
-            env->spr[SPR_BOOKE_CSRR1] = msr;
+            env->spr[SPR_BOOKE_CSRR0] = regs.nip;
+            env->spr[SPR_BOOKE_CSRR1] = regs.msr;
             break;
         default:
             break;
@@ -429,8 +438,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
         trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
         break;
     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
-        trace_ppc_excp_isi(msr, env->nip);
-        msr |= env->error_code;
+        trace_ppc_excp_isi(regs.msr, regs.nip);
+        regs.msr |= env->error_code;
         break;
     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
     {
@@ -460,10 +469,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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 */
@@ -495,20 +504,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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:
-            trace_ppc_excp_inval(env->nip);
-            msr |= 0x00080000;
+            trace_ppc_excp_inval(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:
@@ -529,9 +538,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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) {
@@ -540,21 +552,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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);
 
-        vector += lev * 0x20;
+        regs.new_nip += lev * 0x20;
 
-        env->lr = env->nip;
-        env->ctr = msr;
+        env->lr = regs.nip;
+        env->ctr = regs.msr;
         break;
     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
@@ -568,8 +581,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
         trace_ppc_excp_print("WDT");
         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;
@@ -581,12 +594,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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;
-
-            env->spr[SPR_BOOKE_CSRR0] = env->nip;
-            env->spr[SPR_BOOKE_CSRR1] = msr;
+            regs.sprn_srr0 = SPR_BOOKE_DSRR0;
+            regs.sprn_srr1 = SPR_BOOKE_DSRR1;
 
+            env->spr[SPR_BOOKE_CSRR0] = regs.nip;
+            env->spr[SPR_BOOKE_CSRR1] = regs.msr;
             /* DBSR already modified by caller */
         } else {
             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
@@ -615,22 +627,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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 "
@@ -643,7 +655,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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        */
@@ -652,10 +664,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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               */
@@ -667,10 +679,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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 +709,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
         case POWERPC_EXCP_603:
         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 +743,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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;
         default:
             cpu_abort(cs, "Invalid TLB miss exception\n");
@@ -800,11 +812,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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);
         }
@@ -816,32 +828,32 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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
 
@@ -849,31 +861,32 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
     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;
     }
 
-    /* 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.33.1



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

* [RFC v2 06/12] target/ppc: Extract interrupt routines into a new file
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (4 preceding siblings ...)
  2021-12-20 18:18 ` [RFC v2 05/12] target/ppc: powerpc_excp: Standardize arguments to interrupt code Fabiano Rosas
@ 2021-12-20 18:18 ` Fabiano Rosas
  2021-12-20 18:18 ` [RFC v2 07/12] target/ppc: Introduce PPCInterrupt Fabiano Rosas
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

Extract the interrupt setup routines into their own functions and put
everything in a separate file. These routines will be made independent
of exception model in the following patches. This change is just to
facilitate the review.

No funcional change intended.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/excp_helper.c | 434 ++++----------------------
 target/ppc/interrupts.c  | 645 +++++++++++++++++++++++++++++++++++++++
 target/ppc/meson.build   |   1 +
 target/ppc/ppc_intr.h    |  61 ++++
 4 files changed, 769 insertions(+), 372 deletions(-)
 create mode 100644 target/ppc/interrupts.c
 create mode 100644 target/ppc/ppc_intr.h

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f478ff8a87..bc20499b6c 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -23,6 +23,10 @@
 #include "internal.h"
 #include "helper_regs.h"
 
+#if !defined(CONFIG_USER_ONLY)
+#include "ppc_intr.h"
+#endif
+
 #include "trace.h"
 
 #ifdef CONFIG_TCG
@@ -30,39 +34,10 @@
 #include "exec/cpu_ldst.h"
 #endif
 
-/* #define DEBUG_SOFTWARE_TLB */
-
 /*****************************************************************************/
 /* Exception processing */
 #if !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)
 {
@@ -289,15 +264,6 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
     check_tlb_flush(env, false);
 }
 
-typedef struct PPCIntrArgs {
-    target_ulong nip;
-    target_ulong msr;
-    target_ulong new_nip;
-    target_ulong new_msr;
-    int sprn_srr0;
-    int sprn_srr1;
-} PPCIntrArgs;
-
 /*
  * Note that this function should be greatly optimized when called
  * with a constant excp, from ppc_hw_interrupt
@@ -308,7 +274,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
     CPUPPCState *env = &cpu->env;
     int excp_model = env->excp_model;
     PPCIntrArgs regs;
-    int lev = -1;
+    bool ignore = false;
 
     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
@@ -374,442 +340,166 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int 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;
-        }
+        ppc_intr_critical(cpu, &regs, &ignore);
         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;
-
-            env->spr[SPR_BOOKE_CSRR0] = regs.nip;
-            env->spr[SPR_BOOKE_CSRR1] = regs.msr;
-            break;
-        default:
-            break;
-        }
+        ppc_intr_machine_check(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
-        trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+        ppc_intr_data_storage(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
-        trace_ppc_excp_isi(regs.msr, regs.nip);
-        regs.msr |= env->error_code;
+        ppc_intr_insn_storage(cpu, &regs, &ignore);
         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);
-        }
+        ppc_intr_external(cpu, &regs, &ignore);
         break;
-    }
     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;
+        ppc_intr_alignment(cpu, &regs, &ignore);
         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) {
-                trace_ppc_excp_fp_ignore();
-                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:
-            trace_ppc_excp_inval(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_intr_program(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
-        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);
-            return;
-        }
-
-        if (lev == 1) {
-            regs.new_msr |= (target_ulong)MSR_HVB;
-        }
+        ppc_intr_system_call(cpu, &regs, &ignore);
         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);
-
-        regs.new_nip += lev * 0x20;
-
-        env->lr = regs.nip;
-        env->ctr = regs.msr;
+        ppc_intr_system_call_vectored(cpu, &regs, &ignore);
         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 */
-        trace_ppc_excp_print("FIT");
+        ppc_intr_fit(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
-        trace_ppc_excp_print("WDT");
-        switch (excp_model) {
-        case POWERPC_EXCP_BOOKE:
-            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
-            break;
-        default:
-            break;
-        }
+        ppc_intr_watchdog(cpu, &regs, &ignore);
         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;
-
-            env->spr[SPR_BOOKE_CSRR0] = regs.nip;
-            env->spr[SPR_BOOKE_CSRR1] = regs.msr;
-            /* DBSR already modified by caller */
-        } else {
-            cpu_abort(cs, "Debug exception triggered on unsupported model\n");
-        }
+        ppc_intr_debug(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_SPEU:   /* SPE/embedded floating-point unavailable/VPU  */
-        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+        ppc_intr_spe_unavailable(cpu, &regs, &ignore);
         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;
+        ppc_intr_embedded_fp_data(cpu, &regs, &ignore);
         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;
+        ppc_intr_embedded_fp_round(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "Performance counter exception is not implemented yet !\n");
+        ppc_intr_embedded_perf_monitor(cpu, &regs, &ignore);
         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;
+        ppc_intr_embedded_doorbell_crit(cpu, &regs, &ignore);
         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);
-            }
-        }
+        ppc_intr_system_reset(cpu, &regs, &ignore);
         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 */
+        ppc_intr_hv_insn_storage(cpu, &regs, &ignore);
+        break;
     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
+        ppc_intr_hv_decrementer(cpu, &regs, &ignore);
+        break;
     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
+        ppc_intr_hv_data_storage(cpu, &regs, &ignore);
+        break;
     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
+        ppc_intr_hv_data_segment(cpu, &regs, &ignore);
+        break;
     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
+        ppc_intr_hv_insn_segment(cpu, &regs, &ignore);
+        break;
     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
+        ppc_intr_hv_doorbell(cpu, &regs, &ignore);
+        break;
     case POWERPC_EXCP_HV_EMU:
+        ppc_intr_hv_emulation(cpu, &regs, &ignore);
+        break;
     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);
+        ppc_intr_hv_virtualization(cpu, &regs, &ignore);
         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
+        ppc_intr_facility_unavail(cpu, &regs, &ignore);
         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
+        ppc_intr_hv_facility_unavail(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
-        trace_ppc_excp_print("PIT");
+        ppc_intr_programmable_timer(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_IO:        /* IO error exception                       */
-        /* XXX: TODO */
-        cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
+        ppc_intr_io_error(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
-        /* XXX: TODO */
-        cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
+        ppc_intr_run_mode(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
-        /* XXX: TODO */
-        cpu_abort(cs, "602 emulation trap exception "
-                  "is not implemented yet !\n");
+        ppc_intr_emulation(cpu, &regs, &ignore);
         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_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;
-        default:
-            cpu_abort(cs, "Invalid TLB miss exception\n");
-            break;
-        }
+        ppc_intr_tlb_miss(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
-        /* XXX: TODO */
-        cpu_abort(cs, "Floating point assist exception "
-                  "is not implemented yet !\n");
+        ppc_intr_fpa(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
-        /* XXX: TODO */
-        cpu_abort(cs, "DABR exception is not implemented yet !\n");
+        ppc_intr_dabr(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
-        /* XXX: TODO */
-        cpu_abort(cs, "IABR exception is not implemented yet !\n");
+        ppc_intr_iabr(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_SMI:       /* System management interrupt              */
-        /* XXX: TODO */
-        cpu_abort(cs, "SMI exception is not implemented yet !\n");
+        ppc_intr_smi(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
-        /* XXX: TODO */
-        cpu_abort(cs, "Thermal management exception "
-                  "is not implemented yet !\n");
+        ppc_intr_therm(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "Performance counter exception is not implemented yet !\n");
+        ppc_intr_perfm(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
-        /* XXX: TODO */
-        cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
+        ppc_intr_vpua(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "970 soft-patch exception is not implemented yet !\n");
+        ppc_intr_softp(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "970 maintenance exception is not implemented yet !\n");
+        ppc_intr_maint(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
-        /* XXX: TODO */
-        cpu_abort(cs, "Maskable external exception "
-                  "is not implemented yet !\n");
+        ppc_intr_mextbr(cpu, &regs, &ignore);
         break;
     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
-        /* XXX: TODO */
-        cpu_abort(cs, "Non maskable external exception "
-                  "is not implemented yet !\n");
+        ppc_intr_nmextbr(cpu, &regs, &ignore);
         break;
     default:
-    excp_invalid:
         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
         break;
     }
 
+    if (ignore) {
+        /* No further setup is needed for this interrupt */
+        return;
+    }
+
     /* Sanity check */
     if (!(env->msr_mask & MSR_HVB)) {
         if (regs.new_msr & MSR_HVB) {
diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
new file mode 100644
index 0000000000..0168ce03a7
--- /dev/null
+++ b/target/ppc/interrupts.c
@@ -0,0 +1,645 @@
+/*
+ * PowerPC interrupt emulation.
+ *
+ * Copyright (C) 2021 IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "ppc_intr.h"
+#include "trace.h"
+
+/* for hreg_swap_gpr_tgpr */
+#include "helper_regs.h"
+
+/* #define DEBUG_SOFTWARE_TLB */
+
+void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int excp_model = env->excp_model;
+
+    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(CPU(cpu), "Invalid PowerPC critical exception. Aborting\n");
+        break;
+    }
+}
+
+void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    int excp_model = env->excp_model;
+
+    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;
+
+        env->spr[SPR_BOOKE_CSRR0] = regs->nip;
+        env->spr[SPR_BOOKE_CSRR1] = regs->msr;
+        break;
+    default:
+        break;
+    }
+}
+
+void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+}
+
+
+void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    trace_ppc_excp_isi(regs->msr, regs->nip);
+
+    regs->msr |= env->error_code;
+}
+
+void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    bool lpes0;
+#if defined(TARGET_PPC64)
+    int excp_model = env->excp_model;
+#endif /* defined(TARGET_PPC64) */
+
+    /*
+     * 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);
+    }
+}
+
+void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *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;
+}
+
+void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *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) {
+            trace_ppc_excp_fp_ignore();
+            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:
+        trace_ppc_excp_inval(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;
+    }
+}
+
+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);
+}
+
+void ppc_intr_system_call(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int 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;
+    }
+}
+
+void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int 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;
+}
+
+void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* FIT on 4xx */
+    trace_ppc_excp_print("FIT");
+};
+
+void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int excp_model = env->excp_model;
+
+    trace_ppc_excp_print("WDT");
+    switch (excp_model) {
+    case POWERPC_EXCP_BOOKE:
+        regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+        break;
+    default:
+        break;
+    }
+}
+
+void ppc_intr_debug(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    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;
+
+        env->spr[SPR_BOOKE_CSRR0] = regs->nip;
+        env->spr[SPR_BOOKE_CSRR1] = regs->msr;
+        /* DBSR already modified by caller */
+    } else {
+        cpu_abort(CPU(cpu), "Debug exception triggered on unsupported model\n");
+    }
+}
+
+void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+
+void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "Embedded floating point data exception "
+              "is not implemented yet !\n");
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+
+void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "Embedded floating point round exception "
+              "is not implemented yet !\n");
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+
+void ppc_intr_embedded_perf_monitor(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu),
+              "Performance counter exception is not implemented yet !\n");
+}
+
+void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+    regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+}
+
+void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    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(CPU(cpu), "Trying to deliver power-saving system reset "
+                      "exception with no HV support\n");
+        }
+    }
+}
+
+void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    regs->msr |= env->error_code;
+
+    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);
+}
+
+void ppc_intr_hv_decrementer(PowerPCCPU *cpu, PPCIntrArgs *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);
+}
+
+void ppc_intr_hv_data_storage(PowerPCCPU *cpu, PPCIntrArgs *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);
+}
+
+void ppc_intr_hv_data_segment(PowerPCCPU *cpu, PPCIntrArgs *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);
+}
+
+void ppc_intr_hv_insn_segment(PowerPCCPU *cpu, PPCIntrArgs *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);
+}
+
+void ppc_intr_hv_doorbell(PowerPCCPU *cpu, PPCIntrArgs *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);
+}
+
+void ppc_intr_hv_emulation(PowerPCCPU *cpu, PPCIntrArgs *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);
+}
+
+void ppc_intr_hv_virtualization(PowerPCCPU *cpu, PPCIntrArgs *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);
+}
+
+void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+#ifdef TARGET_PPC64
+    CPUPPCState *env = &cpu->env;
+    env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
+#endif
+}
+
+void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+#ifdef TARGET_PPC64
+    CPUPPCState *env = &cpu->env;
+    env->spr[SPR_FSCR] |= ((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
+}
+
+void ppc_intr_programmable_timer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    trace_ppc_excp_print("PIT");
+}
+
+void ppc_intr_io_error(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "601 IO error exception is not implemented yet !\n");
+}
+
+void ppc_intr_run_mode(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "601 run mode exception is not implemented yet !\n");
+}
+
+void ppc_intr_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "602 emulation trap exception is not implemented yet !\n");
+}
+
+void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int excp_model = env->excp_model;
+
+    switch (excp_model) {
+    case POWERPC_EXCP_602:
+    case POWERPC_EXCP_603:
+    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[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];
+            }
+
+            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;
+    default:
+        cpu_abort(CPU(cpu), "Invalid instruction TLB miss exception\n");
+        break;
+    }
+}
+
+void ppc_intr_fpa(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "Floating point assist exception "
+              "is not implemented yet !\n");
+}
+
+void ppc_intr_dabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "DABR exception is not implemented yet !\n");
+}
+
+void ppc_intr_iabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "IABR exception is not implemented yet !\n");
+}
+
+void ppc_intr_smi(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "SMI exception is not implemented yet !\n");
+}
+
+void ppc_intr_therm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "Thermal management exception "
+              "is not implemented yet !\n");
+}
+
+void ppc_intr_perfm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu),
+              "Performance counter exception is not implemented yet !\n");
+}
+
+void ppc_intr_vpua(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "VPU assist exception is not implemented yet !\n");
+}
+
+void ppc_intr_softp(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu),
+              "970 soft-patch exception is not implemented yet !\n");
+}
+
+void ppc_intr_maint(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu),
+              "970 maintenance exception is not implemented yet !\n");
+}
+
+void ppc_intr_mextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "Maskable external exception "
+              "is not implemented yet !\n");
+}
+
+void ppc_intr_nmextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    /* XXX: TODO */
+    cpu_abort(CPU(cpu), "Non maskable external exception "
+              "is not implemented yet !\n");
+}
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index a49a8911e0..53b8e0a98e 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -39,6 +39,7 @@ ppc_softmmu_ss.add(files(
   'mmu-hash32.c',
   'mmu_common.c',
   'monitor.c',
+  'interrupts.c',
 ))
 ppc_softmmu_ss.add(when: 'CONFIG_TCG', if_true: files(
   'mmu_helper.c',
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
new file mode 100644
index 0000000000..25c11710f9
--- /dev/null
+++ b/target/ppc/ppc_intr.h
@@ -0,0 +1,61 @@
+#ifndef PPC_INTR_H
+#define PPC_INTR_H
+
+typedef struct PPCIntrArgs PPCIntrArgs;
+
+struct PPCIntrArgs {
+    target_ulong nip;
+    target_ulong msr;
+    target_ulong new_nip;
+    target_ulong new_msr;
+    int sprn_srr0;
+    int sprn_srr1;
+};
+
+void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_dabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_debug(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_embedded_perf_monitor(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_fpa(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_data_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_decrementer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_doorbell(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_insn_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_virtualization(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_iabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_io_error(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_maint(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_mextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_nmextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_noop(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_perfm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_programmable_timer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_run_mode(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_smi(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_softp(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_system_call(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_therm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_vpua(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+
+#endif /* PPC_INTR_H */
-- 
2.33.1



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

* [RFC v2 07/12] target/ppc: Introduce PPCInterrupt
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (5 preceding siblings ...)
  2021-12-20 18:18 ` [RFC v2 06/12] target/ppc: Extract interrupt routines into a new file Fabiano Rosas
@ 2021-12-20 18:18 ` Fabiano Rosas
  2021-12-20 18:18 ` [RFC v2 08/12] target/ppc: Remove unimplemented interrupt code Fabiano Rosas
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

Now that each interrupt has its own routine, we can have an array of
interrupts and drop the big switch in powerpc_excp(). That will allow
us to later split the interrupt list between the various powerpc
implementations (book3s, booke, 32bit, kvm, etc).

No functional change.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/excp_helper.c | 172 +++----------------------------
 target/ppc/interrupts.c  | 212 +++++++++++++++++++++++++++++++++++++++
 target/ppc/ppc_intr.h    |   9 ++
 3 files changed, 236 insertions(+), 157 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index bc20499b6c..4f8a6c4ec8 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -31,7 +31,6 @@
 
 #ifdef CONFIG_TCG
 #include "exec/helper-proto.h"
-#include "exec/cpu_ldst.h"
 #endif
 
 /*****************************************************************************/
@@ -274,11 +273,17 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
     CPUPPCState *env = &cpu->env;
     int excp_model = env->excp_model;
     PPCIntrArgs regs;
+    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) {
+        /* Should never happen */
+        return;
+    }
+
     /* new srr1 value excluding must-be-zero bits */
     if (excp_model == POWERPC_EXCP_BOOKE) {
         regs.msr = env->msr;
@@ -336,165 +341,18 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
 
     regs.new_nip |= env->excp_prefix;
 
-    switch (excp) {
-    case POWERPC_EXCP_NONE:
-        /* Should never happen */
-        return;
-
-    case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
-        ppc_intr_critical(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
-        ppc_intr_machine_check(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
-        ppc_intr_data_storage(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
-        ppc_intr_insn_storage(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
-        ppc_intr_external(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
-        ppc_intr_alignment(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
-        ppc_intr_program(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
-        ppc_intr_system_call(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
-        ppc_intr_system_call_vectored(cpu, &regs, &ignore);
-        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           */
-        ppc_intr_fit(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
-        ppc_intr_watchdog(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
-    case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
-        break;
-    case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
-        ppc_intr_debug(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_SPEU:   /* SPE/embedded floating-point unavailable/VPU  */
-        ppc_intr_spe_unavailable(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
-        ppc_intr_embedded_fp_data(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
-        ppc_intr_embedded_fp_round(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
-        ppc_intr_embedded_perf_monitor(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
-        break;
-    case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
-        ppc_intr_embedded_doorbell_crit(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_RESET:     /* System reset exception                   */
-        ppc_intr_system_reset(cpu, &regs, &ignore);
-        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 */
-        ppc_intr_hv_insn_storage(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
-        ppc_intr_hv_decrementer(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
-        ppc_intr_hv_data_storage(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
-        ppc_intr_hv_data_segment(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
-        ppc_intr_hv_insn_segment(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
-        ppc_intr_hv_doorbell(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_HV_EMU:
-        ppc_intr_hv_emulation(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
-        ppc_intr_hv_virtualization(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
-    case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
-    case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
-        ppc_intr_facility_unavail(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
-        ppc_intr_hv_facility_unavail(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
-        ppc_intr_programmable_timer(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_IO:        /* IO error exception                       */
-        ppc_intr_io_error(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
-        ppc_intr_run_mode(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
-        ppc_intr_emulation(cpu, &regs, &ignore);
-        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                      */
-        ppc_intr_tlb_miss(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
-        ppc_intr_fpa(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
-        ppc_intr_dabr(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
-        ppc_intr_iabr(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_SMI:       /* System management interrupt              */
-        ppc_intr_smi(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
-        ppc_intr_therm(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
-        ppc_intr_perfm(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
-        ppc_intr_vpua(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
-        ppc_intr_softp(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
-        ppc_intr_maint(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
-        ppc_intr_mextbr(cpu, &regs, &ignore);
-        break;
-    case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
-        ppc_intr_nmextbr(cpu, &regs, &ignore);
-        break;
-    default:
+    intr = &interrupts[excp];
+    if (!intr->name) {
         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
-        break;
     }
 
+    if (!intr->fn) {
+        cpu_abort(cs, "%s exception is not implemented yet !\n", intr->name);
+    }
+
+    /* Setup interrupt-specific registers before dispatching */
+    intr->fn(cpu, &regs, &ignore);
+
     if (ignore) {
         /* No further setup is needed for this interrupt */
         return;
diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
index 0168ce03a7..2dd3815167 100644
--- a/target/ppc/interrupts.c
+++ b/target/ppc/interrupts.c
@@ -17,6 +17,10 @@
 
 /* #define DEBUG_SOFTWARE_TLB */
 
+void ppc_intr_noop(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+}
+
 void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
     CPUPPCState *env = &cpu->env;
@@ -643,3 +647,211 @@ void ppc_intr_nmextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     cpu_abort(CPU(cpu), "Non maskable external exception "
               "is not implemented yet !\n");
 }
+
+PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
+    [POWERPC_EXCP_ALIGN] = {
+        "Alignment", ppc_intr_alignment
+    },
+
+    [POWERPC_EXCP_CRITICAL] = {
+        "Critical input", ppc_intr_critical
+    },
+
+    [POWERPC_EXCP_DABR] = {
+        "Data address breakpoint", ppc_intr_dabr
+    },
+
+    [POWERPC_EXCP_DEBUG] = {
+        "Debug", ppc_intr_debug
+    },
+
+    [POWERPC_EXCP_DLTLB] = {
+        "Data load TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_DOORCI] = {
+        "Embedded doorbell critical", ppc_intr_embedded_doorbell_crit
+    },
+
+    [POWERPC_EXCP_DSI] = {
+        "Data storage", ppc_intr_data_storage
+    },
+
+    [POWERPC_EXCP_DSTLB] = {
+        "Data store TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_EFPDI] = {
+        "Embedded floating-point data", ppc_intr_embedded_fp_data
+    },
+
+    [POWERPC_EXCP_EFPRI] = {
+        "Embedded floating-point round", ppc_intr_embedded_fp_round
+    },
+
+    [POWERPC_EXCP_EMUL] = {
+        "Emulation trap", ppc_intr_emulation
+    },
+
+    [POWERPC_EXCP_EPERFM] = {
+        "Embedded perf. monitor", ppc_intr_embedded_perf_monitor
+    },
+
+    [POWERPC_EXCP_EXTERNAL] = {
+        "External", ppc_intr_external
+    },
+
+    [POWERPC_EXCP_FIT] = {
+        "Fixed-interval timer", ppc_intr_fit
+    },
+
+    [POWERPC_EXCP_FPA] = {
+        "Floating-point assist", ppc_intr_fpa
+    },
+
+    [POWERPC_EXCP_FU] = {
+        "Facility unavailable", ppc_intr_facility_unavail
+    },
+
+    [POWERPC_EXCP_HDECR] = {
+        "Hypervisor decrementer", ppc_intr_hv_decrementer
+    },
+
+    [POWERPC_EXCP_HDSEG] = {
+        "Hypervisor data segment", ppc_intr_hv_data_segment
+    },
+
+    [POWERPC_EXCP_HDSI] = {
+        "Hypervisor data storage", ppc_intr_hv_data_storage
+    },
+
+    [POWERPC_EXCP_HISEG] = {
+        "Hypervisor insn segment", ppc_intr_hv_insn_segment
+    },
+
+    [POWERPC_EXCP_HISI] = {
+        "Hypervisor instruction storage", ppc_intr_hv_insn_storage
+    },
+
+    [POWERPC_EXCP_HVIRT] = {
+        "Hypervisor virtualization", ppc_intr_hv_virtualization
+    },
+
+    [POWERPC_EXCP_HV_EMU] = {
+        "Hypervisor emulation assist", ppc_intr_hv_emulation
+    },
+
+    [POWERPC_EXCP_HV_FU] = {
+        "Hypervisor facility unavailable" , ppc_intr_hv_facility_unavail
+    },
+
+    [POWERPC_EXCP_IABR] = {
+        "Insn address breakpoint", ppc_intr_iabr
+    },
+
+    [POWERPC_EXCP_IFTLB] = {
+        "Insn fetch TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_IO] = {
+        "IO error", ppc_intr_io_error
+    },
+
+    [POWERPC_EXCP_ISI] = {
+        "Instruction storage", ppc_intr_insn_storage
+    },
+
+    [POWERPC_EXCP_MAINT] = {
+        "Maintenance", ppc_intr_maint
+    },
+
+    [POWERPC_EXCP_MCHECK] = {
+        "Machine check", ppc_intr_machine_check
+    },
+
+    [POWERPC_EXCP_MEXTBR] = {
+        "Maskable external", ppc_intr_mextbr
+    },
+
+    [POWERPC_EXCP_NMEXTBR] = {
+        "Non-maskable external", ppc_intr_nmextbr
+    },
+
+    [POWERPC_EXCP_PERFM] = {
+        "Performance counter", ppc_intr_perfm
+    },
+
+    [POWERPC_EXCP_PIT] = {
+        "Programmable interval timer", ppc_intr_programmable_timer
+    },
+
+    [POWERPC_EXCP_PROGRAM] = {
+        "Program", ppc_intr_program
+    },
+
+    [POWERPC_EXCP_RESET] = {
+        "System reset", ppc_intr_system_reset
+    },
+
+    [POWERPC_EXCP_RUNM] = {
+        "Run mode", ppc_intr_run_mode
+    },
+
+    [POWERPC_EXCP_SDOOR_HV] = {
+        "Hypervisor doorbell", ppc_intr_hv_doorbell
+    },
+
+    [POWERPC_EXCP_SMI] = {
+        "System management", ppc_intr_smi
+    },
+
+    [POWERPC_EXCP_SOFTP] = {
+        "Soft patch", ppc_intr_softp
+    },
+
+    [POWERPC_EXCP_SPEU] = {
+        "SPE/embedded FP unavailable/VPU", ppc_intr_spe_unavailable
+    },
+
+    [POWERPC_EXCP_SYSCALL] = {
+        "System call", ppc_intr_system_call
+    },
+
+    [POWERPC_EXCP_SYSCALL_VECTORED] = {
+        "System call vectored", ppc_intr_system_call_vectored
+    },
+
+    [POWERPC_EXCP_THERM] = {
+        "Thermal management", ppc_intr_therm
+    },
+
+    [POWERPC_EXCP_VPUA] = {
+        "Vector assist", ppc_intr_vpua
+    },
+
+    [POWERPC_EXCP_VPU] = {
+        "Vector unavailable", ppc_intr_facility_unavail
+    },
+
+    [POWERPC_EXCP_VSXU] = {
+        "VSX unavailable", ppc_intr_facility_unavail
+    },
+
+    [POWERPC_EXCP_WDT] = {
+        "Watchdog timer", ppc_intr_watchdog
+    },
+
+    [POWERPC_EXCP_APU]   = { "Aux. processor unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
+    [POWERPC_EXCP_DOORI] = { "Embedded doorbell",          ppc_intr_noop },
+    [POWERPC_EXCP_DSEG]  = { "Data segment",               ppc_intr_noop },
+    [POWERPC_EXCP_DTLB]  = { "Data TLB error",             ppc_intr_noop },
+    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_ISEG]  = { "Instruction segment",        ppc_intr_noop },
+    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
+    [POWERPC_EXCP_TRACE] = { "Trace",                      ppc_intr_noop },
+
+/* Not implemented */
+    [POWERPC_EXCP_HV_MAINT] = { "Hypervisor maintenance" },
+    [POWERPC_EXCP_SDOOR]    = { "Server doorbell" },
+};
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
index 25c11710f9..82372ca227 100644
--- a/target/ppc/ppc_intr.h
+++ b/target/ppc/ppc_intr.h
@@ -2,6 +2,8 @@
 #define PPC_INTR_H
 
 typedef struct PPCIntrArgs PPCIntrArgs;
+typedef struct PPCInterrupt PPCInterrupt;
+typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
 struct PPCIntrArgs {
     target_ulong nip;
@@ -12,6 +14,11 @@ struct PPCIntrArgs {
     int sprn_srr1;
 };
 
+struct PPCInterrupt {
+    const char *name;
+    ppc_intr_fn_t fn;
+};
+
 void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_dabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
@@ -58,4 +65,6 @@ void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_vpua(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
+extern PPCInterrupt interrupts[POWERPC_EXCP_NB];
+
 #endif /* PPC_INTR_H */
-- 
2.33.1



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

* [RFC v2 08/12] target/ppc: Remove unimplemented interrupt code
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (6 preceding siblings ...)
  2021-12-20 18:18 ` [RFC v2 07/12] target/ppc: Introduce PPCInterrupt Fabiano Rosas
@ 2021-12-20 18:18 ` Fabiano Rosas
  2021-12-20 18:19 ` [RFC v2 09/12] target/ppc: Use common code for Hypervisor interrupts Fabiano Rosas
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

Now that PPCInterrupt holds the interrupt name, we can remove all
functions that just emitted the "unimplemented" message and leave that
to the error handling at powerpc_excp():

  if (!intr->fn) {
    cpu_abort(cs, "%s exception is not implemented yet !\n", intr->name);
  }

The user visible change here is that the error message shown when QEMU
tries to dispatch an interrupt that has no implementation will change
from a custom one depending on the exception to a standard one (above)
with the interrupt name as defined in interrupts.c.

(I added ITLBE/DTLBE which were not being handled)

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/interrupts.c | 205 ++++------------------------------------
 target/ppc/ppc_intr.h   |  17 ----
 2 files changed, 19 insertions(+), 203 deletions(-)

diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
index 2dd3815167..1e4fb2d6db 100644
--- a/target/ppc/interrupts.c
+++ b/target/ppc/interrupts.c
@@ -334,33 +334,6 @@ void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     env->spr[SPR_BOOKE_ESR] = ESR_SPV;
 }
 
-void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    CPUPPCState *env = &cpu->env;
-
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "Embedded floating point data exception "
-              "is not implemented yet !\n");
-    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-}
-
-void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    CPUPPCState *env = &cpu->env;
-
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "Embedded floating point round exception "
-              "is not implemented yet !\n");
-    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-}
-
-void ppc_intr_embedded_perf_monitor(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu),
-              "Performance counter exception is not implemented yet !\n");
-}
-
 void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
     regs->sprn_srr0 = SPR_BOOKE_CSRR0;
@@ -499,24 +472,6 @@ void ppc_intr_programmable_timer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignor
     trace_ppc_excp_print("PIT");
 }
 
-void ppc_intr_io_error(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "601 IO error exception is not implemented yet !\n");
-}
-
-void ppc_intr_run_mode(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "601 run mode exception is not implemented yet !\n");
-}
-
-void ppc_intr_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "602 emulation trap exception is not implemented yet !\n");
-}
-
 void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
     CPUPPCState *env = &cpu->env;
@@ -575,79 +530,6 @@ void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     }
 }
 
-void ppc_intr_fpa(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "Floating point assist exception "
-              "is not implemented yet !\n");
-}
-
-void ppc_intr_dabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "DABR exception is not implemented yet !\n");
-}
-
-void ppc_intr_iabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "IABR exception is not implemented yet !\n");
-}
-
-void ppc_intr_smi(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "SMI exception is not implemented yet !\n");
-}
-
-void ppc_intr_therm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "Thermal management exception "
-              "is not implemented yet !\n");
-}
-
-void ppc_intr_perfm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu),
-              "Performance counter exception is not implemented yet !\n");
-}
-
-void ppc_intr_vpua(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "VPU assist exception is not implemented yet !\n");
-}
-
-void ppc_intr_softp(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu),
-              "970 soft-patch exception is not implemented yet !\n");
-}
-
-void ppc_intr_maint(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu),
-              "970 maintenance exception is not implemented yet !\n");
-}
-
-void ppc_intr_mextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "Maskable external exception "
-              "is not implemented yet !\n");
-}
-
-void ppc_intr_nmextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    /* XXX: TODO */
-    cpu_abort(CPU(cpu), "Non maskable external exception "
-              "is not implemented yet !\n");
-}
-
 PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
     [POWERPC_EXCP_ALIGN] = {
         "Alignment", ppc_intr_alignment
@@ -657,10 +539,6 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Critical input", ppc_intr_critical
     },
 
-    [POWERPC_EXCP_DABR] = {
-        "Data address breakpoint", ppc_intr_dabr
-    },
-
     [POWERPC_EXCP_DEBUG] = {
         "Debug", ppc_intr_debug
     },
@@ -681,22 +559,6 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Data store TLB error", ppc_intr_tlb_miss
     },
 
-    [POWERPC_EXCP_EFPDI] = {
-        "Embedded floating-point data", ppc_intr_embedded_fp_data
-    },
-
-    [POWERPC_EXCP_EFPRI] = {
-        "Embedded floating-point round", ppc_intr_embedded_fp_round
-    },
-
-    [POWERPC_EXCP_EMUL] = {
-        "Emulation trap", ppc_intr_emulation
-    },
-
-    [POWERPC_EXCP_EPERFM] = {
-        "Embedded perf. monitor", ppc_intr_embedded_perf_monitor
-    },
-
     [POWERPC_EXCP_EXTERNAL] = {
         "External", ppc_intr_external
     },
@@ -705,10 +567,6 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Fixed-interval timer", ppc_intr_fit
     },
 
-    [POWERPC_EXCP_FPA] = {
-        "Floating-point assist", ppc_intr_fpa
-    },
-
     [POWERPC_EXCP_FU] = {
         "Facility unavailable", ppc_intr_facility_unavail
     },
@@ -745,42 +603,18 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Hypervisor facility unavailable" , ppc_intr_hv_facility_unavail
     },
 
-    [POWERPC_EXCP_IABR] = {
-        "Insn address breakpoint", ppc_intr_iabr
-    },
-
     [POWERPC_EXCP_IFTLB] = {
         "Insn fetch TLB error", ppc_intr_tlb_miss
     },
 
-    [POWERPC_EXCP_IO] = {
-        "IO error", ppc_intr_io_error
-    },
-
     [POWERPC_EXCP_ISI] = {
         "Instruction storage", ppc_intr_insn_storage
     },
 
-    [POWERPC_EXCP_MAINT] = {
-        "Maintenance", ppc_intr_maint
-    },
-
     [POWERPC_EXCP_MCHECK] = {
         "Machine check", ppc_intr_machine_check
     },
 
-    [POWERPC_EXCP_MEXTBR] = {
-        "Maskable external", ppc_intr_mextbr
-    },
-
-    [POWERPC_EXCP_NMEXTBR] = {
-        "Non-maskable external", ppc_intr_nmextbr
-    },
-
-    [POWERPC_EXCP_PERFM] = {
-        "Performance counter", ppc_intr_perfm
-    },
-
     [POWERPC_EXCP_PIT] = {
         "Programmable interval timer", ppc_intr_programmable_timer
     },
@@ -793,22 +627,10 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "System reset", ppc_intr_system_reset
     },
 
-    [POWERPC_EXCP_RUNM] = {
-        "Run mode", ppc_intr_run_mode
-    },
-
     [POWERPC_EXCP_SDOOR_HV] = {
         "Hypervisor doorbell", ppc_intr_hv_doorbell
     },
 
-    [POWERPC_EXCP_SMI] = {
-        "System management", ppc_intr_smi
-    },
-
-    [POWERPC_EXCP_SOFTP] = {
-        "Soft patch", ppc_intr_softp
-    },
-
     [POWERPC_EXCP_SPEU] = {
         "SPE/embedded FP unavailable/VPU", ppc_intr_spe_unavailable
     },
@@ -821,14 +643,6 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "System call vectored", ppc_intr_system_call_vectored
     },
 
-    [POWERPC_EXCP_THERM] = {
-        "Thermal management", ppc_intr_therm
-    },
-
-    [POWERPC_EXCP_VPUA] = {
-        "Vector assist", ppc_intr_vpua
-    },
-
     [POWERPC_EXCP_VPU] = {
         "Vector unavailable", ppc_intr_facility_unavail
     },
@@ -852,6 +666,25 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
     [POWERPC_EXCP_TRACE] = { "Trace",                      ppc_intr_noop },
 
 /* Not implemented */
+    [POWERPC_EXCP_DABR]     = { "Data address breakpoint" },
+    [POWERPC_EXCP_DTLBE]    = { "Data TLB error" },
+    [POWERPC_EXCP_EFPDI]    = { "Embedded floating-point data" },
+    [POWERPC_EXCP_EFPRI]    = { "Embedded floating-point round" },
+    [POWERPC_EXCP_EMUL]     = { "Emulation trap" },
+    [POWERPC_EXCP_EPERFM]   = { "Embedded perf. monitor" },
+    [POWERPC_EXCP_FPA]      = { "Floating-point assist" },
     [POWERPC_EXCP_HV_MAINT] = { "Hypervisor maintenance" },
+    [POWERPC_EXCP_IABR]     = { "Insn address breakpoint" },
+    [POWERPC_EXCP_IO]       = { "IO error" },
+    [POWERPC_EXCP_ITLBE]    = { "Instruction TLB error" },
+    [POWERPC_EXCP_MAINT]    = { "Maintenance" },
+    [POWERPC_EXCP_MEXTBR]   = { "Maskable external" },
+    [POWERPC_EXCP_NMEXTBR]  = { "Non-maskable external" },
+    [POWERPC_EXCP_PERFM]    = { "Performance counter" },
+    [POWERPC_EXCP_RUNM]     = { "Run mode" },
     [POWERPC_EXCP_SDOOR]    = { "Server doorbell" },
+    [POWERPC_EXCP_SMI]      = { "System management" },
+    [POWERPC_EXCP_SOFTP]    = { "Soft patch" },
+    [POWERPC_EXCP_THERM]    = { "Thermal management" },
+    [POWERPC_EXCP_VPUA]     = { "Vector assist" },
 };
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
index 82372ca227..a96062c583 100644
--- a/target/ppc/ppc_intr.h
+++ b/target/ppc/ppc_intr.h
@@ -21,18 +21,12 @@ struct PPCInterrupt {
 
 void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_dabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_debug(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_embedded_perf_monitor(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_fpa(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_data_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_decrementer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
@@ -42,27 +36,16 @@ void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *igno
 void ppc_intr_hv_insn_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_virtualization(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_iabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_io_error(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_maint(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_mextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_nmextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_noop(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_perfm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_programmable_timer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_run_mode(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_smi(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_softp(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_system_call(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_therm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_vpua(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
 extern PPCInterrupt interrupts[POWERPC_EXCP_NB];
-- 
2.33.1



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

* [RFC v2 09/12] target/ppc: Use common code for Hypervisor interrupts
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (7 preceding siblings ...)
  2021-12-20 18:18 ` [RFC v2 08/12] target/ppc: Remove unimplemented interrupt code Fabiano Rosas
@ 2021-12-20 18:19 ` Fabiano Rosas
  2021-12-20 18:19 ` [RFC v2 10/12] target/ppc: Split powerpc_excp into book3s, booke and 32 bit Fabiano Rosas
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

The Hypervisor interrupts all set the MSR_HV bit, and use HSRRs
instead of SRRs, so we can use the same code to setup them all.

No functional change.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/interrupts.c | 128 +++++++---------------------------------
 target/ppc/ppc_intr.h   |   8 +--
 2 files changed, 21 insertions(+), 115 deletions(-)

diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
index 1e4fb2d6db..61a7dec682 100644
--- a/target/ppc/interrupts.c
+++ b/target/ppc/interrupts.c
@@ -364,86 +364,22 @@ void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     }
 }
 
+void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *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);
+}
+
 void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
     CPUPPCState *env = &cpu->env;
 
     regs->msr |= env->error_code;
-
-    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);
-}
-
-void ppc_intr_hv_decrementer(PowerPCCPU *cpu, PPCIntrArgs *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);
-}
-
-void ppc_intr_hv_data_storage(PowerPCCPU *cpu, PPCIntrArgs *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);
-}
-
-void ppc_intr_hv_data_segment(PowerPCCPU *cpu, PPCIntrArgs *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);
-}
-
-void ppc_intr_hv_insn_segment(PowerPCCPU *cpu, PPCIntrArgs *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);
-}
-
-void ppc_intr_hv_doorbell(PowerPCCPU *cpu, PPCIntrArgs *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);
-}
-
-void ppc_intr_hv_emulation(PowerPCCPU *cpu, PPCIntrArgs *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);
-}
-
-void ppc_intr_hv_virtualization(PowerPCCPU *cpu, PPCIntrArgs *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);
+    ppc_intr_hv(cpu, regs, ignore);
 }
 
 void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
@@ -459,11 +395,7 @@ void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *igno
 #ifdef TARGET_PPC64
     CPUPPCState *env = &cpu->env;
     env->spr[SPR_FSCR] |= ((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);
+    ppc_intr_hv(cpu, regs, ignore);
 #endif
 }
 
@@ -571,34 +503,10 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Facility unavailable", ppc_intr_facility_unavail
     },
 
-    [POWERPC_EXCP_HDECR] = {
-        "Hypervisor decrementer", ppc_intr_hv_decrementer
-    },
-
-    [POWERPC_EXCP_HDSEG] = {
-        "Hypervisor data segment", ppc_intr_hv_data_segment
-    },
-
-    [POWERPC_EXCP_HDSI] = {
-        "Hypervisor data storage", ppc_intr_hv_data_storage
-    },
-
-    [POWERPC_EXCP_HISEG] = {
-        "Hypervisor insn segment", ppc_intr_hv_insn_segment
-    },
-
     [POWERPC_EXCP_HISI] = {
         "Hypervisor instruction storage", ppc_intr_hv_insn_storage
     },
 
-    [POWERPC_EXCP_HVIRT] = {
-        "Hypervisor virtualization", ppc_intr_hv_virtualization
-    },
-
-    [POWERPC_EXCP_HV_EMU] = {
-        "Hypervisor emulation assist", ppc_intr_hv_emulation
-    },
-
     [POWERPC_EXCP_HV_FU] = {
         "Hypervisor facility unavailable" , ppc_intr_hv_facility_unavail
     },
@@ -627,10 +535,6 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "System reset", ppc_intr_system_reset
     },
 
-    [POWERPC_EXCP_SDOOR_HV] = {
-        "Hypervisor doorbell", ppc_intr_hv_doorbell
-    },
-
     [POWERPC_EXCP_SPEU] = {
         "SPE/embedded FP unavailable/VPU", ppc_intr_spe_unavailable
     },
@@ -655,6 +559,14 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Watchdog timer", ppc_intr_watchdog
     },
 
+    [POWERPC_EXCP_HDECR]    = { "Hypervisor decrementer",         ppc_intr_hv },
+    [POWERPC_EXCP_HDSEG]    = { "Hypervisor data segment",        ppc_intr_hv },
+    [POWERPC_EXCP_HDSI]     = { "Hypervisor data storage",        ppc_intr_hv },
+    [POWERPC_EXCP_HISEG]    = { "Hypervisor insn segment",        ppc_intr_hv },
+    [POWERPC_EXCP_HVIRT]    = { "Hypervisor virtualization",      ppc_intr_hv },
+    [POWERPC_EXCP_HV_EMU]   = { "Hypervisor emulation assist",    ppc_intr_hv },
+    [POWERPC_EXCP_SDOOR_HV] = { "Hypervisor doorbell",            ppc_intr_hv },
+
     [POWERPC_EXCP_APU]   = { "Aux. processor unavailable", ppc_intr_noop },
     [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
     [POWERPC_EXCP_DOORI] = { "Embedded doorbell",          ppc_intr_noop },
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
index a96062c583..078906ed68 100644
--- a/target/ppc/ppc_intr.h
+++ b/target/ppc/ppc_intr.h
@@ -27,15 +27,9 @@ void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *i
 void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_data_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_decrementer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_doorbell(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_insn_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_virtualization(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_noop(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-- 
2.33.1



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

* [RFC v2 10/12] target/ppc: Split powerpc_excp into book3s, booke and 32 bit
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (8 preceding siblings ...)
  2021-12-20 18:19 ` [RFC v2 09/12] target/ppc: Use common code for Hypervisor interrupts Fabiano Rosas
@ 2021-12-20 18:19 ` Fabiano Rosas
  2021-12-20 18:19 ` [RFC v2 11/12] target/ppc: Create new files for book3s, booke and ppc32 exception code Fabiano Rosas
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

These are the three major categories of processors we support and they
have slightly different requirements when it comes to dispatching
interrupts. Having it all in the same function is somewhat confusing
because one needs to keep guessing which parts of the code apply
exactly to which processors.

This patch splits powerpc_excp into three functions that will later be
moved into their own file.

(POWERPC_EXCP_DOORCI was removed because no CPUs use it)

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/excp_helper.c | 258 +++++++++++++++++++++++++--------------
 target/ppc/interrupts.c  | 223 ++++++++++++++++++++++++++-------
 target/ppc/ppc_intr.h    |   7 +-
 3 files changed, 350 insertions(+), 138 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 4f8a6c4ec8..9c785b75d5 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -37,6 +37,7 @@
 /* Exception processing */
 #if !defined(CONFIG_USER_ONLY)
 
+#ifdef TARGET_PPC64
 static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
                                 target_ulong *msr)
 {
@@ -140,7 +141,6 @@ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
                                       target_ulong *new_msr,
                                       target_ulong *new_nip)
 {
-#if defined(TARGET_PPC64)
     CPUPPCState *env = &cpu->env;
     bool mmu_all_on = ((msr >> MSR_IR) & 1) && ((msr >> MSR_DR) & 1);
     bool hv_escalation = !(msr & MSR_HVB) && (*new_msr & MSR_HVB);
@@ -229,8 +229,9 @@ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
             *new_nip |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
         }
     }
-#endif
 }
+#endif /* TARGET_PPC64 */
+
 
 static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
                                           target_ulong new_msr)
@@ -263,33 +264,16 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
     check_tlb_flush(env, false);
 }
 
-/*
- * Note that this function should be greatly optimized when called
- * with a constant excp, from ppc_hw_interrupt
- */
-static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
+#if defined(TARGET_PPC64)
+static inline void book3s_excp(PowerPCCPU *cpu, int excp)
 {
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     int excp_model = env->excp_model;
     PPCIntrArgs regs;
-    PPCInterrupt *intr;
-    bool ignore = false;
+    bool ignore;
 
-    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) {
-        /* Should never happen */
-        return;
-    }
-
-    /* new srr1 value excluding must-be-zero bits */
-    if (excp_model == POWERPC_EXCP_BOOKE) {
-        regs.msr = env->msr;
-    } else {
-        regs.msr = env->msr & ~0x783f0000ULL;
-    }
+    regs.msr = env->msr & ~0x783f0000ULL;
     regs.nip = env->nip;
 
     /*
@@ -298,6 +282,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
      */
     regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
 
+    /* The Book3S cpus we support are 64 bit only */
+    regs.new_msr |= (target_ulong)1 << MSR_SF;
+
     regs.sprn_srr0 = SPR_SRR0;
     regs.sprn_srr1 = SPR_SRR1;
 
@@ -310,71 +297,31 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
     }
 
     /*
-     * Hypervisor emulation assistance interrupt only exists on server
-     * arch 2.05 server or later. We also don't want to generate it if
-     * we don't have HVB in msr_mask (PAPR mode).
+     * We don't want to generate an Hypervisor emulation assistance
+     * interrupt if we don't have HVB in msr_mask (PAPR mode).
      */
-    if (excp == POWERPC_EXCP_HV_EMU
-#if defined(TARGET_PPC64)
-        && !(mmu_is_64bit(env->mmu_model) && (env->msr_mask & MSR_HVB))
-#endif /* defined(TARGET_PPC64) */
-
-    ) {
+    if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) {
         excp = POWERPC_EXCP_PROGRAM;
     }
 
-#ifdef TARGET_PPC64
-    /*
-     * SPEU and VPU share the same IVOR but they exist in different
-     * processors. SPEU is e500v1/2 only and VPU is e6500 only.
-     */
-    if (excp_model == POWERPC_EXCP_BOOKE && excp == POWERPC_EXCP_VPU) {
-        excp = POWERPC_EXCP_SPEU;
-    }
-#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;
-
-    intr = &interrupts[excp];
-    if (!intr->name) {
-        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
-    }
-
-    if (!intr->fn) {
-        cpu_abort(cs, "%s exception is not implemented yet !\n", intr->name);
-    }
-
-    /* Setup interrupt-specific registers before dispatching */
-    intr->fn(cpu, &regs, &ignore);
+    /* Setup interrupt-specific registers before injecting */
+    ignore = ppc_intr_prepare(cpu, interrupts_book3s, &regs, excp);
 
     if (ignore) {
         /* No further setup is needed for this interrupt */
         return;
     }
 
-    /* Sanity check */
-    if (!(env->msr_mask & 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 (regs.sprn_srr0 == SPR_HSRR0) {
-            cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
-                      "no HV support\n", excp);
-        }
-    }
-
     /*
      * Sort out endianness of interrupt, this differs depending on the
      * CPU, the HV mode, etc...
      */
-#ifdef TARGET_PPC64
     if (excp_model == POWERPC_EXCP_POWER7) {
         if (!(regs.new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
             regs.new_msr |= (target_ulong)1 << MSR_LE;
@@ -399,28 +346,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
     } else if (msr_ile) {
         regs.new_msr |= (target_ulong)1 << MSR_LE;
     }
-#else
-    if (msr_ile) {
-        regs.new_msr |= (target_ulong)1 << MSR_LE;
-    }
-#endif
-
-#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 */
-            regs.new_msr |= (target_ulong)1 << MSR_CM;
-        } else {
-            regs.new_nip = (uint32_t)regs.new_nip;
-        }
-    } else {
-        if (!msr_isf && !mmu_is_64bit(env->mmu_model)) {
-            regs.new_nip = (uint32_t)regs.new_nip;
-        } else {
-            regs.new_msr |= (target_ulong)1 << MSR_SF;
-        }
-    }
-#endif
 
     if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
         /* Save PC */
@@ -436,6 +361,159 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
 
     powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
 }
+#endif /* defined(TARGET_PPC64) */
+
+static inline void booke_excp(PowerPCCPU *cpu, int excp)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    PPCIntrArgs regs;
+    bool ignore;
+
+    regs.msr = env->msr;
+    regs.nip = env->nip;
+
+    /*
+     * new interrupt handler msr preserves existing HV and ME unless
+     * explicitly overriden
+     */
+    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
+
+    regs.sprn_srr0 = SPR_SRR0;
+    regs.sprn_srr1 = SPR_SRR1;
+
+    /*
+     * Hypervisor emulation assistance interrupt only exists on server
+     * arch 2.05 server or later.
+     */
+    if (excp == POWERPC_EXCP_HV_EMU) {
+        excp = POWERPC_EXCP_PROGRAM;
+    }
+
+#ifdef TARGET_PPC64
+    /*
+     * SPEU and VPU share the same IVOR but they exist in different
+     * processors. SPEU is e500v1/2 only and VPU is e6500 only.
+     */
+    if (env->excp_model == POWERPC_EXCP_BOOKE && excp == POWERPC_EXCP_VPU) {
+        excp = POWERPC_EXCP_SPEU;
+    }
+#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;
+
+    /* Setup interrupt-specific registers before injecting */
+    ignore = ppc_intr_prepare(cpu, interrupts_booke, &regs, excp);
+
+    if (ignore) {
+        /* No further setup is needed for this interrupt */
+        return;
+    }
+
+#if defined(TARGET_PPC64)
+    if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
+        /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
+        regs.new_msr |= (target_ulong)1 << MSR_CM;
+    } else {
+        regs.new_nip = (uint32_t)regs.new_nip;
+    }
+#endif
+
+    /* Save PC */
+    env->spr[regs.sprn_srr0] = regs.nip;
+
+    /* Save MSR */
+    env->spr[regs.sprn_srr1] = regs.msr;
+
+    powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
+}
+
+static inline void ppc32_excp(PowerPCCPU *cpu, int excp)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    PPCIntrArgs regs;
+    bool ignore;
+
+    regs.msr = env->msr & ~0x783f0000ULL;
+    regs.nip = env->nip;
+
+    /*
+     * new interrupt handler msr preserves existing HV and ME unless
+     * explicitly overriden
+     */
+    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
+
+    regs.sprn_srr0 = SPR_SRR0;
+    regs.sprn_srr1 = SPR_SRR1;
+
+    /*
+     * Hypervisor emulation assistance interrupt only exists on server
+     * arch 2.05 server or later.
+     */
+    if (excp == POWERPC_EXCP_HV_EMU) {
+        excp = POWERPC_EXCP_PROGRAM;
+    }
+
+    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;
+
+    /* Setup interrupt-specific registers before injecting */
+    ignore = ppc_intr_prepare(cpu, interrupts_ppc32, &regs, excp);
+
+    if (ignore) {
+        /* No further setup is needed for this interrupt */
+        return;
+    }
+
+    if (msr_ile) {
+        regs.new_msr |= (target_ulong)1 << MSR_LE;
+    }
+
+    /* Save PC */
+    env->spr[regs.sprn_srr0] = regs.nip;
+
+    /* Save MSR */
+    env->spr[regs.sprn_srr1] = regs.msr;
+
+    powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
+}
+
+static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
+{
+    CPUPPCState *env = &cpu->env;
+
+    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) {
+        /* Should never happen */
+        return;
+    }
+
+#ifdef TARGET_PPC64
+    if (env->excp_model >= POWERPC_EXCP_970) {
+        return book3s_excp(cpu, excp);
+    }
+#endif
+
+    if (env->excp_model == POWERPC_EXCP_BOOKE) {
+        booke_excp(cpu, excp);
+    } else {
+        ppc32_excp(cpu, excp);
+    }
+}
 
 void ppc_cpu_do_interrupt(CPUState *cs)
 {
diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
index 61a7dec682..743faddfee 100644
--- a/target/ppc/interrupts.c
+++ b/target/ppc/interrupts.c
@@ -334,12 +334,6 @@ void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     env->spr[SPR_BOOKE_ESR] = ESR_SPV;
 }
 
-void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    regs->sprn_srr0 = SPR_BOOKE_CSRR0;
-    regs->sprn_srr1 = SPR_BOOKE_CSRR1;
-}
-
 void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
     CPUPPCState *env = &cpu->env;
@@ -462,7 +456,7 @@ void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     }
 }
 
-PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
+PPCInterrupt interrupts_ppc32[POWERPC_EXCP_NB] = {
     [POWERPC_EXCP_ALIGN] = {
         "Alignment", ppc_intr_alignment
     },
@@ -479,10 +473,6 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Data load TLB error", ppc_intr_tlb_miss
     },
 
-    [POWERPC_EXCP_DOORCI] = {
-        "Embedded doorbell critical", ppc_intr_embedded_doorbell_crit
-    },
-
     [POWERPC_EXCP_DSI] = {
         "Data storage", ppc_intr_data_storage
     },
@@ -499,6 +489,78 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Fixed-interval timer", ppc_intr_fit
     },
 
+    [POWERPC_EXCP_IFTLB] = {
+        "Insn fetch TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_ISI] = {
+        "Instruction storage", ppc_intr_insn_storage
+    },
+
+    [POWERPC_EXCP_MCHECK] = {
+        "Machine check", ppc_intr_machine_check
+    },
+
+    [POWERPC_EXCP_PIT] = {
+        "Programmable interval timer", ppc_intr_programmable_timer
+    },
+
+    [POWERPC_EXCP_PROGRAM] = {
+        "Program", ppc_intr_program
+    },
+
+    [POWERPC_EXCP_RESET] = {
+        "System reset", ppc_intr_system_reset
+    },
+
+    [POWERPC_EXCP_SYSCALL] = {
+        "System call", ppc_intr_system_call
+    },
+
+    [POWERPC_EXCP_VPU] = {
+        "Vector unavailable", ppc_intr_facility_unavail
+    },
+
+    [POWERPC_EXCP_WDT] = {
+        "Watchdog timer", ppc_intr_watchdog
+    },
+
+    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
+    [POWERPC_EXCP_DTLB]  = { "Data TLB error",             ppc_intr_noop },
+    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
+    [POWERPC_EXCP_TRACE] = { "Trace",                      ppc_intr_noop },
+
+/* Not implemented */
+    [POWERPC_EXCP_DABR]     = { "Data address breakpoint" },
+    [POWERPC_EXCP_DTLBE]    = { "Data TLB error" },
+    [POWERPC_EXCP_EMUL]     = { "Emulation trap" },
+    [POWERPC_EXCP_FPA]      = { "Floating-point assist" },
+    [POWERPC_EXCP_IABR]     = { "Insn address breakpoint" },
+    [POWERPC_EXCP_IO]       = { "IO error" },
+    [POWERPC_EXCP_ITLBE]    = { "Instruction TLB error" },
+    [POWERPC_EXCP_MEXTBR]   = { "Maskable external" },
+    [POWERPC_EXCP_NMEXTBR]  = { "Non-maskable external" },
+    [POWERPC_EXCP_PERFM]    = { "Performance counter" },
+    [POWERPC_EXCP_RUNM]     = { "Run mode" },
+    [POWERPC_EXCP_SMI]      = { "System management" },
+    [POWERPC_EXCP_THERM]    = { "Thermal management" },
+    [POWERPC_EXCP_VPUA]     = { "Vector assist" },
+};
+
+PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = {
+    [POWERPC_EXCP_ALIGN] = {
+        "Alignment", ppc_intr_alignment
+    },
+
+    [POWERPC_EXCP_DSI] = {
+        "Data storage", ppc_intr_data_storage
+    },
+
+    [POWERPC_EXCP_EXTERNAL] = {
+        "External", ppc_intr_external
+    },
+
     [POWERPC_EXCP_FU] = {
         "Facility unavailable", ppc_intr_facility_unavail
     },
@@ -508,11 +570,7 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
     },
 
     [POWERPC_EXCP_HV_FU] = {
-        "Hypervisor facility unavailable" , ppc_intr_hv_facility_unavail
-    },
-
-    [POWERPC_EXCP_IFTLB] = {
-        "Insn fetch TLB error", ppc_intr_tlb_miss
+        "Hypervisor facility unavailable", ppc_intr_hv_facility_unavail
     },
 
     [POWERPC_EXCP_ISI] = {
@@ -523,10 +581,6 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "Machine check", ppc_intr_machine_check
     },
 
-    [POWERPC_EXCP_PIT] = {
-        "Programmable interval timer", ppc_intr_programmable_timer
-    },
-
     [POWERPC_EXCP_PROGRAM] = {
         "Program", ppc_intr_program
     },
@@ -535,10 +589,6 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "System reset", ppc_intr_system_reset
     },
 
-    [POWERPC_EXCP_SPEU] = {
-        "SPE/embedded FP unavailable/VPU", ppc_intr_spe_unavailable
-    },
-
     [POWERPC_EXCP_SYSCALL] = {
         "System call", ppc_intr_system_call
     },
@@ -555,48 +605,127 @@ PPCInterrupt interrupts[POWERPC_EXCP_NB] = {
         "VSX unavailable", ppc_intr_facility_unavail
     },
 
-    [POWERPC_EXCP_WDT] = {
-        "Watchdog timer", ppc_intr_watchdog
-    },
-
     [POWERPC_EXCP_HDECR]    = { "Hypervisor decrementer",         ppc_intr_hv },
-    [POWERPC_EXCP_HDSEG]    = { "Hypervisor data segment",        ppc_intr_hv },
     [POWERPC_EXCP_HDSI]     = { "Hypervisor data storage",        ppc_intr_hv },
-    [POWERPC_EXCP_HISEG]    = { "Hypervisor insn segment",        ppc_intr_hv },
     [POWERPC_EXCP_HVIRT]    = { "Hypervisor virtualization",      ppc_intr_hv },
     [POWERPC_EXCP_HV_EMU]   = { "Hypervisor emulation assist",    ppc_intr_hv },
     [POWERPC_EXCP_SDOOR_HV] = { "Hypervisor doorbell",            ppc_intr_hv },
 
-    [POWERPC_EXCP_APU]   = { "Aux. processor unavailable", ppc_intr_noop },
     [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
-    [POWERPC_EXCP_DOORI] = { "Embedded doorbell",          ppc_intr_noop },
     [POWERPC_EXCP_DSEG]  = { "Data segment",               ppc_intr_noop },
-    [POWERPC_EXCP_DTLB]  = { "Data TLB error",             ppc_intr_noop },
     [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
     [POWERPC_EXCP_ISEG]  = { "Instruction segment",        ppc_intr_noop },
     [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
     [POWERPC_EXCP_TRACE] = { "Trace",                      ppc_intr_noop },
 
 /* Not implemented */
-    [POWERPC_EXCP_DABR]     = { "Data address breakpoint" },
-    [POWERPC_EXCP_DTLBE]    = { "Data TLB error" },
-    [POWERPC_EXCP_EFPDI]    = { "Embedded floating-point data" },
-    [POWERPC_EXCP_EFPRI]    = { "Embedded floating-point round" },
-    [POWERPC_EXCP_EMUL]     = { "Emulation trap" },
-    [POWERPC_EXCP_EPERFM]   = { "Embedded perf. monitor" },
-    [POWERPC_EXCP_FPA]      = { "Floating-point assist" },
     [POWERPC_EXCP_HV_MAINT] = { "Hypervisor maintenance" },
     [POWERPC_EXCP_IABR]     = { "Insn address breakpoint" },
-    [POWERPC_EXCP_IO]       = { "IO error" },
-    [POWERPC_EXCP_ITLBE]    = { "Instruction TLB error" },
     [POWERPC_EXCP_MAINT]    = { "Maintenance" },
-    [POWERPC_EXCP_MEXTBR]   = { "Maskable external" },
-    [POWERPC_EXCP_NMEXTBR]  = { "Non-maskable external" },
     [POWERPC_EXCP_PERFM]    = { "Performance counter" },
-    [POWERPC_EXCP_RUNM]     = { "Run mode" },
     [POWERPC_EXCP_SDOOR]    = { "Server doorbell" },
-    [POWERPC_EXCP_SMI]      = { "System management" },
-    [POWERPC_EXCP_SOFTP]    = { "Soft patch" },
     [POWERPC_EXCP_THERM]    = { "Thermal management" },
     [POWERPC_EXCP_VPUA]     = { "Vector assist" },
 };
+
+PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = {
+    [POWERPC_EXCP_ALIGN] = {
+        "Alignment", ppc_intr_alignment
+    },
+
+    [POWERPC_EXCP_CRITICAL] = {
+        "Critical input", ppc_intr_critical
+    },
+
+    [POWERPC_EXCP_DEBUG] = {
+        "Debug", ppc_intr_debug
+    },
+
+    [POWERPC_EXCP_DLTLB] = {
+        "Data load TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_DSI] = {
+        "Data storage", ppc_intr_data_storage
+    },
+
+    [POWERPC_EXCP_EXTERNAL] = {
+        "External", ppc_intr_external
+    },
+
+    [POWERPC_EXCP_FIT] = {
+        "Fixed-interval timer", ppc_intr_fit
+    },
+
+    [POWERPC_EXCP_ISI] = {
+        "Instruction storage", ppc_intr_insn_storage
+    },
+
+    [POWERPC_EXCP_MCHECK] = {
+        "Machine check", ppc_intr_machine_check
+    },
+
+    [POWERPC_EXCP_PROGRAM] = {
+        "Program", ppc_intr_program
+    },
+
+    [POWERPC_EXCP_RESET] = {
+        "System reset", ppc_intr_system_reset
+    },
+
+    [POWERPC_EXCP_SPEU] = {
+        "SPE/embedded FP unavailable/VPU", ppc_intr_spe_unavailable
+    },
+
+    [POWERPC_EXCP_SYSCALL] = {
+        "System call", ppc_intr_system_call
+    },
+
+    [POWERPC_EXCP_WDT] = {
+        "Watchdog timer", ppc_intr_watchdog
+    },
+
+    [POWERPC_EXCP_APU]   = { "Aux. processor unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
+    [POWERPC_EXCP_DTLB]  = { "Data TLB error",             ppc_intr_noop },
+    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
+
+/* Not impleemented */
+    [POWERPC_EXCP_EFPDI]    = { "Embedded floating-point data" },
+    [POWERPC_EXCP_EFPRI]    = { "Embedded floating-point round" },
+};
+
+int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
+                     PPCIntrArgs *regs, int excp)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    PPCInterrupt *intr;
+    bool ignore = false;
+
+    intr = &interrupts[excp];
+    if (!intr->name) {
+        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+    }
+
+    if (!intr->fn) {
+        cpu_abort(cs, "%s exception is not implemented yet !\n", intr->name);
+    }
+
+    intr->fn(cpu, regs, &ignore);
+
+    /* Sanity check */
+    if (!(env->msr_mask & 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 (regs->sprn_srr0 == SPR_HSRR0) {
+            cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
+                      "no HV support\n", excp);
+        }
+    }
+
+    return ignore;
+}
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
index 078906ed68..a12b3a9e4d 100644
--- a/target/ppc/ppc_intr.h
+++ b/target/ppc/ppc_intr.h
@@ -42,6 +42,11 @@ void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
-extern PPCInterrupt interrupts[POWERPC_EXCP_NB];
+int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
+                     PPCIntrArgs *regs, int excp);
+
+extern PPCInterrupt interrupts_ppc32[POWERPC_EXCP_NB];
+extern PPCInterrupt interrupts_booke[POWERPC_EXCP_NB];
+extern PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB];
 
 #endif /* PPC_INTR_H */
-- 
2.33.1



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

* [RFC v2 11/12] target/ppc: Create new files for book3s, booke and ppc32 exception code
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (9 preceding siblings ...)
  2021-12-20 18:19 ` [RFC v2 10/12] target/ppc: Split powerpc_excp into book3s, booke and 32 bit Fabiano Rosas
@ 2021-12-20 18:19 ` Fabiano Rosas
  2021-12-20 18:19 ` [RFC v2 12/12] target/ppc: Do not enable all interrupts when running KVM Fabiano Rosas
  2021-12-26 16:48 ` [RFC v2 00/12] target/ppc: powerpc_excp improvements Cédric Le Goater
  12 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

Now that everything is split we can move them to their own files. The
rationale is that hopefully in the future we'll be able to move the
cpu code along and give them each a separate CONFIG option.

Another benefit is that we can now define static routines to replace
any of the generic ones from interrupts.c in case we need it.

book3s is now TARGET_PPC64 only. I also had to move some function
definitions to put them all under an ifdef.

ppc32 is now CONFIG_TCG only. I added a stub for ppc32_excp.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/cpu.h         |   2 +
 target/ppc/excp_helper.c | 426 +--------------------------------------
 target/ppc/interrupts.c  | 258 +-----------------------
 target/ppc/intr-book3s.c | 381 ++++++++++++++++++++++++++++++++++
 target/ppc/intr-booke.c  | 150 ++++++++++++++
 target/ppc/intr-ppc32.c  | 159 +++++++++++++++
 target/ppc/meson.build   |   3 +
 target/ppc/ppc_intr.h    |  18 +-
 target/ppc/tcg-stub.c    |   6 +
 9 files changed, 724 insertions(+), 679 deletions(-)
 create mode 100644 target/ppc/intr-book3s.c
 create mode 100644 target/ppc/intr-booke.c
 create mode 100644 target/ppc/intr-ppc32.c

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index fc66c3561d..becb5e0eb8 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1356,6 +1356,8 @@ void ppc_cpu_do_interrupt(CPUState *cpu);
 bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void ppc_cpu_do_system_reset(CPUState *cs);
 void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector);
+void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
+                            target_ulong new_msr);
 extern const VMStateDescription vmstate_ppc_cpu;
 #endif
 
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 9c785b75d5..eb8dab1741 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -37,204 +37,8 @@
 /* Exception processing */
 #if !defined(CONFIG_USER_ONLY)
 
-#ifdef TARGET_PPC64
-static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
-                                target_ulong *msr)
-{
-    /* We no longer are in a PM state */
-    env->resume_as_sreset = false;
-
-    /* Pretend to be returning from doze always as we don't lose state */
-    *msr |= SRR1_WS_NOLOSS;
-
-    /* Machine checks are sent normally */
-    if (excp == POWERPC_EXCP_MCHECK) {
-        return excp;
-    }
-    switch (excp) {
-    case POWERPC_EXCP_RESET:
-        *msr |= SRR1_WAKERESET;
-        break;
-    case POWERPC_EXCP_EXTERNAL:
-        *msr |= SRR1_WAKEEE;
-        break;
-    case POWERPC_EXCP_DECR:
-        *msr |= SRR1_WAKEDEC;
-        break;
-    case POWERPC_EXCP_SDOOR:
-        *msr |= SRR1_WAKEDBELL;
-        break;
-    case POWERPC_EXCP_SDOOR_HV:
-        *msr |= SRR1_WAKEHDBELL;
-        break;
-    case POWERPC_EXCP_HV_MAINT:
-        *msr |= SRR1_WAKEHMI;
-        break;
-    case POWERPC_EXCP_HVIRT:
-        *msr |= SRR1_WAKEHVI;
-        break;
-    default:
-        cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
-                  excp);
-    }
-    return POWERPC_EXCP_RESET;
-}
-
-/*
- * AIL - Alternate Interrupt Location, a mode that allows interrupts to be
- * taken with the MMU on, and which uses an alternate location (e.g., so the
- * kernel/hv can map the vectors there with an effective address).
- *
- * An interrupt is considered to be taken "with AIL" or "AIL applies" if they
- * are delivered in this way. AIL requires the LPCR to be set to enable this
- * mode, and then a number of conditions have to be true for AIL to apply.
- *
- * First of all, SRESET, MCE, and HMI are always delivered without AIL, because
- * they specifically want to be in real mode (e.g., the MCE might be signaling
- * a SLB multi-hit which requires SLB flush before the MMU can be enabled).
- *
- * After that, behaviour depends on the current MSR[IR], MSR[DR], MSR[HV],
- * whether or not the interrupt changes MSR[HV] from 0 to 1, and the current
- * radix mode (LPCR[HR]).
- *
- * POWER8, POWER9 with LPCR[HR]=0
- * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
- * +-----------+-------------+---------+-------------+-----+
- * | a         | 00/01/10    | x       | x           | 0   |
- * | a         | 11          | 0       | 1           | 0   |
- * | a         | 11          | 1       | 1           | a   |
- * | a         | 11          | 0       | 0           | a   |
- * +-------------------------------------------------------+
- *
- * POWER9 with LPCR[HR]=1
- * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
- * +-----------+-------------+---------+-------------+-----+
- * | a         | 00/01/10    | x       | x           | 0   |
- * | a         | 11          | x       | x           | a   |
- * +-------------------------------------------------------+
- *
- * The difference with POWER9 being that MSR[HV] 0->1 interrupts can be sent to
- * the hypervisor in AIL mode if the guest is radix. This is good for
- * performance but allows the guest to influence the AIL of hypervisor
- * interrupts using its MSR, and also the hypervisor must disallow guest
- * interrupts (MSR[HV] 0->0) from using AIL if the hypervisor does not want to
- * use AIL for its MSR[HV] 0->1 interrupts.
- *
- * POWER10 addresses those issues with a new LPCR[HAIL] bit that is applied to
- * interrupts that begin execution with MSR[HV]=1 (so both MSR[HV] 0->1 and
- * MSR[HV] 1->1).
- *
- * HAIL=1 is equivalent to AIL=3, for interrupts delivered with MSR[HV]=1.
- *
- * POWER10 behaviour is
- * | LPCR[AIL] | LPCR[HAIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
- * +-----------+------------+-------------+---------+-------------+-----+
- * | a         | h          | 00/01/10    | 0       | 0           | 0   |
- * | a         | h          | 11          | 0       | 0           | a   |
- * | a         | h          | x           | 0       | 1           | h   |
- * | a         | h          | 00/01/10    | 1       | 1           | 0   |
- * | a         | h          | 11          | 1       | 1           | h   |
- * +--------------------------------------------------------------------+
- */
-static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
-                                      target_ulong msr,
-                                      target_ulong *new_msr,
-                                      target_ulong *new_nip)
-{
-    CPUPPCState *env = &cpu->env;
-    bool mmu_all_on = ((msr >> MSR_IR) & 1) && ((msr >> MSR_DR) & 1);
-    bool hv_escalation = !(msr & MSR_HVB) && (*new_msr & MSR_HVB);
-    int ail = 0;
-
-    if (excp == POWERPC_EXCP_MCHECK ||
-        excp == POWERPC_EXCP_RESET ||
-        excp == POWERPC_EXCP_HV_MAINT) {
-        /* SRESET, MCE, HMI never apply AIL */
-        return;
-    }
-
-    if (excp_model == POWERPC_EXCP_POWER8 ||
-        excp_model == POWERPC_EXCP_POWER9) {
-        if (!mmu_all_on) {
-            /* AIL only works if MSR[IR] and MSR[DR] are both enabled. */
-            return;
-        }
-        if (hv_escalation && !(env->spr[SPR_LPCR] & LPCR_HR)) {
-            /*
-             * AIL does not work if there is a MSR[HV] 0->1 transition and the
-             * partition is in HPT mode. For radix guests, such interrupts are
-             * allowed to be delivered to the hypervisor in ail mode.
-             */
-            return;
-        }
-
-        ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
-        if (ail == 0) {
-            return;
-        }
-        if (ail == 1) {
-            /* AIL=1 is reserved, treat it like AIL=0 */
-            return;
-        }
-
-    } else if (excp_model == POWERPC_EXCP_POWER10) {
-        if (!mmu_all_on && !hv_escalation) {
-            /*
-             * AIL works for HV interrupts even with guest MSR[IR/DR] disabled.
-             * Guest->guest and HV->HV interrupts do require MMU on.
-             */
-            return;
-        }
-
-        if (*new_msr & MSR_HVB) {
-            if (!(env->spr[SPR_LPCR] & LPCR_HAIL)) {
-                /* HV interrupts depend on LPCR[HAIL] */
-                return;
-            }
-            ail = 3; /* HAIL=1 gives AIL=3 behaviour for HV interrupts */
-        } else {
-            ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
-        }
-        if (ail == 0) {
-            return;
-        }
-        if (ail == 1 || ail == 2) {
-            /* AIL=1 and AIL=2 are reserved, treat them like AIL=0 */
-            return;
-        }
-    } else {
-        /* Other processors do not support AIL */
-        return;
-    }
-
-    /*
-     * AIL applies, so the new MSR gets IR and DR set, and an offset applied
-     * to the new IP.
-     */
-    *new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
-
-    if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
-        if (ail == 2) {
-            *new_nip |= 0x0000000000018000ull;
-        } else if (ail == 3) {
-            *new_nip |= 0xc000000000004000ull;
-        }
-    } else {
-        /*
-         * scv AIL is a little different. AIL=2 does not change the address,
-         * only the MSR. AIL=3 replaces the 0x17000 base with 0xc...3000.
-         */
-        if (ail == 3) {
-            *new_nip &= ~0x0000000000017000ull; /* Un-apply the base offset */
-            *new_nip |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
-        }
-    }
-}
-#endif /* TARGET_PPC64 */
-
-
-static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
-                                          target_ulong new_msr)
+inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
+                                   target_ulong new_msr)
 {
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
@@ -264,232 +68,6 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
     check_tlb_flush(env, false);
 }
 
-#if defined(TARGET_PPC64)
-static inline void book3s_excp(PowerPCCPU *cpu, int excp)
-{
-    CPUState *cs = CPU(cpu);
-    CPUPPCState *env = &cpu->env;
-    int excp_model = env->excp_model;
-    PPCIntrArgs regs;
-    bool ignore;
-
-    regs.msr = env->msr & ~0x783f0000ULL;
-    regs.nip = env->nip;
-
-    /*
-     * new interrupt handler msr preserves existing HV and ME unless
-     * explicitly overriden
-     */
-    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
-
-    /* The Book3S cpus we support are 64 bit only */
-    regs.new_msr |= (target_ulong)1 << MSR_SF;
-
-    regs.sprn_srr0 = SPR_SRR0;
-    regs.sprn_srr1 = SPR_SRR1;
-
-    /*
-     * 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, &regs.msr);
-    }
-
-    /*
-     * We don't want to generate an Hypervisor emulation assistance
-     * interrupt if we don't have HVB in msr_mask (PAPR mode).
-     */
-    if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) {
-        excp = POWERPC_EXCP_PROGRAM;
-    }
-
-    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);
-    }
-
-    /* Setup interrupt-specific registers before injecting */
-    ignore = ppc_intr_prepare(cpu, interrupts_book3s, &regs, excp);
-
-    if (ignore) {
-        /* No further setup is needed for this interrupt */
-        return;
-    }
-
-    /*
-     * Sort out endianness of interrupt, this differs depending on the
-     * CPU, the HV mode, etc...
-     */
-    if (excp_model == POWERPC_EXCP_POWER7) {
-        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 (regs.new_msr & MSR_HVB) {
-            if (env->spr[SPR_HID0] & HID0_HILE) {
-                regs.new_msr |= (target_ulong)1 << MSR_LE;
-            }
-        } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
-            regs.new_msr |= (target_ulong)1 << MSR_LE;
-        }
-    } else if (excp_model == POWERPC_EXCP_POWER9 ||
-               excp_model == POWERPC_EXCP_POWER10) {
-        if (regs.new_msr & MSR_HVB) {
-            if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
-                regs.new_msr |= (target_ulong)1 << MSR_LE;
-            }
-        } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
-            regs.new_msr |= (target_ulong)1 << MSR_LE;
-        }
-    } else if (msr_ile) {
-        regs.new_msr |= (target_ulong)1 << MSR_LE;
-    }
-
-    if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
-        /* Save PC */
-        env->spr[regs.sprn_srr0] = regs.nip;
-
-        /* Save MSR */
-        env->spr[regs.sprn_srr1] = regs.msr;
-    }
-
-    /* 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, regs.new_nip, regs.new_msr);
-}
-#endif /* defined(TARGET_PPC64) */
-
-static inline void booke_excp(PowerPCCPU *cpu, int excp)
-{
-    CPUState *cs = CPU(cpu);
-    CPUPPCState *env = &cpu->env;
-    PPCIntrArgs regs;
-    bool ignore;
-
-    regs.msr = env->msr;
-    regs.nip = env->nip;
-
-    /*
-     * new interrupt handler msr preserves existing HV and ME unless
-     * explicitly overriden
-     */
-    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
-
-    regs.sprn_srr0 = SPR_SRR0;
-    regs.sprn_srr1 = SPR_SRR1;
-
-    /*
-     * Hypervisor emulation assistance interrupt only exists on server
-     * arch 2.05 server or later.
-     */
-    if (excp == POWERPC_EXCP_HV_EMU) {
-        excp = POWERPC_EXCP_PROGRAM;
-    }
-
-#ifdef TARGET_PPC64
-    /*
-     * SPEU and VPU share the same IVOR but they exist in different
-     * processors. SPEU is e500v1/2 only and VPU is e6500 only.
-     */
-    if (env->excp_model == POWERPC_EXCP_BOOKE && excp == POWERPC_EXCP_VPU) {
-        excp = POWERPC_EXCP_SPEU;
-    }
-#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;
-
-    /* Setup interrupt-specific registers before injecting */
-    ignore = ppc_intr_prepare(cpu, interrupts_booke, &regs, excp);
-
-    if (ignore) {
-        /* No further setup is needed for this interrupt */
-        return;
-    }
-
-#if defined(TARGET_PPC64)
-    if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
-        /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
-        regs.new_msr |= (target_ulong)1 << MSR_CM;
-    } else {
-        regs.new_nip = (uint32_t)regs.new_nip;
-    }
-#endif
-
-    /* Save PC */
-    env->spr[regs.sprn_srr0] = regs.nip;
-
-    /* Save MSR */
-    env->spr[regs.sprn_srr1] = regs.msr;
-
-    powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
-}
-
-static inline void ppc32_excp(PowerPCCPU *cpu, int excp)
-{
-    CPUState *cs = CPU(cpu);
-    CPUPPCState *env = &cpu->env;
-    PPCIntrArgs regs;
-    bool ignore;
-
-    regs.msr = env->msr & ~0x783f0000ULL;
-    regs.nip = env->nip;
-
-    /*
-     * new interrupt handler msr preserves existing HV and ME unless
-     * explicitly overriden
-     */
-    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
-
-    regs.sprn_srr0 = SPR_SRR0;
-    regs.sprn_srr1 = SPR_SRR1;
-
-    /*
-     * Hypervisor emulation assistance interrupt only exists on server
-     * arch 2.05 server or later.
-     */
-    if (excp == POWERPC_EXCP_HV_EMU) {
-        excp = POWERPC_EXCP_PROGRAM;
-    }
-
-    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;
-
-    /* Setup interrupt-specific registers before injecting */
-    ignore = ppc_intr_prepare(cpu, interrupts_ppc32, &regs, excp);
-
-    if (ignore) {
-        /* No further setup is needed for this interrupt */
-        return;
-    }
-
-    if (msr_ile) {
-        regs.new_msr |= (target_ulong)1 << MSR_LE;
-    }
-
-    /* Save PC */
-    env->spr[regs.sprn_srr0] = regs.nip;
-
-    /* Save MSR */
-    env->spr[regs.sprn_srr1] = regs.msr;
-
-    powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
-}
-
 static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
 {
     CPUPPCState *env = &cpu->env;
diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
index 743faddfee..6f956029fd 100644
--- a/target/ppc/interrupts.c
+++ b/target/ppc/interrupts.c
@@ -358,6 +358,7 @@ void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     }
 }
 
+#ifdef TARGET_PPC64
 void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
     CPUPPCState *env = &cpu->env;
@@ -376,20 +377,19 @@ void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     ppc_intr_hv(cpu, regs, ignore);
 }
 
-void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-#ifdef TARGET_PPC64
-    CPUPPCState *env = &cpu->env;
-    env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
-#endif
-}
-
 void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
-#ifdef TARGET_PPC64
     CPUPPCState *env = &cpu->env;
     env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
     ppc_intr_hv(cpu, regs, ignore);
+}
+#endif /* TARGET PPC64 */
+
+void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+#ifdef TARGET_PPC64
+    CPUPPCState *env = &cpu->env;
+    env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
 #endif
 }
 
@@ -456,246 +456,6 @@ void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     }
 }
 
-PPCInterrupt interrupts_ppc32[POWERPC_EXCP_NB] = {
-    [POWERPC_EXCP_ALIGN] = {
-        "Alignment", ppc_intr_alignment
-    },
-
-    [POWERPC_EXCP_CRITICAL] = {
-        "Critical input", ppc_intr_critical
-    },
-
-    [POWERPC_EXCP_DEBUG] = {
-        "Debug", ppc_intr_debug
-    },
-
-    [POWERPC_EXCP_DLTLB] = {
-        "Data load TLB error", ppc_intr_tlb_miss
-    },
-
-    [POWERPC_EXCP_DSI] = {
-        "Data storage", ppc_intr_data_storage
-    },
-
-    [POWERPC_EXCP_DSTLB] = {
-        "Data store TLB error", ppc_intr_tlb_miss
-    },
-
-    [POWERPC_EXCP_EXTERNAL] = {
-        "External", ppc_intr_external
-    },
-
-    [POWERPC_EXCP_FIT] = {
-        "Fixed-interval timer", ppc_intr_fit
-    },
-
-    [POWERPC_EXCP_IFTLB] = {
-        "Insn fetch TLB error", ppc_intr_tlb_miss
-    },
-
-    [POWERPC_EXCP_ISI] = {
-        "Instruction storage", ppc_intr_insn_storage
-    },
-
-    [POWERPC_EXCP_MCHECK] = {
-        "Machine check", ppc_intr_machine_check
-    },
-
-    [POWERPC_EXCP_PIT] = {
-        "Programmable interval timer", ppc_intr_programmable_timer
-    },
-
-    [POWERPC_EXCP_PROGRAM] = {
-        "Program", ppc_intr_program
-    },
-
-    [POWERPC_EXCP_RESET] = {
-        "System reset", ppc_intr_system_reset
-    },
-
-    [POWERPC_EXCP_SYSCALL] = {
-        "System call", ppc_intr_system_call
-    },
-
-    [POWERPC_EXCP_VPU] = {
-        "Vector unavailable", ppc_intr_facility_unavail
-    },
-
-    [POWERPC_EXCP_WDT] = {
-        "Watchdog timer", ppc_intr_watchdog
-    },
-
-    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
-    [POWERPC_EXCP_DTLB]  = { "Data TLB error",             ppc_intr_noop },
-    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
-    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
-    [POWERPC_EXCP_TRACE] = { "Trace",                      ppc_intr_noop },
-
-/* Not implemented */
-    [POWERPC_EXCP_DABR]     = { "Data address breakpoint" },
-    [POWERPC_EXCP_DTLBE]    = { "Data TLB error" },
-    [POWERPC_EXCP_EMUL]     = { "Emulation trap" },
-    [POWERPC_EXCP_FPA]      = { "Floating-point assist" },
-    [POWERPC_EXCP_IABR]     = { "Insn address breakpoint" },
-    [POWERPC_EXCP_IO]       = { "IO error" },
-    [POWERPC_EXCP_ITLBE]    = { "Instruction TLB error" },
-    [POWERPC_EXCP_MEXTBR]   = { "Maskable external" },
-    [POWERPC_EXCP_NMEXTBR]  = { "Non-maskable external" },
-    [POWERPC_EXCP_PERFM]    = { "Performance counter" },
-    [POWERPC_EXCP_RUNM]     = { "Run mode" },
-    [POWERPC_EXCP_SMI]      = { "System management" },
-    [POWERPC_EXCP_THERM]    = { "Thermal management" },
-    [POWERPC_EXCP_VPUA]     = { "Vector assist" },
-};
-
-PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = {
-    [POWERPC_EXCP_ALIGN] = {
-        "Alignment", ppc_intr_alignment
-    },
-
-    [POWERPC_EXCP_DSI] = {
-        "Data storage", ppc_intr_data_storage
-    },
-
-    [POWERPC_EXCP_EXTERNAL] = {
-        "External", ppc_intr_external
-    },
-
-    [POWERPC_EXCP_FU] = {
-        "Facility unavailable", ppc_intr_facility_unavail
-    },
-
-    [POWERPC_EXCP_HISI] = {
-        "Hypervisor instruction storage", ppc_intr_hv_insn_storage
-    },
-
-    [POWERPC_EXCP_HV_FU] = {
-        "Hypervisor facility unavailable", ppc_intr_hv_facility_unavail
-    },
-
-    [POWERPC_EXCP_ISI] = {
-        "Instruction storage", ppc_intr_insn_storage
-    },
-
-    [POWERPC_EXCP_MCHECK] = {
-        "Machine check", ppc_intr_machine_check
-    },
-
-    [POWERPC_EXCP_PROGRAM] = {
-        "Program", ppc_intr_program
-    },
-
-    [POWERPC_EXCP_RESET] = {
-        "System reset", ppc_intr_system_reset
-    },
-
-    [POWERPC_EXCP_SYSCALL] = {
-        "System call", ppc_intr_system_call
-    },
-
-    [POWERPC_EXCP_SYSCALL_VECTORED] = {
-        "System call vectored", ppc_intr_system_call_vectored
-    },
-
-    [POWERPC_EXCP_VPU] = {
-        "Vector unavailable", ppc_intr_facility_unavail
-    },
-
-    [POWERPC_EXCP_VSXU] = {
-        "VSX unavailable", ppc_intr_facility_unavail
-    },
-
-    [POWERPC_EXCP_HDECR]    = { "Hypervisor decrementer",         ppc_intr_hv },
-    [POWERPC_EXCP_HDSI]     = { "Hypervisor data storage",        ppc_intr_hv },
-    [POWERPC_EXCP_HVIRT]    = { "Hypervisor virtualization",      ppc_intr_hv },
-    [POWERPC_EXCP_HV_EMU]   = { "Hypervisor emulation assist",    ppc_intr_hv },
-    [POWERPC_EXCP_SDOOR_HV] = { "Hypervisor doorbell",            ppc_intr_hv },
-
-    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
-    [POWERPC_EXCP_DSEG]  = { "Data segment",               ppc_intr_noop },
-    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
-    [POWERPC_EXCP_ISEG]  = { "Instruction segment",        ppc_intr_noop },
-    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
-    [POWERPC_EXCP_TRACE] = { "Trace",                      ppc_intr_noop },
-
-/* Not implemented */
-    [POWERPC_EXCP_HV_MAINT] = { "Hypervisor maintenance" },
-    [POWERPC_EXCP_IABR]     = { "Insn address breakpoint" },
-    [POWERPC_EXCP_MAINT]    = { "Maintenance" },
-    [POWERPC_EXCP_PERFM]    = { "Performance counter" },
-    [POWERPC_EXCP_SDOOR]    = { "Server doorbell" },
-    [POWERPC_EXCP_THERM]    = { "Thermal management" },
-    [POWERPC_EXCP_VPUA]     = { "Vector assist" },
-};
-
-PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = {
-    [POWERPC_EXCP_ALIGN] = {
-        "Alignment", ppc_intr_alignment
-    },
-
-    [POWERPC_EXCP_CRITICAL] = {
-        "Critical input", ppc_intr_critical
-    },
-
-    [POWERPC_EXCP_DEBUG] = {
-        "Debug", ppc_intr_debug
-    },
-
-    [POWERPC_EXCP_DLTLB] = {
-        "Data load TLB error", ppc_intr_tlb_miss
-    },
-
-    [POWERPC_EXCP_DSI] = {
-        "Data storage", ppc_intr_data_storage
-    },
-
-    [POWERPC_EXCP_EXTERNAL] = {
-        "External", ppc_intr_external
-    },
-
-    [POWERPC_EXCP_FIT] = {
-        "Fixed-interval timer", ppc_intr_fit
-    },
-
-    [POWERPC_EXCP_ISI] = {
-        "Instruction storage", ppc_intr_insn_storage
-    },
-
-    [POWERPC_EXCP_MCHECK] = {
-        "Machine check", ppc_intr_machine_check
-    },
-
-    [POWERPC_EXCP_PROGRAM] = {
-        "Program", ppc_intr_program
-    },
-
-    [POWERPC_EXCP_RESET] = {
-        "System reset", ppc_intr_system_reset
-    },
-
-    [POWERPC_EXCP_SPEU] = {
-        "SPE/embedded FP unavailable/VPU", ppc_intr_spe_unavailable
-    },
-
-    [POWERPC_EXCP_SYSCALL] = {
-        "System call", ppc_intr_system_call
-    },
-
-    [POWERPC_EXCP_WDT] = {
-        "Watchdog timer", ppc_intr_watchdog
-    },
-
-    [POWERPC_EXCP_APU]   = { "Aux. processor unavailable", ppc_intr_noop },
-    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
-    [POWERPC_EXCP_DTLB]  = { "Data TLB error",             ppc_intr_noop },
-    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
-    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
-
-/* Not impleemented */
-    [POWERPC_EXCP_EFPDI]    = { "Embedded floating-point data" },
-    [POWERPC_EXCP_EFPRI]    = { "Embedded floating-point round" },
-};
-
 int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
                      PPCIntrArgs *regs, int excp)
 {
diff --git a/target/ppc/intr-book3s.c b/target/ppc/intr-book3s.c
new file mode 100644
index 0000000000..cd279de346
--- /dev/null
+++ b/target/ppc/intr-book3s.c
@@ -0,0 +1,381 @@
+/*
+ * PowerPC interrupt dispatching for Book3S CPUs
+ *
+ * Copyright (C) 2021 IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "ppc_intr.h"
+
+static PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = {
+    [POWERPC_EXCP_ALIGN] = {
+        "Alignment", ppc_intr_alignment
+    },
+
+    [POWERPC_EXCP_DSI] = {
+        "Data storage", ppc_intr_data_storage
+    },
+
+    [POWERPC_EXCP_EXTERNAL] = {
+        "External", ppc_intr_external
+    },
+
+    [POWERPC_EXCP_FU] = {
+        "Facility unavailable", ppc_intr_facility_unavail
+    },
+
+    [POWERPC_EXCP_HISI] = {
+        "Hypervisor instruction storage", ppc_intr_hv_insn_storage
+    },
+
+    [POWERPC_EXCP_HV_FU] = {
+        "Hypervisor facility unavailable", ppc_intr_hv_facility_unavail
+    },
+
+    [POWERPC_EXCP_ISI] = {
+        "Instruction storage", ppc_intr_insn_storage
+    },
+
+    [POWERPC_EXCP_MCHECK] = {
+        "Machine check", ppc_intr_machine_check
+    },
+
+    [POWERPC_EXCP_PROGRAM] = {
+        "Program", ppc_intr_program
+    },
+
+    [POWERPC_EXCP_RESET] = {
+        "System reset", ppc_intr_system_reset
+    },
+
+    [POWERPC_EXCP_SYSCALL] = {
+        "System call", ppc_intr_system_call
+    },
+
+    [POWERPC_EXCP_SYSCALL_VECTORED] = {
+        "System call vectored", ppc_intr_system_call_vectored
+    },
+
+    [POWERPC_EXCP_VPU] = {
+        "Vector unavailable", ppc_intr_facility_unavail
+    },
+
+    [POWERPC_EXCP_VSXU] = {
+        "VSX unavailable", ppc_intr_facility_unavail
+    },
+
+    [POWERPC_EXCP_HDECR]    = { "Hypervisor decrementer",         ppc_intr_hv },
+    [POWERPC_EXCP_HDSI]     = { "Hypervisor data storage",        ppc_intr_hv },
+    [POWERPC_EXCP_HVIRT]    = { "Hypervisor virtualization",      ppc_intr_hv },
+    [POWERPC_EXCP_HV_EMU]   = { "Hypervisor emulation assist",    ppc_intr_hv },
+    [POWERPC_EXCP_SDOOR_HV] = { "Hypervisor doorbell",            ppc_intr_hv },
+
+    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
+    [POWERPC_EXCP_DSEG]  = { "Data segment",               ppc_intr_noop },
+    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_ISEG]  = { "Instruction segment",        ppc_intr_noop },
+    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
+    [POWERPC_EXCP_TRACE] = { "Trace",                      ppc_intr_noop },
+
+/* Not implemented */
+    [POWERPC_EXCP_HV_MAINT] = { "Hypervisor maintenance" },
+    [POWERPC_EXCP_IABR]     = { "Insn address breakpoint" },
+    [POWERPC_EXCP_MAINT]    = { "Maintenance" },
+    [POWERPC_EXCP_PERFM]    = { "Performance counter" },
+    [POWERPC_EXCP_SDOOR]    = { "Server doorbell" },
+    [POWERPC_EXCP_THERM]    = { "Thermal management" },
+    [POWERPC_EXCP_VPUA]     = { "Vector assist" },
+};
+
+static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
+                                target_ulong *msr)
+{
+    /* We no longer are in a PM state */
+    env->resume_as_sreset = false;
+
+    /* Pretend to be returning from doze always as we don't lose state */
+    *msr |= SRR1_WS_NOLOSS;
+
+    /* Machine checks are sent normally */
+    if (excp == POWERPC_EXCP_MCHECK) {
+        return excp;
+    }
+    switch (excp) {
+    case POWERPC_EXCP_RESET:
+        *msr |= SRR1_WAKERESET;
+        break;
+    case POWERPC_EXCP_EXTERNAL:
+        *msr |= SRR1_WAKEEE;
+        break;
+    case POWERPC_EXCP_DECR:
+        *msr |= SRR1_WAKEDEC;
+        break;
+    case POWERPC_EXCP_SDOOR:
+        *msr |= SRR1_WAKEDBELL;
+        break;
+    case POWERPC_EXCP_SDOOR_HV:
+        *msr |= SRR1_WAKEHDBELL;
+        break;
+    case POWERPC_EXCP_HV_MAINT:
+        *msr |= SRR1_WAKEHMI;
+        break;
+    case POWERPC_EXCP_HVIRT:
+        *msr |= SRR1_WAKEHVI;
+        break;
+    default:
+        cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
+                  excp);
+    }
+    return POWERPC_EXCP_RESET;
+}
+
+/*
+ * AIL - Alternate Interrupt Location, a mode that allows interrupts to be
+ * taken with the MMU on, and which uses an alternate location (e.g., so the
+ * kernel/hv can map the vectors there with an effective address).
+ *
+ * An interrupt is considered to be taken "with AIL" or "AIL applies" if they
+ * are delivered in this way. AIL requires the LPCR to be set to enable this
+ * mode, and then a number of conditions have to be true for AIL to apply.
+ *
+ * First of all, SRESET, MCE, and HMI are always delivered without AIL, because
+ * they specifically want to be in real mode (e.g., the MCE might be signaling
+ * a SLB multi-hit which requires SLB flush before the MMU can be enabled).
+ *
+ * After that, behaviour depends on the current MSR[IR], MSR[DR], MSR[HV],
+ * whether or not the interrupt changes MSR[HV] from 0 to 1, and the current
+ * radix mode (LPCR[HR]).
+ *
+ * POWER8, POWER9 with LPCR[HR]=0
+ * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
+ * +-----------+-------------+---------+-------------+-----+
+ * | a         | 00/01/10    | x       | x           | 0   |
+ * | a         | 11          | 0       | 1           | 0   |
+ * | a         | 11          | 1       | 1           | a   |
+ * | a         | 11          | 0       | 0           | a   |
+ * +-------------------------------------------------------+
+ *
+ * POWER9 with LPCR[HR]=1
+ * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
+ * +-----------+-------------+---------+-------------+-----+
+ * | a         | 00/01/10    | x       | x           | 0   |
+ * | a         | 11          | x       | x           | a   |
+ * +-------------------------------------------------------+
+ *
+ * The difference with POWER9 being that MSR[HV] 0->1 interrupts can be sent to
+ * the hypervisor in AIL mode if the guest is radix. This is good for
+ * performance but allows the guest to influence the AIL of hypervisor
+ * interrupts using its MSR, and also the hypervisor must disallow guest
+ * interrupts (MSR[HV] 0->0) from using AIL if the hypervisor does not want to
+ * use AIL for its MSR[HV] 0->1 interrupts.
+ *
+ * POWER10 addresses those issues with a new LPCR[HAIL] bit that is applied to
+ * interrupts that begin execution with MSR[HV]=1 (so both MSR[HV] 0->1 and
+ * MSR[HV] 1->1).
+ *
+ * HAIL=1 is equivalent to AIL=3, for interrupts delivered with MSR[HV]=1.
+ *
+ * POWER10 behaviour is
+ * | LPCR[AIL] | LPCR[HAIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
+ * +-----------+------------+-------------+---------+-------------+-----+
+ * | a         | h          | 00/01/10    | 0       | 0           | 0   |
+ * | a         | h          | 11          | 0       | 0           | a   |
+ * | a         | h          | x           | 0       | 1           | h   |
+ * | a         | h          | 00/01/10    | 1       | 1           | 0   |
+ * | a         | h          | 11          | 1       | 1           | h   |
+ * +--------------------------------------------------------------------+
+ */
+static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
+                                      target_ulong msr,
+                                      target_ulong *new_msr,
+                                      target_ulong *new_nip)
+{
+    CPUPPCState *env = &cpu->env;
+    bool mmu_all_on = ((msr >> MSR_IR) & 1) && ((msr >> MSR_DR) & 1);
+    bool hv_escalation = !(msr & MSR_HVB) && (*new_msr & MSR_HVB);
+    int ail = 0;
+
+    if (excp == POWERPC_EXCP_MCHECK ||
+        excp == POWERPC_EXCP_RESET ||
+        excp == POWERPC_EXCP_HV_MAINT) {
+        /* SRESET, MCE, HMI never apply AIL */
+        return;
+    }
+
+    if (excp_model == POWERPC_EXCP_POWER8 ||
+        excp_model == POWERPC_EXCP_POWER9) {
+        if (!mmu_all_on) {
+            /* AIL only works if MSR[IR] and MSR[DR] are both enabled. */
+            return;
+        }
+        if (hv_escalation && !(env->spr[SPR_LPCR] & LPCR_HR)) {
+            /*
+             * AIL does not work if there is a MSR[HV] 0->1 transition and the
+             * partition is in HPT mode. For radix guests, such interrupts are
+             * allowed to be delivered to the hypervisor in ail mode.
+             */
+            return;
+        }
+
+        ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
+        if (ail == 0) {
+            return;
+        }
+        if (ail == 1) {
+            /* AIL=1 is reserved, treat it like AIL=0 */
+            return;
+        }
+
+    } else if (excp_model == POWERPC_EXCP_POWER10) {
+        if (!mmu_all_on && !hv_escalation) {
+            /*
+             * AIL works for HV interrupts even with guest MSR[IR/DR] disabled.
+             * Guest->guest and HV->HV interrupts do require MMU on.
+             */
+            return;
+        }
+
+        if (*new_msr & MSR_HVB) {
+            if (!(env->spr[SPR_LPCR] & LPCR_HAIL)) {
+                /* HV interrupts depend on LPCR[HAIL] */
+                return;
+            }
+            ail = 3; /* HAIL=1 gives AIL=3 behaviour for HV interrupts */
+        } else {
+            ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
+        }
+        if (ail == 0) {
+            return;
+        }
+        if (ail == 1 || ail == 2) {
+            /* AIL=1 and AIL=2 are reserved, treat them like AIL=0 */
+            return;
+        }
+    } else {
+        /* Other processors do not support AIL */
+        return;
+    }
+
+    /*
+     * AIL applies, so the new MSR gets IR and DR set, and an offset applied
+     * to the new IP.
+     */
+    *new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
+
+    if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
+        if (ail == 2) {
+            *new_nip |= 0x0000000000018000ull;
+        } else if (ail == 3) {
+            *new_nip |= 0xc000000000004000ull;
+        }
+    } else {
+        /*
+         * scv AIL is a little different. AIL=2 does not change the address,
+         * only the MSR. AIL=3 replaces the 0x17000 base with 0xc...3000.
+         */
+        if (ail == 3) {
+            *new_nip &= ~0x0000000000017000ull; /* Un-apply the base offset */
+            *new_nip |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
+        }
+    }
+}
+
+void book3s_excp(PowerPCCPU *cpu, int excp)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    int excp_model = env->excp_model;
+    PPCIntrArgs regs;
+    bool ignore;
+
+    regs.msr = env->msr & ~0x783f0000ULL;
+    regs.nip = env->nip;
+
+    /*
+     * new interrupt handler msr preserves existing HV and ME unless
+     * explicitly overriden
+     */
+    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
+
+    /* The Book3S cpus we support are 64 bit only */
+    regs.new_msr |= (target_ulong)1 << MSR_SF;
+
+    regs.sprn_srr0 = SPR_SRR0;
+    regs.sprn_srr1 = SPR_SRR1;
+
+    /*
+     * 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, &regs.msr);
+    }
+
+    /*
+     * We don't want to generate an Hypervisor emulation assistance
+     * interrupt if we don't have HVB in msr_mask (PAPR mode).
+     */
+    if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) {
+        excp = POWERPC_EXCP_PROGRAM;
+    }
+
+    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);
+    }
+
+    /* Setup interrupt-specific registers before injecting */
+    ignore = ppc_intr_prepare(cpu, interrupts_book3s, &regs, excp);
+
+    if (ignore) {
+        /* No further setup is needed for this interrupt */
+        return;
+    }
+
+    /*
+     * Sort out endianness of interrupt, this differs depending on the
+     * CPU, the HV mode, etc...
+     */
+    if (excp_model == POWERPC_EXCP_POWER7) {
+        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 (regs.new_msr & MSR_HVB) {
+            if (env->spr[SPR_HID0] & HID0_HILE) {
+                regs.new_msr |= (target_ulong)1 << MSR_LE;
+            }
+        } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
+            regs.new_msr |= (target_ulong)1 << MSR_LE;
+        }
+    } else if (excp_model == POWERPC_EXCP_POWER9 ||
+               excp_model == POWERPC_EXCP_POWER10) {
+        if (regs.new_msr & MSR_HVB) {
+            if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
+                regs.new_msr |= (target_ulong)1 << MSR_LE;
+            }
+        } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
+            regs.new_msr |= (target_ulong)1 << MSR_LE;
+        }
+    } else if (msr_ile) {
+        regs.new_msr |= (target_ulong)1 << MSR_LE;
+    }
+
+    if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
+        /* Save PC */
+        env->spr[regs.sprn_srr0] = regs.nip;
+
+        /* Save MSR */
+        env->spr[regs.sprn_srr1] = regs.msr;
+    }
+
+    /* 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, regs.new_nip, regs.new_msr);
+}
diff --git a/target/ppc/intr-booke.c b/target/ppc/intr-booke.c
new file mode 100644
index 0000000000..598d372069
--- /dev/null
+++ b/target/ppc/intr-booke.c
@@ -0,0 +1,150 @@
+/*
+ * PowerPC exception dispatching for BookE CPUs
+ *
+ * Copyright (C) 2021 IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "ppc_intr.h"
+
+static PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = {
+    [POWERPC_EXCP_ALIGN] = {
+        "Alignment", ppc_intr_alignment
+    },
+
+    [POWERPC_EXCP_CRITICAL] = {
+        "Critical input", ppc_intr_critical
+    },
+
+    [POWERPC_EXCP_DEBUG] = {
+        "Debug", ppc_intr_debug
+    },
+
+    [POWERPC_EXCP_DLTLB] = {
+        "Data load TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_DSI] = {
+        "Data storage", ppc_intr_data_storage
+    },
+
+    [POWERPC_EXCP_EXTERNAL] = {
+        "External", ppc_intr_external
+    },
+
+    [POWERPC_EXCP_FIT] = {
+        "Fixed-interval timer", ppc_intr_fit
+    },
+
+    [POWERPC_EXCP_ISI] = {
+        "Instruction storage", ppc_intr_insn_storage
+    },
+
+    [POWERPC_EXCP_MCHECK] = {
+        "Machine check", ppc_intr_machine_check
+    },
+
+    [POWERPC_EXCP_PROGRAM] = {
+        "Program", ppc_intr_program
+    },
+
+    [POWERPC_EXCP_RESET] = {
+        "System reset", ppc_intr_system_reset
+    },
+
+    [POWERPC_EXCP_SPEU] = {
+        "SPE/embedded FP unavailable/VPU", ppc_intr_spe_unavailable
+    },
+
+    [POWERPC_EXCP_SYSCALL] = {
+        "System call", ppc_intr_system_call
+    },
+
+    [POWERPC_EXCP_WDT] = {
+        "Watchdog timer", ppc_intr_watchdog
+    },
+
+    [POWERPC_EXCP_APU]   = { "Aux. processor unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
+    [POWERPC_EXCP_DTLB]  = { "Data TLB error",             ppc_intr_noop },
+    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
+
+/* Not impleemented */
+    [POWERPC_EXCP_EFPDI]    = { "Embedded floating-point data" },
+    [POWERPC_EXCP_EFPRI]    = { "Embedded floating-point round" },
+};
+
+void booke_excp(PowerPCCPU *cpu, int excp)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    PPCIntrArgs regs;
+    bool ignore;
+
+    regs.msr = env->msr;
+    regs.nip = env->nip;
+
+    /*
+     * new interrupt handler msr preserves existing HV and ME unless
+     * explicitly overriden
+     */
+    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
+
+    regs.sprn_srr0 = SPR_SRR0;
+    regs.sprn_srr1 = SPR_SRR1;
+
+    /*
+     * Hypervisor emulation assistance interrupt only exists on server
+     * arch 2.05 server or later.
+     */
+    if (excp == POWERPC_EXCP_HV_EMU) {
+        excp = POWERPC_EXCP_PROGRAM;
+    }
+
+#ifdef TARGET_PPC64
+    /*
+     * SPEU and VPU share the same IVOR but they exist in different
+     * processors. SPEU is e500v1/2 only and VPU is e6500 only.
+     */
+    if (env->excp_model == POWERPC_EXCP_BOOKE && excp == POWERPC_EXCP_VPU) {
+        excp = POWERPC_EXCP_SPEU;
+    }
+#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;
+
+    /* Setup interrupt-specific registers before injecting */
+    ignore = ppc_intr_prepare(cpu, interrupts_booke, &regs, excp);
+
+    if (ignore) {
+        /* No further setup is needed for this interrupt */
+        return;
+    }
+
+#if defined(TARGET_PPC64)
+    if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
+        /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
+        regs.new_msr |= (target_ulong)1 << MSR_CM;
+    } else {
+        regs.new_nip = (uint32_t)regs.new_nip;
+    }
+#endif
+
+    /* Save PC */
+    env->spr[regs.sprn_srr0] = regs.nip;
+
+    /* Save MSR */
+    env->spr[regs.sprn_srr1] = regs.msr;
+
+    powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
+}
diff --git a/target/ppc/intr-ppc32.c b/target/ppc/intr-ppc32.c
new file mode 100644
index 0000000000..a4b89da536
--- /dev/null
+++ b/target/ppc/intr-ppc32.c
@@ -0,0 +1,159 @@
+/*
+ * PowerPC exception dispatching for 32bit CPUs
+ *
+ * Copyright (C) 2021 IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "ppc_intr.h"
+
+static PPCInterrupt interrupts_ppc32[POWERPC_EXCP_NB] = {
+    [POWERPC_EXCP_ALIGN] = {
+        "Alignment", ppc_intr_alignment
+    },
+
+    [POWERPC_EXCP_CRITICAL] = {
+        "Critical input", ppc_intr_critical
+    },
+
+    [POWERPC_EXCP_DEBUG] = {
+        "Debug", ppc_intr_debug
+    },
+
+    [POWERPC_EXCP_DLTLB] = {
+        "Data load TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_DSI] = {
+        "Data storage", ppc_intr_data_storage
+    },
+
+    [POWERPC_EXCP_DSTLB] = {
+        "Data store TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_EXTERNAL] = {
+        "External", ppc_intr_external
+    },
+
+    [POWERPC_EXCP_FIT] = {
+        "Fixed-interval timer", ppc_intr_fit
+    },
+
+    [POWERPC_EXCP_IFTLB] = {
+        "Insn fetch TLB error", ppc_intr_tlb_miss
+    },
+
+    [POWERPC_EXCP_ISI] = {
+        "Instruction storage", ppc_intr_insn_storage
+    },
+
+    [POWERPC_EXCP_MCHECK] = {
+        "Machine check", ppc_intr_machine_check
+    },
+
+    [POWERPC_EXCP_PIT] = {
+        "Programmable interval timer", ppc_intr_programmable_timer
+    },
+
+    [POWERPC_EXCP_PROGRAM] = {
+        "Program", ppc_intr_program
+    },
+
+    [POWERPC_EXCP_RESET] = {
+        "System reset", ppc_intr_system_reset
+    },
+
+    [POWERPC_EXCP_SYSCALL] = {
+        "System call", ppc_intr_system_call
+    },
+
+    [POWERPC_EXCP_VPU] = {
+        "Vector unavailable", ppc_intr_facility_unavail
+    },
+
+    [POWERPC_EXCP_WDT] = {
+        "Watchdog timer", ppc_intr_watchdog
+    },
+
+    [POWERPC_EXCP_DECR]  = { "Decrementer",                ppc_intr_noop },
+    [POWERPC_EXCP_DTLB]  = { "Data TLB error",             ppc_intr_noop },
+    [POWERPC_EXCP_FPU]   = { "Floating-point unavailable", ppc_intr_noop },
+    [POWERPC_EXCP_ITLB]  = { "Instruction TLB error",      ppc_intr_noop },
+    [POWERPC_EXCP_TRACE] = { "Trace",                      ppc_intr_noop },
+
+/* Not implemented */
+    [POWERPC_EXCP_DABR]     = { "Data address breakpoint" },
+    [POWERPC_EXCP_DTLBE]    = { "Data TLB error" },
+    [POWERPC_EXCP_EMUL]     = { "Emulation trap" },
+    [POWERPC_EXCP_FPA]      = { "Floating-point assist" },
+    [POWERPC_EXCP_IABR]     = { "Insn address breakpoint" },
+    [POWERPC_EXCP_IO]       = { "IO error" },
+    [POWERPC_EXCP_ITLBE]    = { "Instruction TLB error" },
+    [POWERPC_EXCP_MEXTBR]   = { "Maskable external" },
+    [POWERPC_EXCP_NMEXTBR]  = { "Non-maskable external" },
+    [POWERPC_EXCP_PERFM]    = { "Performance counter" },
+    [POWERPC_EXCP_RUNM]     = { "Run mode" },
+    [POWERPC_EXCP_SMI]      = { "System management" },
+    [POWERPC_EXCP_THERM]    = { "Thermal management" },
+    [POWERPC_EXCP_VPUA]     = { "Vector assist" },
+};
+
+void ppc32_excp(PowerPCCPU *cpu, int excp)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    PPCIntrArgs regs;
+    bool ignore;
+
+    regs.msr = env->msr & ~0x783f0000ULL;
+    regs.nip = env->nip;
+
+    /*
+     * new interrupt handler msr preserves existing HV and ME unless
+     * explicitly overriden
+     */
+    regs.new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
+
+    regs.sprn_srr0 = SPR_SRR0;
+    regs.sprn_srr1 = SPR_SRR1;
+
+    /*
+     * Hypervisor emulation assistance interrupt only exists on server
+     * arch 2.05 server or later.
+     */
+    if (excp == POWERPC_EXCP_HV_EMU) {
+        excp = POWERPC_EXCP_PROGRAM;
+    }
+
+    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;
+
+    /* Setup interrupt-specific registers before injecting */
+    ignore = ppc_intr_prepare(cpu, interrupts_ppc32, &regs, excp);
+
+    if (ignore) {
+        /* No further setup is needed for this interrupt */
+        return;
+    }
+
+    if (msr_ile) {
+        regs.new_msr |= (target_ulong)1 << MSR_LE;
+    }
+
+    /* Save PC */
+    env->spr[regs.sprn_srr0] = regs.nip;
+
+    /* Save MSR */
+    env->spr[regs.sprn_srr1] = regs.msr;
+
+    powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
+}
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index 53b8e0a98e..9ec335d438 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -40,9 +40,11 @@ ppc_softmmu_ss.add(files(
   'mmu_common.c',
   'monitor.c',
   'interrupts.c',
+  'intr-booke.c',
 ))
 ppc_softmmu_ss.add(when: 'CONFIG_TCG', if_true: files(
   'mmu_helper.c',
+  'intr-ppc32.c',
 ), if_false: files(
   'tcg-stub.c',
 ))
@@ -53,6 +55,7 @@ ppc_softmmu_ss.add(when: 'TARGET_PPC64', if_true: files(
   'mmu-hash64.c',
   'mmu-radix64.c',
   'power8-pmu.c',
+  'intr-book3s.c',
 ))
 
 target_arch += {'ppc': ppc_ss}
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
index a12b3a9e4d..a0362f4248 100644
--- a/target/ppc/ppc_intr.h
+++ b/target/ppc/ppc_intr.h
@@ -27,9 +27,6 @@ void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *i
 void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_noop(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
@@ -42,11 +39,20 @@ void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
+#ifdef TARGET_PPC64
+void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+#endif
+
 int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
                      PPCIntrArgs *regs, int excp);
 
-extern PPCInterrupt interrupts_ppc32[POWERPC_EXCP_NB];
-extern PPCInterrupt interrupts_booke[POWERPC_EXCP_NB];
-extern PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB];
+void ppc32_excp(PowerPCCPU *cpu, int excp);
+void booke_excp(PowerPCCPU *cpu, int excp);
+
+#ifdef TARGET_PPC64
+void book3s_excp(PowerPCCPU *cpu, int excp);
+#endif
 
 #endif /* PPC_INTR_H */
diff --git a/target/ppc/tcg-stub.c b/target/ppc/tcg-stub.c
index aadcf59d26..2b40258b01 100644
--- a/target/ppc/tcg-stub.c
+++ b/target/ppc/tcg-stub.c
@@ -20,6 +20,7 @@
 #include "cpu.h"
 #include "internal.h"
 #include "hw/ppc/spapr.h"
+#include "ppc_intr.h"
 
 void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
 {
@@ -43,3 +44,8 @@ target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu,
 {
     g_assert_not_reached();
 }
+
+void ppc32_excp(PowerPCCPU *cpu, int excp)
+{
+    g_assert_not_reached();
+}
-- 
2.33.1



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

* [RFC v2 12/12] target/ppc: Do not enable all interrupts when running KVM
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (10 preceding siblings ...)
  2021-12-20 18:19 ` [RFC v2 11/12] target/ppc: Create new files for book3s, booke and ppc32 exception code Fabiano Rosas
@ 2021-12-20 18:19 ` Fabiano Rosas
  2021-12-26 16:48 ` [RFC v2 00/12] target/ppc: powerpc_excp improvements Cédric Le Goater
  12 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-20 18:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

When running with KVM, QEMU only needs to dispatch a few interrupts in
specific occasions, so we don't need to have all interrupts
registered. We also want to better identify code that is used with KVM
to avoid breaking the --disable-tcg|kvm builds, so this patch also
adds ifdefs to make that distinction.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/interrupts.c  | 268 ++++++++++++++++++++++-----------------
 target/ppc/intr-book3s.c |   2 +
 target/ppc/intr-booke.c  |   2 +
 target/ppc/ppc_intr.h    |  12 +-
 4 files changed, 161 insertions(+), 123 deletions(-)

diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
index 6f956029fd..be2755b1a8 100644
--- a/target/ppc/interrupts.c
+++ b/target/ppc/interrupts.c
@@ -11,7 +11,9 @@
 #include "cpu.h"
 #include "ppc_intr.h"
 #include "trace.h"
+#include "sysemu/kvm.h"
 
+#ifdef CONFIG_TCG
 /* for hreg_swap_gpr_tgpr */
 #include "helper_regs.h"
 
@@ -43,56 +45,6 @@ void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     }
 }
 
-void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    CPUState *cs = CPU(cpu);
-    CPUPPCState *env = &cpu->env;
-    int excp_model = env->excp_model;
-
-    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;
-
-        env->spr[SPR_BOOKE_CSRR0] = regs->nip;
-        env->spr[SPR_BOOKE_CSRR1] = regs->msr;
-        break;
-    default:
-        break;
-    }
-}
-
 void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
     CPUPPCState *env = &cpu->env;
@@ -165,51 +117,6 @@ void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
 }
 
-void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *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) {
-            trace_ppc_excp_fp_ignore();
-            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:
-        trace_ppc_excp_inval(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;
-    }
-}
-
 static inline void dump_syscall(CPUPPCState *env)
 {
     qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
@@ -334,30 +241,6 @@ void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     env->spr[SPR_BOOKE_ESR] = ESR_SPV;
 }
 
-void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    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(CPU(cpu), "Trying to deliver power-saving system reset "
-                      "exception with no HV support\n");
-        }
-    }
-}
-
 #ifdef TARGET_PPC64
 void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
@@ -455,6 +338,149 @@ void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
         break;
     }
 }
+#endif /* CONFIG_TCG */
+
+void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    int excp_model = env->excp_model;
+
+    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;
+#if defined(CONFIG_TCG)
+        cpu_interrupt_exittb(cs);
+#endif
+    }
+    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;
+
+        env->spr[SPR_BOOKE_CSRR0] = regs->nip;
+        env->spr[SPR_BOOKE_CSRR1] = regs->msr;
+        break;
+    default:
+        break;
+    }
+}
+
+void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *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) {
+            trace_ppc_excp_fp_ignore();
+            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:
+        trace_ppc_excp_inval(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;
+    }
+}
+
+void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    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(CPU(cpu), "Trying to deliver power-saving system reset "
+                      "exception with no HV support\n");
+        }
+    }
+}
+
+/*
+ * Book3S and BookE support KVM, but QEMU only dispatches a small
+ * set of interrupts in very specific ocasions. All other
+ * interrupts are dispatched by the real harware and QEMU knows
+ * nothing about them.
+ */
+PPCInterrupt interrupts_kvm[POWERPC_EXCP_NB] = {
+
+    [POWERPC_EXCP_MCHECK] = {
+        "Machine check", ppc_intr_machine_check
+    },
+
+    [POWERPC_EXCP_PROGRAM] = {
+        "Program", ppc_intr_program
+    },
+
+    [POWERPC_EXCP_RESET] = {
+        "System reset", ppc_intr_system_reset
+    },
+};
 
 int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
                      PPCIntrArgs *regs, int excp)
@@ -464,6 +490,10 @@ int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
     PPCInterrupt *intr;
     bool ignore = false;
 
+    if (kvm_enabled()) {
+        interrupts = interrupts_kvm;
+    }
+
     intr = &interrupts[excp];
     if (!intr->name) {
         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
diff --git a/target/ppc/intr-book3s.c b/target/ppc/intr-book3s.c
index cd279de346..a475c668ed 100644
--- a/target/ppc/intr-book3s.c
+++ b/target/ppc/intr-book3s.c
@@ -11,6 +11,7 @@
 #include "ppc_intr.h"
 
 static PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = {
+#ifdef CONFIG_TCG
     [POWERPC_EXCP_ALIGN] = {
         "Alignment", ppc_intr_alignment
     },
@@ -88,6 +89,7 @@ static PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = {
     [POWERPC_EXCP_SDOOR]    = { "Server doorbell" },
     [POWERPC_EXCP_THERM]    = { "Thermal management" },
     [POWERPC_EXCP_VPUA]     = { "Vector assist" },
+#endif
 };
 
 static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
diff --git a/target/ppc/intr-booke.c b/target/ppc/intr-booke.c
index 598d372069..9297b14ed6 100644
--- a/target/ppc/intr-booke.c
+++ b/target/ppc/intr-booke.c
@@ -11,6 +11,7 @@
 #include "ppc_intr.h"
 
 static PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = {
+#ifdef CONFIG_TCG
     [POWERPC_EXCP_ALIGN] = {
         "Alignment", ppc_intr_alignment
     },
@@ -76,6 +77,7 @@ static PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = {
 /* Not impleemented */
     [POWERPC_EXCP_EFPDI]    = { "Embedded floating-point data" },
     [POWERPC_EXCP_EFPRI]    = { "Embedded floating-point round" },
+#endif
 };
 
 void booke_excp(PowerPCCPU *cpu, int excp)
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
index a0362f4248..4aab37ea28 100644
--- a/target/ppc/ppc_intr.h
+++ b/target/ppc/ppc_intr.h
@@ -19,6 +19,7 @@ struct PPCInterrupt {
     ppc_intr_fn_t fn;
 };
 
+#ifdef CONFIG_TCG
 void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
@@ -28,14 +29,11 @@ void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_noop(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_programmable_timer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_system_call(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
@@ -43,7 +41,13 @@ void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-#endif
+#endif /* TARGET_PPC64 */
+
+#endif /* CONFIG_TCG */
+
+void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
 int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
                      PPCIntrArgs *regs, int excp);
-- 
2.33.1



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

* Re: [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly
  2021-12-20 18:18 ` [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly Fabiano Rosas
@ 2021-12-21 23:32   ` Richard Henderson
  2021-12-22  6:46   ` Cédric Le Goater
  2021-12-23  4:39   ` David Gibson
  2 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2021-12-21 23:32 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

On 12/20/21 10:18 AM, Fabiano Rosas wrote:
> There are currently only two interrupts that use alternate SRRs, so
> let them write to them directly during the setup code.
> 
> No functional change intented.
> 
> Signed-off-by: Fabiano Rosas<farosas@linux.ibm.com>
> ---
>   target/ppc/excp_helper.c | 23 ++++++++---------------
>   1 file changed, 8 insertions(+), 15 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly
  2021-12-20 18:18 ` [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly Fabiano Rosas
  2021-12-21 23:32   ` Richard Henderson
@ 2021-12-22  6:46   ` Cédric Le Goater
  2021-12-23  4:39   ` David Gibson
  2 siblings, 0 replies; 29+ messages in thread
From: Cédric Le Goater @ 2021-12-22  6:46 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, david

On 12/20/21 19:18, Fabiano Rosas wrote:
> There are currently only two interrupts that use alternate SRRs, so
> let them write to them directly during the setup code.
> 
> No functional change intented.

intended.

> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.
     

> ---
>   target/ppc/excp_helper.c | 23 ++++++++---------------
>   1 file changed, 8 insertions(+), 15 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index f90e616aac..8b9c6bc5a8 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -298,7 +298,7 @@ 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;
> +    int srr0, srr1, lev = -1;
>   
>       qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
>                     " => %08x (%02x)\n", env->nip, excp, env->error_code);
> @@ -319,8 +319,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>       /* target registers */
>       srr0 = SPR_SRR0;
>       srr1 = SPR_SRR1;
> -    asrr0 = -1;
> -    asrr1 = -1;
>   
>       /*
>        * check for special resume at 0x100 from doze/nap/sleep/winkle on
> @@ -410,8 +408,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>               /* 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;
> +
> +            env->spr[SPR_BOOKE_CSRR0] = env->nip;
> +            env->spr[SPR_BOOKE_CSRR1] = msr;
>               break;
>           default:
>               break;
> @@ -570,8 +569,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>               /* 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;
> +
> +            env->spr[SPR_BOOKE_CSRR0] = env->nip;
> +            env->spr[SPR_BOOKE_CSRR1] = msr;
> +
>               /* DBSR already modified by caller */
>           } else {
>               cpu_abort(cs, "Debug exception triggered on unsupported model\n");
> @@ -838,14 +839,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>   
>       vector |= env->excp_prefix;
>   
> -    /* If any alternate SRR register are defined, duplicate saved values */
> -    if (asrr0 != -1) {
> -        env->spr[asrr0] = env->nip;
> -    }
> -    if (asrr1 != -1) {
> -        env->spr[asrr1] = msr;
> -    }
> -
>   #if defined(TARGET_PPC64)
>       if (excp_model == POWERPC_EXCP_BOOKE) {
>           if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
> 



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

* Re: [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier
  2021-12-20 18:18 ` [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier Fabiano Rosas
@ 2021-12-22  6:48   ` Cédric Le Goater
  2021-12-25 10:45     ` Nicholas Piggin
  2021-12-24  0:11   ` Richard Henderson
  1 sibling, 1 reply; 29+ messages in thread
From: Cédric Le Goater @ 2021-12-22  6:48 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, Nicholas Piggin, david

Adding Nicholas.

On 12/20/21 19:18, Fabiano Rosas wrote:
> None of the interrupt setup code touches 'vector', so we can move it
> earlier in the function. This will allow us to later move the System
> Call Vectored setup that is on the top level into the
> POWERPC_EXCP_SYSCALL_VECTORED code block.
> 
> This patch also moves the verification for when 'excp' does not have
> an address associated with it. We now bail a little earlier when that
> is the case. This should not cause any visible effects.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.
     
> ---
>   target/ppc/excp_helper.c | 16 ++++++++--------
>   1 file changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 8b9c6bc5a8..14fd0213a0 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -352,6 +352,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>       }
>   #endif
>   
> +    vector = env->excp_vectors[excp];
> +    if (vector == (target_ulong)-1ULL) {
> +        cpu_abort(cs, "Raised an exception without defined vector %d\n",
> +                  excp);
> +    }
> +
> +    vector |= env->excp_prefix;
> +
>       switch (excp) {
>       case POWERPC_EXCP_NONE:
>           /* Should never happen */
> @@ -831,14 +839,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>       }
>   #endif
>   
> -    vector = env->excp_vectors[excp];
> -    if (vector == (target_ulong)-1ULL) {
> -        cpu_abort(cs, "Raised an exception without defined vector %d\n",
> -                  excp);
> -    }
> -
> -    vector |= env->excp_prefix;
> -
>   #if defined(TARGET_PPC64)
>       if (excp_model == POWERPC_EXCP_BOOKE) {
>           if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
> 



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

* Re: [RFC v2 03/12] target/ppc: powerpc_excp: Move system call vectored code together
  2021-12-20 18:18 ` [RFC v2 03/12] target/ppc: powerpc_excp: Move system call vectored code together Fabiano Rosas
@ 2021-12-22  6:48   ` Cédric Le Goater
  2021-12-24  0:12   ` Richard Henderson
  1 sibling, 0 replies; 29+ messages in thread
From: Cédric Le Goater @ 2021-12-22  6:48 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, Nicholas Piggin, david

Adding Nicholas.

On 12/20/21 19:18, Fabiano Rosas wrote:
> Now that 'vector' is known before calling the interrupt-specific setup
> code, we can move all of the scv setup into one place.
> 
> No functional change intended.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>

Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.
     

> ---
>   target/ppc/excp_helper.c | 13 +++++--------
>   1 file changed, 5 insertions(+), 8 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 14fd0213a0..7bdc1e8410 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -549,6 +549,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>           env->nip += 4;
>           new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
>           new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> +
> +        vector += lev * 0x20;
> +
> +        env->lr = env->nip;
> +        env->ctr = msr;
>           break;
>       case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
>       case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
> @@ -862,14 +867,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>   
>           /* Save MSR */
>           env->spr[srr1] = msr;
> -
> -#if defined(TARGET_PPC64)
> -    } else {
> -        vector += lev * 0x20;
> -
> -        env->lr = env->nip;
> -        env->ctr = msr;
> -#endif
>       }
>   
>       /* This can update new_msr and vector if AIL applies */
> 



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

* Re: [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around
  2021-12-20 18:18 ` [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around Fabiano Rosas
@ 2021-12-22  6:48   ` Cédric Le Goater
  2021-12-24  0:13   ` Richard Henderson
  2021-12-25  6:33   ` David Gibson
  2 siblings, 0 replies; 29+ messages in thread
From: Cédric Le Goater @ 2021-12-22  6:48 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, david

On 12/20/21 19:18, Fabiano Rosas wrote:
> We can just access it directly in powerpc_excp.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>


Reviewed-by: Cédric Le Goater <clg@kaod.org>

Thanks,

C.

> ---
>   target/ppc/excp_helper.c | 43 ++++++++++++++++++++--------------------
>   1 file changed, 21 insertions(+), 22 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 7bdc1e8410..45641f6d1d 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -293,10 +293,11 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
>    * Note that this function should be greatly optimized when called
>    * with a constant excp, from ppc_hw_interrupt
>    */
> -static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
> +static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>   {
>       CPUState *cs = CPU(cpu);
>       CPUPPCState *env = &cpu->env;
> +    int excp_model = env->excp_model;
>       target_ulong msr, new_msr, vector;
>       int srr0, srr1, lev = -1;
>   
> @@ -878,9 +879,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>   void ppc_cpu_do_interrupt(CPUState *cs)
>   {
>       PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
>   
> -    powerpc_excp(cpu, env->excp_model, cs->exception_index);
> +    powerpc_excp(cpu, cs->exception_index);
>   }
>   
>   static void ppc_hw_interrupt(CPUPPCState *env)
> @@ -891,20 +891,20 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>       /* External reset */
>       if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
>           env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
> -        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
> +        powerpc_excp(cpu, POWERPC_EXCP_RESET);
>           return;
>       }
>       /* Machine check exception */
>       if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
>           env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
> -        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
> +        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
>           return;
>       }
>   #if 0 /* TODO */
>       /* External debug exception */
>       if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
>           env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
> -        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
> +        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
>           return;
>       }
>   #endif
> @@ -924,7 +924,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>           if ((async_deliver || msr_hv == 0) && hdice) {
>               /* HDEC clears on delivery */
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
> +            powerpc_excp(cpu, POWERPC_EXCP_HDECR);
>               return;
>           }
>       }
> @@ -934,7 +934,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>           /* LPCR will be clear when not supported so this will work */
>           bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
>           if ((async_deliver || msr_hv == 0) && hvice) {
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT);
> +            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
>               return;
>           }
>       }
> @@ -946,14 +946,14 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>           /* HEIC blocks delivery to the hypervisor */
>           if ((async_deliver && !(heic && msr_hv && !msr_pr)) ||
>               (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
> +            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
>               return;
>           }
>       }
>       if (msr_ce != 0) {
>           /* External critical interrupt */
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
> +            powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
>               return;
>           }
>       }
> @@ -961,24 +961,24 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>           /* Watchdog timer on embedded PowerPC */
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
> +            powerpc_excp(cpu, POWERPC_EXCP_WDT);
>               return;
>           }
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
> +            powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
>               return;
>           }
>           /* Fixed interval timer on embedded PowerPC */
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
> +            powerpc_excp(cpu, POWERPC_EXCP_FIT);
>               return;
>           }
>           /* Programmable interval timer on embedded PowerPC */
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
> +            powerpc_excp(cpu, POWERPC_EXCP_PIT);
>               return;
>           }
>           /* Decrementer exception */
> @@ -986,32 +986,32 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>               if (ppc_decr_clear_on_delivery(env)) {
>                   env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
>               }
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
> +            powerpc_excp(cpu, POWERPC_EXCP_DECR);
>               return;
>           }
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
>               if (is_book3s_arch2x(env)) {
> -                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR);
> +                powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
>               } else {
> -                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
> +                powerpc_excp(cpu, POWERPC_EXCP_DOORI);
>               }
>               return;
>           }
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
> +            powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
>               return;
>           }
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
> +            powerpc_excp(cpu, POWERPC_EXCP_PERFM);
>               return;
>           }
>           /* Thermal interrupt */
>           if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
>               env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
> +            powerpc_excp(cpu, POWERPC_EXCP_THERM);
>               return;
>           }
>       }
> @@ -1036,9 +1036,8 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>   void ppc_cpu_do_system_reset(CPUState *cs)
>   {
>       PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
>   
> -    powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
> +    powerpc_excp(cpu, POWERPC_EXCP_RESET);
>   }
>   
>   void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
> 



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

* Re: [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly
  2021-12-20 18:18 ` [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly Fabiano Rosas
  2021-12-21 23:32   ` Richard Henderson
  2021-12-22  6:46   ` Cédric Le Goater
@ 2021-12-23  4:39   ` David Gibson
  2 siblings, 0 replies; 29+ messages in thread
From: David Gibson @ 2021-12-23  4:39 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: danielhb413, qemu-ppc, qemu-devel, clg

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

On Mon, Dec 20, 2021 at 03:18:52PM -0300, Fabiano Rosas wrote:
> There are currently only two interrupts that use alternate SRRs, so
> let them write to them directly during the setup code.
> 
> No functional change intented.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  target/ppc/excp_helper.c | 23 ++++++++---------------
>  1 file changed, 8 insertions(+), 15 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index f90e616aac..8b9c6bc5a8 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -298,7 +298,7 @@ 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;
> +    int srr0, srr1, lev = -1;
>  
>      qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
>                    " => %08x (%02x)\n", env->nip, excp, env->error_code);
> @@ -319,8 +319,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      /* target registers */
>      srr0 = SPR_SRR0;
>      srr1 = SPR_SRR1;
> -    asrr0 = -1;
> -    asrr1 = -1;
>  
>      /*
>       * check for special resume at 0x100 from doze/nap/sleep/winkle on
> @@ -410,8 +408,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              /* 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;
> +
> +            env->spr[SPR_BOOKE_CSRR0] = env->nip;
> +            env->spr[SPR_BOOKE_CSRR1] = msr;
>              break;
>          default:
>              break;
> @@ -570,8 +569,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              /* 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;
> +
> +            env->spr[SPR_BOOKE_CSRR0] = env->nip;
> +            env->spr[SPR_BOOKE_CSRR1] = msr;
> +
>              /* DBSR already modified by caller */
>          } else {
>              cpu_abort(cs, "Debug exception triggered on unsupported model\n");
> @@ -838,14 +839,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>  
>      vector |= env->excp_prefix;
>  
> -    /* If any alternate SRR register are defined, duplicate saved values */
> -    if (asrr0 != -1) {
> -        env->spr[asrr0] = env->nip;
> -    }
> -    if (asrr1 != -1) {
> -        env->spr[asrr1] = msr;
> -    }
> -
>  #if defined(TARGET_PPC64)
>      if (excp_model == POWERPC_EXCP_BOOKE) {
>          if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {

-- 
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] 29+ messages in thread

* Re: [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier
  2021-12-20 18:18 ` [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier Fabiano Rosas
  2021-12-22  6:48   ` Cédric Le Goater
@ 2021-12-24  0:11   ` Richard Henderson
  2021-12-24 11:14     ` Fabiano Rosas
  1 sibling, 1 reply; 29+ messages in thread
From: Richard Henderson @ 2021-12-24  0:11 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

On 12/20/21 10:18 AM, Fabiano Rosas wrote:
> None of the interrupt setup code touches 'vector', so we can move it
> earlier in the function. This will allow us to later move the System
> Call Vectored setup that is on the top level into the
> POWERPC_EXCP_SYSCALL_VECTORED code block.
> 
> This patch also moves the verification for when 'excp' does not have
> an address associated with it. We now bail a little earlier when that
> is the case. This should not cause any visible effects.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
> ---
>   target/ppc/excp_helper.c | 16 ++++++++--------
>   1 file changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 8b9c6bc5a8..14fd0213a0 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -352,6 +352,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>       }
>   #endif
>   
> +    vector = env->excp_vectors[excp];
> +    if (vector == (target_ulong)-1ULL) {
> +        cpu_abort(cs, "Raised an exception without defined vector %d\n",
> +                  excp);
> +    }
> +
> +    vector |= env->excp_prefix;
> +
>       switch (excp) {
>       case POWERPC_EXCP_NONE:
>           /* Should never happen */

You've moved the cpu_abort above the excp check above the early return for NONE (which 
possibly shouldn't exist) and above the excp default

         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);

I would certainly expect invalid excp to not have a defined vector either.

I'll also note that the excp_vectors[] index is no longer bounds checked by the switch.


r~


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

* Re: [RFC v2 03/12] target/ppc: powerpc_excp: Move system call vectored code together
  2021-12-20 18:18 ` [RFC v2 03/12] target/ppc: powerpc_excp: Move system call vectored code together Fabiano Rosas
  2021-12-22  6:48   ` Cédric Le Goater
@ 2021-12-24  0:12   ` Richard Henderson
  1 sibling, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2021-12-24  0:12 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

On 12/20/21 10:18 AM, Fabiano Rosas wrote:
> Now that 'vector' is known before calling the interrupt-specific setup
> code, we can move all of the scv setup into one place.
> 
> No functional change intended.
> 
> Signed-off-by: Fabiano Rosas<farosas@linux.ibm.com>
> ---
>   target/ppc/excp_helper.c | 13 +++++--------
>   1 file changed, 5 insertions(+), 8 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around
  2021-12-20 18:18 ` [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around Fabiano Rosas
  2021-12-22  6:48   ` Cédric Le Goater
@ 2021-12-24  0:13   ` Richard Henderson
  2021-12-25  6:33   ` David Gibson
  2 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2021-12-24  0:13 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

On 12/20/21 10:18 AM, Fabiano Rosas wrote:
> We can just access it directly in powerpc_excp.
> 
> Signed-off-by: Fabiano Rosas<farosas@linux.ibm.com>
> ---
>   target/ppc/excp_helper.c | 43 ++++++++++++++++++++--------------------
>   1 file changed, 21 insertions(+), 22 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


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

* Re: [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier
  2021-12-24  0:11   ` Richard Henderson
@ 2021-12-24 11:14     ` Fabiano Rosas
  0 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-24 11:14 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david

Richard Henderson <richard.henderson@linaro.org> writes:

> On 12/20/21 10:18 AM, Fabiano Rosas wrote:
>> None of the interrupt setup code touches 'vector', so we can move it
>> earlier in the function. This will allow us to later move the System
>> Call Vectored setup that is on the top level into the
>> POWERPC_EXCP_SYSCALL_VECTORED code block.
>> 
>> This patch also moves the verification for when 'excp' does not have
>> an address associated with it. We now bail a little earlier when that
>> is the case. This should not cause any visible effects.
>> 
>> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
>> ---
>>   target/ppc/excp_helper.c | 16 ++++++++--------
>>   1 file changed, 8 insertions(+), 8 deletions(-)
>> 
>> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
>> index 8b9c6bc5a8..14fd0213a0 100644
>> --- a/target/ppc/excp_helper.c
>> +++ b/target/ppc/excp_helper.c
>> @@ -352,6 +352,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>>       }
>>   #endif
>>   
>> +    vector = env->excp_vectors[excp];
>> +    if (vector == (target_ulong)-1ULL) {
>> +        cpu_abort(cs, "Raised an exception without defined vector %d\n",
>> +                  excp);
>> +    }
>> +
>> +    vector |= env->excp_prefix;
>> +
>>       switch (excp) {
>>       case POWERPC_EXCP_NONE:
>>           /* Should never happen */
>
> You've moved the cpu_abort above the excp check above the early return for NONE (which 
> possibly shouldn't exist) and above the excp default

Right, I think I had this patch initially after patch 7 which moves the
NONE check ealier in the function. I'll reorganize.

>          cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
>
> I would certainly expect invalid excp to not have a defined vector
> either.

One thing we always had that this series makes more explicit is the
distinction between what interrupts QEMU knows about and what vectors a
processor uses. I have played around with using the same data structure
to hold both, which would perhaps match the expectation more closely,
but nothing came out of it. I think there's still space after this
series for further improvement in that regard.

> I'll also note that the excp_vectors[] index is no longer bounds checked by the switch.

Ack.


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

* Re: [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around
  2021-12-20 18:18 ` [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around Fabiano Rosas
  2021-12-22  6:48   ` Cédric Le Goater
  2021-12-24  0:13   ` Richard Henderson
@ 2021-12-25  6:33   ` David Gibson
  2 siblings, 0 replies; 29+ messages in thread
From: David Gibson @ 2021-12-25  6:33 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: danielhb413, qemu-ppc, qemu-devel, clg

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

On Mon, Dec 20, 2021 at 03:18:55PM -0300, Fabiano Rosas wrote:
> We can just access it directly in powerpc_excp.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

> ---
>  target/ppc/excp_helper.c | 43 ++++++++++++++++++++--------------------
>  1 file changed, 21 insertions(+), 22 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 7bdc1e8410..45641f6d1d 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -293,10 +293,11 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
>   * Note that this function should be greatly optimized when called
>   * with a constant excp, from ppc_hw_interrupt
>   */
> -static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
> +static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>  {
>      CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
> +    int excp_model = env->excp_model;
>      target_ulong msr, new_msr, vector;
>      int srr0, srr1, lev = -1;
>  
> @@ -878,9 +879,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>  void ppc_cpu_do_interrupt(CPUState *cs)
>  {
>      PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
>  
> -    powerpc_excp(cpu, env->excp_model, cs->exception_index);
> +    powerpc_excp(cpu, cs->exception_index);
>  }
>  
>  static void ppc_hw_interrupt(CPUPPCState *env)
> @@ -891,20 +891,20 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>      /* External reset */
>      if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
>          env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
> -        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
> +        powerpc_excp(cpu, POWERPC_EXCP_RESET);
>          return;
>      }
>      /* Machine check exception */
>      if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
>          env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
> -        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
> +        powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
>          return;
>      }
>  #if 0 /* TODO */
>      /* External debug exception */
>      if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
>          env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
> -        powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
> +        powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
>          return;
>      }
>  #endif
> @@ -924,7 +924,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>          if ((async_deliver || msr_hv == 0) && hdice) {
>              /* HDEC clears on delivery */
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
> +            powerpc_excp(cpu, POWERPC_EXCP_HDECR);
>              return;
>          }
>      }
> @@ -934,7 +934,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>          /* LPCR will be clear when not supported so this will work */
>          bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
>          if ((async_deliver || msr_hv == 0) && hvice) {
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT);
> +            powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
>              return;
>          }
>      }
> @@ -946,14 +946,14 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>          /* HEIC blocks delivery to the hypervisor */
>          if ((async_deliver && !(heic && msr_hv && !msr_pr)) ||
>              (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
> +            powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
>              return;
>          }
>      }
>      if (msr_ce != 0) {
>          /* External critical interrupt */
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
> +            powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
>              return;
>          }
>      }
> @@ -961,24 +961,24 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>          /* Watchdog timer on embedded PowerPC */
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
> +            powerpc_excp(cpu, POWERPC_EXCP_WDT);
>              return;
>          }
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
> +            powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
>              return;
>          }
>          /* Fixed interval timer on embedded PowerPC */
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
> +            powerpc_excp(cpu, POWERPC_EXCP_FIT);
>              return;
>          }
>          /* Programmable interval timer on embedded PowerPC */
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
> +            powerpc_excp(cpu, POWERPC_EXCP_PIT);
>              return;
>          }
>          /* Decrementer exception */
> @@ -986,32 +986,32 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>              if (ppc_decr_clear_on_delivery(env)) {
>                  env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
>              }
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
> +            powerpc_excp(cpu, POWERPC_EXCP_DECR);
>              return;
>          }
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
>              if (is_book3s_arch2x(env)) {
> -                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR);
> +                powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
>              } else {
> -                powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
> +                powerpc_excp(cpu, POWERPC_EXCP_DOORI);
>              }
>              return;
>          }
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
> +            powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
>              return;
>          }
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
> +            powerpc_excp(cpu, POWERPC_EXCP_PERFM);
>              return;
>          }
>          /* Thermal interrupt */
>          if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
>              env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
> -            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
> +            powerpc_excp(cpu, POWERPC_EXCP_THERM);
>              return;
>          }
>      }
> @@ -1036,9 +1036,8 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>  void ppc_cpu_do_system_reset(CPUState *cs)
>  {
>      PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    CPUPPCState *env = &cpu->env;
>  
> -    powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
> +    powerpc_excp(cpu, POWERPC_EXCP_RESET);
>  }
>  
>  void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)

-- 
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] 29+ messages in thread

* Re: [RFC v2 05/12] target/ppc: powerpc_excp: Standardize arguments to interrupt code
  2021-12-20 18:18 ` [RFC v2 05/12] target/ppc: powerpc_excp: Standardize arguments to interrupt code Fabiano Rosas
@ 2021-12-25  6:35   ` David Gibson
  2021-12-27 17:13     ` Fabiano Rosas
  0 siblings, 1 reply; 29+ messages in thread
From: David Gibson @ 2021-12-25  6:35 UTC (permalink / raw)
  To: Fabiano Rosas; +Cc: danielhb413, qemu-ppc, qemu-devel, clg

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

On Mon, Dec 20, 2021 at 03:18:56PM -0300, Fabiano Rosas wrote:
> In preparation to moving the interrupt code into separate functions,
> create a PPCIntrArgs structure to serve as a consistent API.

The patch doesn't seem to match this description - I see no new
structure here.

> 
> No functional change intended.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
> ---
>  target/ppc/excp_helper.c | 213 +++++++++++++++++++++------------------
>  1 file changed, 113 insertions(+), 100 deletions(-)
> 
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 45641f6d1d..f478ff8a87 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -164,7 +164,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;
> @@ -241,9 +241,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 {
>          /*
> @@ -251,15 +251,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;
> @@ -272,9 +272,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;
> @@ -289,6 +289,15 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
>      check_tlb_flush(env, false);
>  }
>  
> +typedef struct PPCIntrArgs {
> +    target_ulong nip;
> +    target_ulong msr;
> +    target_ulong new_nip;
> +    target_ulong new_msr;
> +    int sprn_srr0;
> +    int sprn_srr1;
> +} PPCIntrArgs;
> +
>  /*
>   * Note that this function should be greatly optimized when called
>   * with a constant excp, from ppc_hw_interrupt
> @@ -298,35 +307,35 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>      CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
>      int excp_model = env->excp_model;
> -    target_ulong msr, new_msr, vector;
> -    int srr0, srr1, lev = -1;
> +    PPCIntrArgs 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
>       */
> -    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;
> +    regs.sprn_srr0 = SPR_SRR0;
> +    regs.sprn_srr1 = SPR_SRR1;
>  
>      /*
>       * 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);
>      }
>  
>      /*
> @@ -353,13 +362,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>      }
>  #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;
>  
>      switch (excp) {
>      case POWERPC_EXCP_NONE:
> @@ -368,12 +377,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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;
> @@ -401,25 +410,25 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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;
> +            regs.sprn_srr0 = SPR_BOOKE_MCSRR0;
> +            regs.sprn_srr1 = SPR_BOOKE_MCSRR1;
>  
> -            env->spr[SPR_BOOKE_CSRR0] = env->nip;
> -            env->spr[SPR_BOOKE_CSRR1] = msr;
> +            env->spr[SPR_BOOKE_CSRR0] = regs.nip;
> +            env->spr[SPR_BOOKE_CSRR1] = regs.msr;
>              break;
>          default:
>              break;
> @@ -429,8 +438,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>          trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
>          break;
>      case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
> -        trace_ppc_excp_isi(msr, env->nip);
> -        msr |= env->error_code;
> +        trace_ppc_excp_isi(regs.msr, regs.nip);
> +        regs.msr |= env->error_code;
>          break;
>      case POWERPC_EXCP_EXTERNAL:  /* External input                           */
>      {
> @@ -460,10 +469,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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 */
> @@ -495,20 +504,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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:
> -            trace_ppc_excp_inval(env->nip);
> -            msr |= 0x00080000;
> +            trace_ppc_excp_inval(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:
> @@ -529,9 +538,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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) {
> @@ -540,21 +552,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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);
>  
> -        vector += lev * 0x20;
> +        regs.new_nip += lev * 0x20;
>  
> -        env->lr = env->nip;
> -        env->ctr = msr;
> +        env->lr = regs.nip;
> +        env->ctr = regs.msr;
>          break;
>      case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
>      case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
> @@ -568,8 +581,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>          trace_ppc_excp_print("WDT");
>          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;
> @@ -581,12 +594,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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;
> -
> -            env->spr[SPR_BOOKE_CSRR0] = env->nip;
> -            env->spr[SPR_BOOKE_CSRR1] = msr;
> +            regs.sprn_srr0 = SPR_BOOKE_DSRR0;
> +            regs.sprn_srr1 = SPR_BOOKE_DSRR1;
>  
> +            env->spr[SPR_BOOKE_CSRR0] = regs.nip;
> +            env->spr[SPR_BOOKE_CSRR1] = regs.msr;
>              /* DBSR already modified by caller */
>          } else {
>              cpu_abort(cs, "Debug exception triggered on unsupported model\n");
> @@ -615,22 +627,22 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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 "
> @@ -643,7 +655,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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        */
> @@ -652,10 +664,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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               */
> @@ -667,10 +679,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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 +709,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>          case POWERPC_EXCP_603:
>          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 +743,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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;
>          default:
>              cpu_abort(cs, "Invalid TLB miss exception\n");
> @@ -800,11 +812,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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);
>          }
> @@ -816,32 +828,32 @@ static inline void powerpc_excp(PowerPCCPU *cpu, 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
>  
> @@ -849,31 +861,32 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>      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;
>      }
>  
> -    /* 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] 29+ messages in thread

* Re: [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier
  2021-12-22  6:48   ` Cédric Le Goater
@ 2021-12-25 10:45     ` Nicholas Piggin
  0 siblings, 0 replies; 29+ messages in thread
From: Nicholas Piggin @ 2021-12-25 10:45 UTC (permalink / raw)
  To: Cédric Le Goater, Fabiano Rosas, qemu-devel
  Cc: danielhb413, qemu-ppc, david

Excerpts from Cédric Le Goater's message of December 22, 2021 4:48 pm:
> Adding Nicholas.

These look fine by me. The whole series looks like a really nice
cleanup actually.

Thanks,
Nick

> 
> On 12/20/21 19:18, Fabiano Rosas wrote:
>> None of the interrupt setup code touches 'vector', so we can move it
>> earlier in the function. This will allow us to later move the System
>> Call Vectored setup that is on the top level into the
>> POWERPC_EXCP_SYSCALL_VECTORED code block.
>> 
>> This patch also moves the verification for when 'excp' does not have
>> an address associated with it. We now bail a little earlier when that
>> is the case. This should not cause any visible effects.
>> 
>> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
> 
> 
> Reviewed-by: Cédric Le Goater <clg@kaod.org>
> 
> Thanks,
> 
> C.
>      
>> ---
>>   target/ppc/excp_helper.c | 16 ++++++++--------
>>   1 file changed, 8 insertions(+), 8 deletions(-)
>> 
>> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
>> index 8b9c6bc5a8..14fd0213a0 100644
>> --- a/target/ppc/excp_helper.c
>> +++ b/target/ppc/excp_helper.c
>> @@ -352,6 +352,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>>       }
>>   #endif
>>   
>> +    vector = env->excp_vectors[excp];
>> +    if (vector == (target_ulong)-1ULL) {
>> +        cpu_abort(cs, "Raised an exception without defined vector %d\n",
>> +                  excp);
>> +    }
>> +
>> +    vector |= env->excp_prefix;
>> +
>>       switch (excp) {
>>       case POWERPC_EXCP_NONE:
>>           /* Should never happen */
>> @@ -831,14 +839,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>>       }
>>   #endif
>>   
>> -    vector = env->excp_vectors[excp];
>> -    if (vector == (target_ulong)-1ULL) {
>> -        cpu_abort(cs, "Raised an exception without defined vector %d\n",
>> -                  excp);
>> -    }
>> -
>> -    vector |= env->excp_prefix;
>> -
>>   #if defined(TARGET_PPC64)
>>       if (excp_model == POWERPC_EXCP_BOOKE) {
>>           if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
>> 
> 
> 


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

* Re: [RFC v2 00/12] target/ppc: powerpc_excp improvements
  2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
                   ` (11 preceding siblings ...)
  2021-12-20 18:19 ` [RFC v2 12/12] target/ppc: Do not enable all interrupts when running KVM Fabiano Rosas
@ 2021-12-26 16:48 ` Cédric Le Goater
  2021-12-29 14:18   ` Fabiano Rosas
  12 siblings, 1 reply; 29+ messages in thread
From: Cédric Le Goater @ 2021-12-26 16:48 UTC (permalink / raw)
  To: Fabiano Rosas, qemu-devel; +Cc: danielhb413, qemu-ppc, david

Hello Fabiano,

On 12/20/21 19:18, Fabiano Rosas wrote:
> This changed a lot since v1, basically what remains is the idea that
> we want to have some sort of array of interrupts and some sort of
> separation between processors.
> 
> At the end of this series we'll have:
> 
> - One file with all interrupt implementations (interrupts.c);
> 
> - Separate files for each major group of CPUs (book3s, booke,
>    32bits). Only interrupt code for now, but we could bring pieces of
>    cpu_init into them;
> 
> - Four separate interrupt arrays, one for each of the above groups
>    plus KVM.
> 
> - powerpc_excp calls into the individual files and from there we
>    dispatch according to what is available in the interrupts array.


This is going in the good direction. I think we need more steps for
the reviewers, for tests and bisectability. First 4 patches are OK
and I hope to merge them ASAP.

The powerpc_excp() routine has grown nearly out of control these last
years and it is becoming difficult to maintain. The goal is to clarify
what it is going on for each CPU or each CPU family. The first step
consists basically in duplicating the code and moving the exceptions
handlers in specific routines.

1. cleanups should come first as usual.

2. isolate large chunks, like Nick did with ppc_excp_apply_ail().
    We could do easily the same for :

    2.1 ILE
    2.2 unimplemeted ones doing a cpu abort:
     
          cpu_abort(cs, ".... "  "is not implemented yet !\n");
    2.3 6x TLBS

    This should reduce considerably powerpc_excp() without changing too
    much the execution path.

3. Cleanup the use of excp_model, like in dcbz_common() and kvm.
    This is not critical but some are shortcuts.

4. Introduce a new powerpc_excp() handler :

    static void powerpc_excp(PowerPCCPU *cpu, int excp)
    {
        switch(env->excp_model) {
        case POWERPC_EXCP_FOO1:
        case POWERPC_EXCP_FOO2:
            powerpc_excp_foo(cpu, excp);
	   break;
        case POWERPC_EXCP_BAR:
            powerpc_excp_legacy(cpu, excp);
	   break;
        default:
            g_assert_not_reached();
        }
    }

    and start duplicating code cpu per cpu in specific excp handlers, avoiding
    as much as possible the use of excp_model in the powerpc_excp_*() routines.
    That's for the theory.

    I suppose these can be grouped in the following way :

    * 405 CPU
         POWERPC_EXCP_40x,

    * 6xx CPUs
         POWERPC_EXCP_601,
         POWERPC_EXCP_602,
         POWERPC_EXCP_603,
         POWERPC_EXCP_G2,
         POWERPC_EXCP_604,
	
    * 7xx CPUs
         POWERPC_EXCP_7x0,
         POWERPC_EXCP_7x5,
         POWERPC_EXCP_74xx,
	
    * BOOKE CPUs
         POWERPC_EXCP_BOOKE,

    * BOOKS CPUs
         POWERPC_EXCP_970,            /* could be special */
         POWERPC_EXCP_POWER7,
         POWERPC_EXCP_POWER8,
         POWERPC_EXCP_POWER9,
         POWERPC_EXCP_POWER10,
     
    If not possible, then, we will duplicate more and that's not a problem.

    I would keep the routines in the same excp_helper.c file for now; we
    can move the code in different files but I would do it later and with
    other components in mind and not just the exception models. book3s,
    booke, 7xx, 6xx, 405 are the different groups. It fits what you did.
    
5. Once done, get rid of powerpc_excp_legacy()

6. Start looking at refactoring again.

    There might be a common prologue and epilogue. As a consequence we could
    change the args passed to powerpc_excp_*().

    There could be common handlers and that's why an array of exception
    handlers looks good. this is what you are trying to address after patch 5
    but I would prefer to do the above steps before.

Thanks,

C.


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

* Re: [RFC v2 05/12] target/ppc: powerpc_excp: Standardize arguments to interrupt code
  2021-12-25  6:35   ` David Gibson
@ 2021-12-27 17:13     ` Fabiano Rosas
  0 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-27 17:13 UTC (permalink / raw)
  To: David Gibson; +Cc: danielhb413, qemu-ppc, qemu-devel, clg

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

> On Mon, Dec 20, 2021 at 03:18:56PM -0300, Fabiano Rosas wrote:
>> In preparation to moving the interrupt code into separate functions,
>> create a PPCIntrArgs structure to serve as a consistent API.
>
> The patch doesn't seem to match this description - I see no new
> structure here.

I didn't want to create the new ppc_intr.h header in this patch so I
might have been careless and put the structure right before the
powerpc_excp definition. See below.

>> 
>> No functional change intended.
>> 
>> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
>> ---
>>  target/ppc/excp_helper.c | 213 +++++++++++++++++++++------------------
>>  1 file changed, 113 insertions(+), 100 deletions(-)
>> 
>> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
>> index 45641f6d1d..f478ff8a87 100644
>> --- a/target/ppc/excp_helper.c
>> +++ b/target/ppc/excp_helper.c
>> @@ -164,7 +164,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;
>> @@ -241,9 +241,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 {
>>          /*
>> @@ -251,15 +251,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;
>> @@ -272,9 +272,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;
>> @@ -289,6 +289,15 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
>>      check_tlb_flush(env, false);
>>  }
>>  
>> +typedef struct PPCIntrArgs {
>> +    target_ulong nip;
>> +    target_ulong msr;
>> +    target_ulong new_nip;
>> +    target_ulong new_msr;
>> +    int sprn_srr0;
>> +    int sprn_srr1;
>> +} PPCIntrArgs;

here ^

I can have new header in this patch for the next version.

>> +
>>  /*
>>   * Note that this function should be greatly optimized when called
>>   * with a constant excp, from ppc_hw_interrupt
>> @@ -298,35 +307,35 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
>>      CPUState *cs = CPU(cpu);
>>      CPUPPCState *env = &cpu->env;
>>      int excp_model = env->excp_model;
>> -    target_ulong msr, new_msr, vector;
>> -    int srr0, srr1, lev = -1;
>> +    PPCIntrArgs regs;
>> +    int lev = -1;


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

* Re: [RFC v2 00/12] target/ppc: powerpc_excp improvements
  2021-12-26 16:48 ` [RFC v2 00/12] target/ppc: powerpc_excp improvements Cédric Le Goater
@ 2021-12-29 14:18   ` Fabiano Rosas
  0 siblings, 0 replies; 29+ messages in thread
From: Fabiano Rosas @ 2021-12-29 14:18 UTC (permalink / raw)
  To: Cédric Le Goater, qemu-devel; +Cc: danielhb413, qemu-ppc, david

Cédric Le Goater <clg@kaod.org> writes:

> Hello Fabiano,
>
> On 12/20/21 19:18, Fabiano Rosas wrote:
>> This changed a lot since v1, basically what remains is the idea that
>> we want to have some sort of array of interrupts and some sort of
>> separation between processors.
>> 
>> At the end of this series we'll have:
>> 
>> - One file with all interrupt implementations (interrupts.c);
>> 
>> - Separate files for each major group of CPUs (book3s, booke,
>>    32bits). Only interrupt code for now, but we could bring pieces of
>>    cpu_init into them;
>> 
>> - Four separate interrupt arrays, one for each of the above groups
>>    plus KVM.
>> 
>> - powerpc_excp calls into the individual files and from there we
>>    dispatch according to what is available in the interrupts array.
>
>
> This is going in the good direction. I think we need more steps for
> the reviewers, for tests and bisectability. First 4 patches are OK
> and I hope to merge them ASAP.

Ok, I'm sending another series with just these 4 + the bounds check
Richard mentioned.

>
> The powerpc_excp() routine has grown nearly out of control these last
> years and it is becoming difficult to maintain. The goal is to clarify
> what it is going on for each CPU or each CPU family. The first step
> consists basically in duplicating the code and moving the exceptions
> handlers in specific routines.
>
> 1. cleanups should come first as usual.
>
> 2. isolate large chunks, like Nick did with ppc_excp_apply_ail().
>     We could do easily the same for :
>
>     2.1 ILE
>     2.2 unimplemeted ones doing a cpu abort:
>      
>           cpu_abort(cs, ".... "  "is not implemented yet !\n");
>     2.3 6x TLBS
>
>     This should reduce considerably powerpc_excp() without changing too
>     much the execution path.

Agreed.

>
> 3. Cleanup the use of excp_model, like in dcbz_common() and kvm.
>     This is not critical but some are shortcuts.

The issue here is that we would probably be switching one arbitrary
identifier for another. I don't think we have a lightweight canonical
way of identifying a CPU or group of CPUs. But maybe having these
conditionals on a specific CPU should be considered a hack to begin
with.

>
> 4. Introduce a new powerpc_excp() handler :
>
>     static void powerpc_excp(PowerPCCPU *cpu, int excp)
>     {
>         switch(env->excp_model) {
>         case POWERPC_EXCP_FOO1:
>         case POWERPC_EXCP_FOO2:
>             powerpc_excp_foo(cpu, excp);
> 	   break;
>         case POWERPC_EXCP_BAR:
>             powerpc_excp_legacy(cpu, excp);
> 	   break;
>         default:
>             g_assert_not_reached();
>         }
>     }
>
>     and start duplicating code cpu per cpu in specific excp handlers, avoiding
>     as much as possible the use of excp_model in the powerpc_excp_*() routines.
>     That's for the theory.
>
>     I suppose these can be grouped in the following way :
>
>     * 405 CPU
>          POWERPC_EXCP_40x,
>
>     * 6xx CPUs
>          POWERPC_EXCP_601,
>          POWERPC_EXCP_602,
>          POWERPC_EXCP_603,
>          POWERPC_EXCP_G2,
>          POWERPC_EXCP_604,
> 	
>     * 7xx CPUs
>          POWERPC_EXCP_7x0,
>          POWERPC_EXCP_7x5,
>          POWERPC_EXCP_74xx,
> 	
>     * BOOKE CPUs
>          POWERPC_EXCP_BOOKE,
>
>     * BOOKS CPUs
>          POWERPC_EXCP_970,            /* could be special */
>          POWERPC_EXCP_POWER7,
>          POWERPC_EXCP_POWER8,
>          POWERPC_EXCP_POWER9,
>          POWERPC_EXCP_POWER10,
>      
>     If not possible, then, we will duplicate more and that's not a problem.
>
>     I would keep the routines in the same excp_helper.c file for now; we
>     can move the code in different files but I would do it later and with
>     other components in mind and not just the exception models. book3s,
>     booke, 7xx, 6xx, 405 are the different groups. It fits what you did.
>     
> 5. Once done, get rid of powerpc_excp_legacy()
>
> 6. Start looking at refactoring again.
>
>     There might be a common prologue and epilogue. As a consequence we could
>     change the args passed to powerpc_excp_*().
>
>     There could be common handlers and that's why an array of exception
>     handlers looks good. this is what you are trying to address after patch 5
>     but I would prefer to do the above steps before.

Ack all of this. I'm working on it.

Thank you for the inputs.


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

end of thread, other threads:[~2021-12-29 14:22 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-20 18:18 [RFC v2 00/12] target/ppc: powerpc_excp improvements Fabiano Rosas
2021-12-20 18:18 ` [RFC v2 01/12] target/ppc: powerpc_excp: Set alternate SRRs directly Fabiano Rosas
2021-12-21 23:32   ` Richard Henderson
2021-12-22  6:46   ` Cédric Le Goater
2021-12-23  4:39   ` David Gibson
2021-12-20 18:18 ` [RFC v2 02/12] target/ppc: powerpc_excp: Set vector earlier Fabiano Rosas
2021-12-22  6:48   ` Cédric Le Goater
2021-12-25 10:45     ` Nicholas Piggin
2021-12-24  0:11   ` Richard Henderson
2021-12-24 11:14     ` Fabiano Rosas
2021-12-20 18:18 ` [RFC v2 03/12] target/ppc: powerpc_excp: Move system call vectored code together Fabiano Rosas
2021-12-22  6:48   ` Cédric Le Goater
2021-12-24  0:12   ` Richard Henderson
2021-12-20 18:18 ` [RFC v2 04/12] target/ppc: powerpc_excp: Stop passing excp_model around Fabiano Rosas
2021-12-22  6:48   ` Cédric Le Goater
2021-12-24  0:13   ` Richard Henderson
2021-12-25  6:33   ` David Gibson
2021-12-20 18:18 ` [RFC v2 05/12] target/ppc: powerpc_excp: Standardize arguments to interrupt code Fabiano Rosas
2021-12-25  6:35   ` David Gibson
2021-12-27 17:13     ` Fabiano Rosas
2021-12-20 18:18 ` [RFC v2 06/12] target/ppc: Extract interrupt routines into a new file Fabiano Rosas
2021-12-20 18:18 ` [RFC v2 07/12] target/ppc: Introduce PPCInterrupt Fabiano Rosas
2021-12-20 18:18 ` [RFC v2 08/12] target/ppc: Remove unimplemented interrupt code Fabiano Rosas
2021-12-20 18:19 ` [RFC v2 09/12] target/ppc: Use common code for Hypervisor interrupts Fabiano Rosas
2021-12-20 18:19 ` [RFC v2 10/12] target/ppc: Split powerpc_excp into book3s, booke and 32 bit Fabiano Rosas
2021-12-20 18:19 ` [RFC v2 11/12] target/ppc: Create new files for book3s, booke and ppc32 exception code Fabiano Rosas
2021-12-20 18:19 ` [RFC v2 12/12] target/ppc: Do not enable all interrupts when running KVM Fabiano Rosas
2021-12-26 16:48 ` [RFC v2 00/12] target/ppc: powerpc_excp improvements Cédric Le Goater
2021-12-29 14:18   ` Fabiano Rosas

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.