[PATCH v4 1/3] target/ppc: introduce ppc_maybe_interrupt

2022-10-21 Thread Matheus Ferst
This new method will check if any pending interrupt was unmasked and
then call cpu_interrupt/cpu_reset_interrupt accordingly. Code that
raises/lowers or masks/unmasks interrupts should call this method to
keep CPU_INTERRUPT_HARD coherent with env->pending_interrupts.

Signed-off-by: Matheus Ferst 
---
v4:
  - Call gen_icount_io_start before helper_ppc_maybe_interrupt to avoid
the cpu_abort("Raised interrupt while not in I/O function")
in icount_handle_interrupt
---
 hw/ppc/pnv_core.c|  1 +
 hw/ppc/ppc.c |  7 +--
 hw/ppc/spapr_hcall.c |  6 ++
 hw/ppc/spapr_rtas.c  |  2 +-
 target/ppc/cpu.c |  2 ++
 target/ppc/cpu.h |  1 +
 target/ppc/excp_helper.c | 42 
 target/ppc/helper.h  |  1 +
 target/ppc/helper_regs.c |  2 ++
 target/ppc/translate.c   | 11 ++-
 10 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 19e8eb885f..9ee79192dd 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -58,6 +58,7 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
 env->msr |= MSR_HVB; /* Hypervisor mode */
 env->spr[SPR_HRMOR] = pc->hrmor;
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 
 pcc->intc_reset(pc->chip, cpu);
 }
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 77e611e81c..dc86c1c7db 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -42,7 +42,6 @@ static void cpu_ppc_tb_start (CPUPPCState *env);
 
 void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
-CPUState *cs = CPU(cpu);
 CPUPPCState *env = >env;
 unsigned int old_pending;
 bool locked = false;
@@ -57,19 +56,15 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 
 if (level) {
 env->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 env->pending_interrupts &= ~irq;
-if (env->pending_interrupts == 0) {
-cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
-}
 }
 
 if (old_pending != env->pending_interrupts) {
+ppc_maybe_interrupt(env);
 kvmppc_set_interrupt(cpu, irq, level);
 }
 
-
 trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 891206e893..925ff523cc 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -490,6 +490,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 
 env->msr |= (1ULL << MSR_EE);
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 
 if (spapr_cpu->prod) {
 spapr_cpu->prod = false;
@@ -500,6 +501,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 cs->halted = 1;
 cs->exception_index = EXCP_HLT;
 cs->exit_request = 1;
+ppc_maybe_interrupt(env);
 }
 
 return H_SUCCESS;
@@ -521,6 +523,7 @@ static target_ulong h_confer_self(PowerPCCPU *cpu)
 cs->halted = 1;
 cs->exception_index = EXCP_HALTED;
 cs->exit_request = 1;
+ppc_maybe_interrupt(>env);
 
 return H_SUCCESS;
 }
@@ -633,6 +636,7 @@ static target_ulong h_prod(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 spapr_cpu = spapr_cpu_state(tcpu);
 spapr_cpu->prod = true;
 cs->halted = 0;
+ppc_maybe_interrupt(>env);
 qemu_cpu_kick(cs);
 
 return H_SUCCESS;
@@ -1669,6 +1673,7 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu,
 spapr_cpu->in_nested = true;
 
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 tlb_flush(cs);
 env->reserve_addr = -1; /* Reset the reservation */
 
@@ -1810,6 +1815,7 @@ out_restore_l1:
 spapr_cpu->in_nested = false;
 
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 tlb_flush(cs);
 env->reserve_addr = -1; /* Reset the reservation */
 
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index d58b65e88f..3f664ea02c 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -214,9 +214,9 @@ static void rtas_stop_self(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
  * guest.
  * For the same reason, set PSSCR_EC.
  */
-ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
 env->spr[SPR_PSSCR] |= PSSCR_EC;
 cs->halted = 1;
+ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
 kvmppc_set_reg_ppc_online(cpu, 0);
 qemu_cpu_kick(cs);
 }
diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index e95b4c5ee1..1a97b41c6b 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -82,6 +82,8 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
 /* The gtse bit affects hflags */
 hreg_compute_hflags(env);
+
+ppc_maybe_interrupt(env);
 }
 #endif
 
dif

[PATCH v4 2/3] target/ppc: unify cpu->has_work based on cs->interrupt_request

2022-10-21 Thread Matheus Ferst
Now that cs->interrupt_request indicates if there is any unmasked
interrupt, checking if the CPU has work to do can be simplified to a
single check that works for all CPU models.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 94 +--
 1 file changed, 1 insertion(+), 93 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 0adc866485..15d549ad38 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5984,27 +5984,10 @@ int p7_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER7(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-return p7_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER7";
 dc->desc = "POWER7";
@@ -6013,7 +5996,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER7;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER7;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6170,27 +6152,10 @@ int p8_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER8(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-return p8_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER8";
 dc->desc = "POWER8";
@@ -6199,7 +6164,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER8;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER8;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6407,35 +6371,10 @@ int p9_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER9(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-uint64_t psscr = env->spr[SPR_PSSCR];
-
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-
-/* If EC is clear, just return true on any pending interrupt */
-if (!(psscr & PSSCR_EC)) {
-return true;
-}
-
-return p9_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER9";
 dc->desc = "POWER9";
@@ -6445,7 +6384,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
  PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER9;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER9;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6604,35 +6542,10 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
-static bool cpu_has_work_POWER10(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-uint64_t psscr = env->spr[SPR_PSSCR];
-
-  

[PATCH v4 3/3] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c

2022-10-21 Thread Matheus Ferst
Move the methods to excp_helper.c and make them static.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c| 102 ---
 target/ppc/excp_helper.c | 102 +++
 target/ppc/internal.h|   6 ---
 3 files changed, 102 insertions(+), 108 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 15d549ad38..6f3539f13a 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,30 +5960,6 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-int p7_interrupt_powersave(CPUPPCState *env)
-{
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
-return PPC_INTERRUPT_EXT;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
-return PPC_INTERRUPT_DECR;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return PPC_INTERRUPT_MCK;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return PPC_INTERRUPT_HMI;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
@@ -6120,38 +6096,6 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-int p8_interrupt_powersave(CPUPPCState *env)
-{
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
-return PPC_INTERRUPT_EXT;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
-return PPC_INTERRUPT_DECR;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return PPC_INTERRUPT_MCK;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return PPC_INTERRUPT_HMI;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
-return PPC_INTERRUPT_DOORBELL;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
-return PPC_INTERRUPT_HDOORBELL;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
@@ -6325,52 +6269,6 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
-int p9_interrupt_powersave(CPUPPCState *env)
-{
-/* External Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_EEE)) {
-bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-if (!heic || !FIELD_EX64_HV(env->msr) ||
-FIELD_EX64(env->msr, MSR, PR)) {
-return PPC_INTERRUPT_EXT;
-}
-}
-/* Decrementer Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_DEE)) {
-return PPC_INTERRUPT_DECR;
-}
-/* Machine Check or Hypervisor Maintenance Exception */
-if (env->spr[SPR_LPCR] & LPCR_OEE) {
-if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
-return PPC_INTERRUPT_MCK;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
-return PPC_INTERRUPT_HMI;
-}
-}
-/* Privileged Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_PDEE)) {
-return PPC_INTERRUPT_DOORBELL;
-}
-/* Hypervisor Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_HDEE)) {
-return PPC_INTERRUPT_HDOORBELL;
-}
-/* Hypervisor virtualization exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
-(env->spr[SPR_LPCR] & LPCR_HVEE)) {
-return PPC_INTERRUPT_HVIRT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
 D

[PATCH v4 0/3] PowerPC interrupt rework

2022-10-21 Thread Matheus Ferst
This version fixes the problems found by Daniel with e500 tests and
rebases on ppc-next.

Based-on: https://gitlab.com/danielhb/qemu/-/tree/ppc-next

Matheus Ferst (3):
  target/ppc: introduce ppc_maybe_interrupt
  target/ppc: unify cpu->has_work based on cs->interrupt_request
  target/ppc: move the p*_interrupt_powersave methods to excp_helper.c

 hw/ppc/pnv_core.c|   1 +
 hw/ppc/ppc.c |   7 +-
 hw/ppc/spapr_hcall.c |   6 ++
 hw/ppc/spapr_rtas.c  |   2 +-
 target/ppc/cpu.c |   2 +
 target/ppc/cpu.h |   1 +
 target/ppc/cpu_init.c| 196 +--
 target/ppc/excp_helper.c | 144 
 target/ppc/helper.h  |   1 +
 target/ppc/helper_regs.c |   2 +
 target/ppc/internal.h|   6 --
 target/ppc/translate.c   |  11 ++-
 12 files changed, 170 insertions(+), 209 deletions(-)

-- 
2.25.1




[PATCH v3 28/29] target/ppc: unify cpu->has_work based on cs->interrupt_request

2022-10-11 Thread Matheus Ferst
Now that cs->interrupt_request indicates if there is any unmasked
interrupt, checking if the CPU has work to do can be simplified to a
single check that works for all CPU models.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 94 +--
 1 file changed, 1 insertion(+), 93 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 0adc866485..15d549ad38 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5984,27 +5984,10 @@ int p7_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER7(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-return p7_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER7";
 dc->desc = "POWER7";
@@ -6013,7 +5996,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER7;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER7;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6170,27 +6152,10 @@ int p8_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER8(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-return p8_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER8";
 dc->desc = "POWER8";
@@ -6199,7 +6164,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER8;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER8;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6407,35 +6371,10 @@ int p9_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER9(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-uint64_t psscr = env->spr[SPR_PSSCR];
-
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-
-/* If EC is clear, just return true on any pending interrupt */
-if (!(psscr & PSSCR_EC)) {
-return true;
-}
-
-return p9_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER9";
 dc->desc = "POWER9";
@@ -6445,7 +6384,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
  PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER9;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER9;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6604,35 +6542,10 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
-static bool cpu_has_work_POWER10(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-uint64_t psscr = env->spr[SPR_PSSCR];
-
-  

[PATCH v3 26/29] target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds

2022-10-11 Thread Matheus Ferst
Writes to LPCR are hypervisor privileged.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu.c | 2 ++
 target/ppc/cpu.h | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index 0ebac04bc4..e95b4c5ee1 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -73,6 +73,7 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value)
 hreg_store_msr(env, value, 0);
 }
 
+#if !defined(CONFIG_USER_ONLY)
 void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 {
 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
@@ -82,6 +83,7 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 /* The gtse bit affects hflags */
 hreg_compute_hflags(env);
 }
+#endif
 
 static inline void fpscr_set_rounding_mode(CPUPPCState *env)
 {
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 2433756973..ad758b00e5 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1370,9 +1370,9 @@ void ppc_translate_init(void);
 
 #if !defined(CONFIG_USER_ONLY)
 void ppc_store_sdr1(CPUPPCState *env, target_ulong value);
+void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
 #endif /* !defined(CONFIG_USER_ONLY) */
 void ppc_store_msr(CPUPPCState *env, target_ulong value);
-void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
 
 void ppc_cpu_list(void);
 
-- 
2.25.1




[PATCH v3 19/29] target/ppc: create an interrupt masking method for POWER7

2022-10-11 Thread Matheus Ferst
The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 114 +++
 1 file changed, 114 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 18a16bf316..534c0f8f5c 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,6 +1679,118 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+static int p7_next_unmasked_interrupt(CPUPPCState *env)
+{
+bool async_deliver;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+#if 0 /* TODO */
+/* External debug exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+return PPC_INTERRUPT_DEBUG;
+}
+#endif
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)) {
+/* External critical interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+return PPC_INTERRUPT_CEXT;
+}
+}
+if (async_deliver != 0) {
+/* Watchdog timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+return PPC_INTERRUPT_WDT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+return PPC_INTERRUPT_CDOORBELL;
+}
+/* Fixed interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+return PPC_INTERRUPT_FIT;
+}
+/* Programmable interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+return PPC_INTERRUPT_PIT;
+}
+/* Decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+return PPC_INTERRUPT_DECR;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+return PPC_INTERRUPT_PERFM;
+}
+/* Thermal interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+return PPC_INTERRUPT_THERM;
+}
+/* EBB exception */
+if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+/*
+ * EBB exception must be taken in problem state and
+ * with BESCR_GE set.
+ */
+if (FIELD_EX64(env->msr, MSR, PR) &&
+(env->spr[SPR_BESCR] & BESCR_GE)) {
+return PPC_INTERRUPT_EBB;
+}
+}
+}
+
+return 0;
+}
+
 #define P8_UNUSED_INTERRUPTS \
 (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PP

[PATCH v3 27/29] target/ppc: introduce ppc_maybe_interrupt

2022-10-11 Thread Matheus Ferst
This new method will check if any pending interrupt was unmasked and
then call cpu_interrupt/cpu_reset_interrupt accordingly. Code that
raises/lowers or masks/unmasks interrupts should call this method to
keep CPU_INTERRUPT_HARD coherent with env->pending_interrupts.

Signed-off-by: Matheus Ferst 
---
v3:
 - Comment about when the method should be used.
---
 hw/ppc/pnv_core.c|  1 +
 hw/ppc/ppc.c |  7 +--
 hw/ppc/spapr_hcall.c |  6 ++
 hw/ppc/spapr_rtas.c  |  2 +-
 target/ppc/cpu.c |  2 ++
 target/ppc/cpu.h |  1 +
 target/ppc/excp_helper.c | 42 
 target/ppc/helper.h  |  1 +
 target/ppc/helper_regs.c |  2 ++
 target/ppc/translate.c   |  2 ++
 10 files changed, 59 insertions(+), 7 deletions(-)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 19e8eb885f..9ee79192dd 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -58,6 +58,7 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
 env->msr |= MSR_HVB; /* Hypervisor mode */
 env->spr[SPR_HRMOR] = pc->hrmor;
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 
 pcc->intc_reset(pc->chip, cpu);
 }
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 77e611e81c..dc86c1c7db 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -42,7 +42,6 @@ static void cpu_ppc_tb_start (CPUPPCState *env);
 
 void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
-CPUState *cs = CPU(cpu);
 CPUPPCState *env = >env;
 unsigned int old_pending;
 bool locked = false;
@@ -57,19 +56,15 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 
 if (level) {
 env->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 env->pending_interrupts &= ~irq;
-if (env->pending_interrupts == 0) {
-cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
-}
 }
 
 if (old_pending != env->pending_interrupts) {
+ppc_maybe_interrupt(env);
 kvmppc_set_interrupt(cpu, irq, level);
 }
 
-
 trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index a8d4a6bcf0..23aa41c879 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -490,6 +490,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 
 env->msr |= (1ULL << MSR_EE);
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 
 if (spapr_cpu->prod) {
 spapr_cpu->prod = false;
@@ -500,6 +501,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 cs->halted = 1;
 cs->exception_index = EXCP_HLT;
 cs->exit_request = 1;
+ppc_maybe_interrupt(env);
 }
 
 return H_SUCCESS;
@@ -521,6 +523,7 @@ static target_ulong h_confer_self(PowerPCCPU *cpu)
 cs->halted = 1;
 cs->exception_index = EXCP_HALTED;
 cs->exit_request = 1;
+ppc_maybe_interrupt(>env);
 
 return H_SUCCESS;
 }
@@ -633,6 +636,7 @@ static target_ulong h_prod(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 spapr_cpu = spapr_cpu_state(tcpu);
 spapr_cpu->prod = true;
 cs->halted = 0;
+ppc_maybe_interrupt(>env);
 qemu_cpu_kick(cs);
 
 return H_SUCCESS;
@@ -1661,6 +1665,7 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu,
 spapr_cpu->in_nested = true;
 
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 tlb_flush(cs);
 env->reserve_addr = -1; /* Reset the reservation */
 
@@ -1802,6 +1807,7 @@ out_restore_l1:
 spapr_cpu->in_nested = false;
 
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 tlb_flush(cs);
 env->reserve_addr = -1; /* Reset the reservation */
 
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index d58b65e88f..3f664ea02c 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -214,9 +214,9 @@ static void rtas_stop_self(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
  * guest.
  * For the same reason, set PSSCR_EC.
  */
-ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
 env->spr[SPR_PSSCR] |= PSSCR_EC;
 cs->halted = 1;
+ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
 kvmppc_set_reg_ppc_online(cpu, 0);
 qemu_cpu_kick(cs);
 }
diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index e95b4c5ee1..1a97b41c6b 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -82,6 +82,8 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
 /* The gtse bit affects hflags */
 hreg_compute_hflags(env);
+
+ppc_maybe_interrupt(env);
 }
 #endif
 
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index ad758b00e5..cc2d0305ff 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1358,6

[PATCH v3 17/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8

2022-10-11 Thread Matheus Ferst
Move the interrupt masking logic out of cpu_has_work_POWER8 in a new
method, p8_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 61 +++
 1 file changed, 33 insertions(+), 28 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index efdcf63282..3772f82e51 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6133,6 +6133,38 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
+static int p8_interrupt_powersave(CPUPPCState *env)
+{
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
+return PPC_INTERRUPT_EXT;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
+return PPC_INTERRUPT_DECR;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+return PPC_INTERRUPT_MCK;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+return PPC_INTERRUPT_HMI;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+return 0;
+}
+
 static bool cpu_has_work_POWER8(CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -6142,34 +6174,7 @@ static bool cpu_has_work_POWER8(CPUState *cs)
 if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
 return false;
 }
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
-return true;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return true;
-}
-return false;
+return p8_interrupt_powersave(env) != 0;
 } else {
 return FIELD_EX64(env->msr, MSR, EE) &&
(cs->interrupt_request & CPU_INTERRUPT_HARD);
-- 
2.25.1




[PATCH v3 22/29] target/ppc: remove unused interrupts from p7_deliver_interrupt

2022-10-11 Thread Matheus Ferst
Remove the following unused interrupts from the POWER7 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Hypervisor Doorbell and Event-Based Branch: introduced in
  Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Doorbell and Critical Doorbell Interrupt: processor does not implement
  the Embedded.Processor Control category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 50 
 1 file changed, 50 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 48c1b9f627..055f1de20e 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2051,10 +2051,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 CPUState *cs = env_cpu(env);
 
 switch (interrupt) {
-case PPC_INTERRUPT_RESET: /* External reset */
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-break;
 case PPC_INTERRUPT_MCK: /* Machine check exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
 powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
@@ -2071,9 +2067,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
 powerpc_excp(cpu, POWERPC_EXCP_HDECR);
 break;
-case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-break;
 
 case PPC_INTERRUPT_EXT:
 if (books_vhyp_promotes_external_to_hvirt(cpu)) {
@@ -2082,60 +2075,17 @@ static void p7_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
 }
 break;
-case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-break;
 
-case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-break;
-case PPC_INTERRUPT_CDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-break;
-case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-break;
-case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-break;
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
 if (ppc_decr_clear_on_delivery(env)) {
 env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
 }
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
-case PPC_INTERRUPT_DOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-if (is_book3s_arch2x(env)) {
-powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-} else {
-powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-}
-break;
-case PPC_INTERRUPT_HDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
-break;
 case PPC_INTERRUPT_PERFM:
 env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
 powerpc_excp(cpu, POWERPC_EXCP_PERFM);
 break;
-case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-powerpc_excp(cpu, POWERPC_EXCP_THERM);
-break;
-case PPC_INTERRUPT_EBB: /* EBB exception */
-env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
-if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
-} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
-powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
-}
-break;
 case 0:
 /*
  * This is a bug ! It means that has_work took us out of halt without
-- 
2.25.1




[PATCH v3 24/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7

2022-10-11 Thread Matheus Ferst
Move the interrupt masking logic out of cpu_has_work_POWER7 in a new
method, p7_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 45 ---
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 4a44ba1733..53a87c379c 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,6 +5960,30 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
+static int p7_interrupt_powersave(CPUPPCState *env)
+{
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
+return PPC_INTERRUPT_EXT;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
+return PPC_INTERRUPT_DECR;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+return PPC_INTERRUPT_MCK;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+return PPC_INTERRUPT_HMI;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+return 0;
+}
+
 static bool cpu_has_work_POWER7(CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -5969,26 +5993,7 @@ static bool cpu_has_work_POWER7(CPUState *cs)
 if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
 return false;
 }
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return true;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return true;
-}
-return false;
+return p7_interrupt_powersave(env) != 0;
 } else {
 return FIELD_EX64(env->msr, MSR, EE) &&
(cs->interrupt_request & CPU_INTERRUPT_HARD);
-- 
2.25.1




[PATCH v3 16/29] target/ppc: remove generic architecture checks from p8_deliver_interrupt

2022-10-11 Thread Matheus Ferst
Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 662daad796..aaf1c95087 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2004,9 +2004,6 @@ static void p8_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 break;
 
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
-if (ppc_decr_clear_on_delivery(env)) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-}
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
 case PPC_INTERRUPT_DOORBELL:
-- 
2.25.1




[PATCH v3 29/29] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c

2022-10-11 Thread Matheus Ferst
Move the methods to excp_helper.c and make them static.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c| 102 ---
 target/ppc/excp_helper.c | 102 +++
 target/ppc/internal.h|   6 ---
 3 files changed, 102 insertions(+), 108 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 15d549ad38..6f3539f13a 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,30 +5960,6 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-int p7_interrupt_powersave(CPUPPCState *env)
-{
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
-return PPC_INTERRUPT_EXT;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
-return PPC_INTERRUPT_DECR;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return PPC_INTERRUPT_MCK;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return PPC_INTERRUPT_HMI;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
@@ -6120,38 +6096,6 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-int p8_interrupt_powersave(CPUPPCState *env)
-{
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
-return PPC_INTERRUPT_EXT;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
-return PPC_INTERRUPT_DECR;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return PPC_INTERRUPT_MCK;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return PPC_INTERRUPT_HMI;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
-return PPC_INTERRUPT_DOORBELL;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
-return PPC_INTERRUPT_HDOORBELL;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
@@ -6325,52 +6269,6 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
-int p9_interrupt_powersave(CPUPPCState *env)
-{
-/* External Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_EEE)) {
-bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-if (!heic || !FIELD_EX64_HV(env->msr) ||
-FIELD_EX64(env->msr, MSR, PR)) {
-return PPC_INTERRUPT_EXT;
-}
-}
-/* Decrementer Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_DEE)) {
-return PPC_INTERRUPT_DECR;
-}
-/* Machine Check or Hypervisor Maintenance Exception */
-if (env->spr[SPR_LPCR] & LPCR_OEE) {
-if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
-return PPC_INTERRUPT_MCK;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
-return PPC_INTERRUPT_HMI;
-}
-}
-/* Privileged Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_PDEE)) {
-return PPC_INTERRUPT_DOORBELL;
-}
-/* Hypervisor Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_HDEE)) {
-return PPC_INTERRUPT_HDOORBELL;
-}
-/* Hypervisor virtualization exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
-(env->spr[SPR_LPCR] & LPCR_HVEE)) {
-return PPC_INTERRUPT_HVIRT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
 D

[PATCH v3 21/29] target/ppc: create an interrupt deliver method for POWER7

2022-10-11 Thread Matheus Ferst
The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 113 +++
 1 file changed, 113 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index a4d5fac37b..48c1b9f627 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2045,6 +2045,116 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 }
 
 #if defined(TARGET_PPC64)
+static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = env_cpu(env);
+
+switch (interrupt) {
+case PPC_INTERRUPT_RESET: /* External reset */
+env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+powerpc_excp(cpu, POWERPC_EXCP_RESET);
+break;
+case PPC_INTERRUPT_MCK: /* Machine check exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+break;
+#if 0 /* TODO */
+case PPC_INTERRUPT_DEBUG: /* External debug exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+break;
+#endif
+
+case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+/* HDEC clears on delivery */
+env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+break;
+case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+break;
+
+case PPC_INTERRUPT_EXT:
+if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+}
+break;
+case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+break;
+
+case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+powerpc_excp(cpu, POWERPC_EXCP_WDT);
+break;
+case PPC_INTERRUPT_CDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+break;
+case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+powerpc_excp(cpu, POWERPC_EXCP_FIT);
+break;
+case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
+env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+powerpc_excp(cpu, POWERPC_EXCP_PIT);
+break;
+case PPC_INTERRUPT_DECR: /* Decrementer exception */
+if (ppc_decr_clear_on_delivery(env)) {
+env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+}
+powerpc_excp(cpu, POWERPC_EXCP_DECR);
+break;
+case PPC_INTERRUPT_DOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+if (is_book3s_arch2x(env)) {
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+}
+break;
+case PPC_INTERRUPT_HDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+break;
+case PPC_INTERRUPT_PERFM:
+env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+break;
+case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+powerpc_excp(cpu, POWERPC_EXCP_THERM);
+break;
+case PPC_INTERRUPT_EBB: /* EBB exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+}
+break;
+case 0:
+/*
+ * This is a bug ! It means that has_work took us out of halt without
+ * anything to deliver while in a PM state that requires getting
+ * out via a 0x100
+ *
+ * This means we will incorrectly execute past the power management
+ * instruction instead of triggering a reset.
+ *
+ * It generally means a discrepancy between the wakeup conditions in 
the
+ * processor has_work implementation and the logic in this function.
+ */
+assert(!env->resume_as_sreset);
+break;
+default:
+cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
+}
+}
+
 static void p8_del

[PATCH v3 23/29] target/ppc: remove generic architecture checks from p7_deliver_interrupt

2022-10-11 Thread Matheus Ferst
Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 055f1de20e..1c373c1a7c 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2077,9 +2077,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 break;
 
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
-if (ppc_decr_clear_on_delivery(env)) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-}
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
 case PPC_INTERRUPT_PERFM:
-- 
2.25.1




[PATCH v3 15/29] target/ppc: remove unused interrupts from p8_deliver_interrupt

2022-10-11 Thread Matheus Ferst
Remove the following unused interrupts from the POWER8 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Critical Doorbell: processor does not implement the
  "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst 
---
v3:
 - Keep Hypervisor and Privileged Doorbell interrupts, the category for
   processor control instruction became "Embedded.Processor Control" or
   "Server" on Power ISA v2.07, so the interrupts are still necessary.
---
 target/ppc/excp_helper.c | 36 
 1 file changed, 36 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 1d1b26b8d8..662daad796 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1984,29 +1984,16 @@ static void p8_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 CPUState *cs = env_cpu(env);
 
 switch (interrupt) {
-case PPC_INTERRUPT_RESET: /* External reset */
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-break;
 case PPC_INTERRUPT_MCK: /* Machine check exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
 powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
 break;
-#if 0 /* TODO */
-case PPC_INTERRUPT_DEBUG: /* External debug exception */
-env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-break;
-#endif
 
 case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
 /* HDEC clears on delivery */
 env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
 powerpc_excp(cpu, POWERPC_EXCP_HDECR);
 break;
-case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-break;
 
 case PPC_INTERRUPT_EXT:
 if (books_vhyp_promotes_external_to_hvirt(cpu)) {
@@ -2015,26 +2002,7 @@ static void p8_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
 }
 break;
-case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-break;
 
-case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-break;
-case PPC_INTERRUPT_CDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-break;
-case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-break;
-case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-break;
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
 if (ppc_decr_clear_on_delivery(env)) {
 env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
@@ -2057,10 +2025,6 @@ static void p8_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
 powerpc_excp(cpu, POWERPC_EXCP_PERFM);
 break;
-case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-powerpc_excp(cpu, POWERPC_EXCP_THERM);
-break;
 case PPC_INTERRUPT_EBB: /* EBB exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
 if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-- 
2.25.1




[PATCH v3 25/29] target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt

2022-10-11 Thread Matheus Ferst
Export p7_interrupt_powersave and use it in p7_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c|  2 +-
 target/ppc/excp_helper.c | 24 
 target/ppc/internal.h|  1 +
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 53a87c379c..0adc866485 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,7 +5960,7 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-static int p7_interrupt_powersave(CPUPPCState *env)
+int p7_interrupt_powersave(CPUPPCState *env)
 {
 if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
 (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 1c373c1a7c..3e8a368d01 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1687,10 +1687,18 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p7_next_unmasked_interrupt(CPUPPCState *env)
 {
-bool async_deliver;
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = CPU(cpu);
+/* Ignore MSR[EE] when coming out of some power management states */
+bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
 assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0);
 
+if (cs->halted) {
+/* LPCR[PECE] controls which interrupts can exit power-saving mode */
+return p7_interrupt_powersave(env);
+}
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
@@ -1702,19 +1710,11 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
 }
 #endif
 
-/*
- * For interrupts that gate on MSR:EE, we need to do something a
- * bit more subtle, as we need to let them through even when EE is
- * clear when coming out of some power management states (in order
- * for them to become a 0x100).
- */
-async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
 /* Hypervisor decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
 /* LPCR will be clear when not supported so this will work */
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
 return PPC_INTERRUPT_HDECR;
 }
@@ -1725,13 +1725,13 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
 bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
 /* HEIC blocks delivery to the hypervisor */
-if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
 return PPC_INTERRUPT_EXT;
 }
 }
-if (async_deliver != 0) {
+if (msr_ee != 0) {
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 9069874adb..25827ebf6f 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -309,6 +309,7 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int 
xmsk)
 #if defined(TARGET_PPC64)
 int p9_interrupt_powersave(CPUPPCState *env);
 int p8_interrupt_powersave(CPUPPCState *env);
+int p7_interrupt_powersave(CPUPPCState *env);
 #endif
 
 #endif /* PPC_INTERNAL_H */
-- 
2.25.1




[PATCH v3 20/29] target/ppc: remove unused interrupts from p7_next_unmasked_interrupt

2022-10-11 Thread Matheus Ferst
Remove the following unused interrupts from the POWER7 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Hypervisor Doorbell and Event-Based Branch: introduced in
  Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Doorbell and Critical Doorbell Interrupt: processor does not implement
  the Embedded.Processor Control category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst 
---
v3:
 - Fixed method name in subject.
---
 target/ppc/excp_helper.c | 63 +---
 1 file changed, 8 insertions(+), 55 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 534c0f8f5c..a4d5fac37b 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,14 +1679,18 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P7_UNUSED_INTERRUPTS \
+(PPC_INTERRUPT_RESET | PPC_INTERRUPT_HVIRT | PPC_INTERRUPT_CEXT |   \
+ PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |  \
+ PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \
+ PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB)
+
 static int p7_next_unmasked_interrupt(CPUPPCState *env)
 {
 bool async_deliver;
 
-/* External reset */
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
+assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0);
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
@@ -1716,15 +1720,6 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
 }
 }
 
-/* Hypervisor virtualization interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
-/* LPCR will be clear when not supported so this will work */
-bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-return PPC_INTERRUPT_HVIRT;
-}
-}
-
 /* External interrupt can ignore MSR:EE under some circumstances */
 if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
@@ -1736,56 +1731,14 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-return PPC_INTERRUPT_CDOORBELL;
-}
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
 }
-if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
-return PPC_INTERRUPT_DOORBELL;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
-return PPC_INTERRUPT_HDOORBELL;
-}
 if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
 return PPC_INTERRUPT_PERFM;
 }
-/* Thermal interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-return PPC_INTERRUPT_THERM;
-}
-/* EBB exception */
-if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
-/*
- * EBB exception must be taken in problem state and
- * with BESCR_GE set.
- */
-if (FIELD_EX64(env->msr, MSR, PR) &&
-(env->spr[SPR_BESCR] & BESCR_GE)) {
-return PPC_INTERRUPT_EBB;
-}
-}
 }
 
 return 0;
-- 
2.25.1




[PATCH v3 13/29] target/ppc: remove unused interrupts from p8_next_unmasked_interrupt

2022-10-11 Thread Matheus Ferst
Remove the following unused interrupts from the POWER8 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Critical Doorbell: processor does not implement the "Embedded.Processor
  Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst 
---
v3:
 - Keep Hypervisor and Privileged Doorbell interrupts, the category for
   processor control instruction became "Embedded.Processor Control" or
   "Server" on Power ISA v2.07, so the interrupts are still necessary;
 - Fixed method name in subject.
---
 target/ppc/excp_helper.c | 51 ++--
 1 file changed, 7 insertions(+), 44 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 19d352a1b2..9bdc87aa61 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,24 +1679,21 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P8_UNUSED_INTERRUPTS \
+(PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_HVIRT |  \
+PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL |  \
+PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM)
+
 static int p8_next_unmasked_interrupt(CPUPPCState *env)
 {
 bool async_deliver;
 
-/* External reset */
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
+assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0);
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
 }
-#if 0 /* TODO */
-/* External debug exception */
-if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-return PPC_INTERRUPT_DEBUG;
-}
-#endif
 
 /*
  * For interrupts that gate on MSR:EE, we need to do something a
@@ -1716,15 +1713,6 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
 }
 }
 
-/* Hypervisor virtualization interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
-/* LPCR will be clear when not supported so this will work */
-bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-return PPC_INTERRUPT_HVIRT;
-}
-}
-
 /* External interrupt can ignore MSR:EE under some circumstances */
 if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
@@ -1736,28 +1724,7 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-return PPC_INTERRUPT_CDOORBELL;
-}
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
@@ -1771,10 +1738,6 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
 if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
 return PPC_INTERRUPT_PERFM;
 }
-/* Thermal interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-return PPC_INTERRUPT_THERM;
-}
 /* EBB exception */
 if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
 /*
-- 
2.25.1




[PATCH v3 14/29] target/ppc: create an interrupt deliver method for POWER8

2022-10-11 Thread Matheus Ferst
The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 113 +++
 1 file changed, 113 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 9bdc87aa61..1d1b26b8d8 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1978,6 +1978,116 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 }
 
 #if defined(TARGET_PPC64)
+static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = env_cpu(env);
+
+switch (interrupt) {
+case PPC_INTERRUPT_RESET: /* External reset */
+env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+powerpc_excp(cpu, POWERPC_EXCP_RESET);
+break;
+case PPC_INTERRUPT_MCK: /* Machine check exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+break;
+#if 0 /* TODO */
+case PPC_INTERRUPT_DEBUG: /* External debug exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+break;
+#endif
+
+case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+/* HDEC clears on delivery */
+env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+break;
+case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+break;
+
+case PPC_INTERRUPT_EXT:
+if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+}
+break;
+case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+break;
+
+case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+powerpc_excp(cpu, POWERPC_EXCP_WDT);
+break;
+case PPC_INTERRUPT_CDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+break;
+case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+powerpc_excp(cpu, POWERPC_EXCP_FIT);
+break;
+case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
+env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+powerpc_excp(cpu, POWERPC_EXCP_PIT);
+break;
+case PPC_INTERRUPT_DECR: /* Decrementer exception */
+if (ppc_decr_clear_on_delivery(env)) {
+env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+}
+powerpc_excp(cpu, POWERPC_EXCP_DECR);
+break;
+case PPC_INTERRUPT_DOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+if (is_book3s_arch2x(env)) {
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+}
+break;
+case PPC_INTERRUPT_HDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+break;
+case PPC_INTERRUPT_PERFM:
+env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+break;
+case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+powerpc_excp(cpu, POWERPC_EXCP_THERM);
+break;
+case PPC_INTERRUPT_EBB: /* EBB exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+}
+break;
+case 0:
+/*
+ * This is a bug ! It means that has_work took us out of halt without
+ * anything to deliver while in a PM state that requires getting
+ * out via a 0x100
+ *
+ * This means we will incorrectly execute past the power management
+ * instruction instead of triggering a reset.
+ *
+ * It generally means a discrepancy between the wakeup conditions in 
the
+ * processor has_work implementation and the logic in this function.
+ */
+assert(!env->resume_as_sreset);
+break;
+default:
+cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
+}
+}
+
 static void p9_del

[PATCH v3 18/29] target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt

2022-10-11 Thread Matheus Ferst
Export p8_interrupt_powersave and use it in p8_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c|  2 +-
 target/ppc/excp_helper.c | 24 
 target/ppc/internal.h|  1 +
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 3772f82e51..4a44ba1733 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6133,7 +6133,7 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-static int p8_interrupt_powersave(CPUPPCState *env)
+int p8_interrupt_powersave(CPUPPCState *env)
 {
 if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
 (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index aaf1c95087..18a16bf316 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1686,28 +1686,28 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p8_next_unmasked_interrupt(CPUPPCState *env)
 {
-bool async_deliver;
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = CPU(cpu);
+/* Ignore MSR[EE] when coming out of some power management states */
+bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
 assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0);
 
+if (cs->halted) {
+/* LPCR[PECE] controls which interrupts can exit power-saving mode */
+return p8_interrupt_powersave(env);
+}
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
 }
 
-/*
- * For interrupts that gate on MSR:EE, we need to do something a
- * bit more subtle, as we need to let them through even when EE is
- * clear when coming out of some power management states (in order
- * for them to become a 0x100).
- */
-async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
 /* Hypervisor decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
 /* LPCR will be clear when not supported so this will work */
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
 return PPC_INTERRUPT_HDECR;
 }
@@ -1718,13 +1718,13 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
 bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
 /* HEIC blocks delivery to the hypervisor */
-if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
 return PPC_INTERRUPT_EXT;
 }
 }
-if (async_deliver != 0) {
+if (msr_ee != 0) {
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 41e79adfdb..9069874adb 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -308,6 +308,7 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int 
xmsk)
 
 #if defined(TARGET_PPC64)
 int p9_interrupt_powersave(CPUPPCState *env);
+int p8_interrupt_powersave(CPUPPCState *env);
 #endif
 
 #endif /* PPC_INTERNAL_H */
-- 
2.25.1




[PATCH v3 10/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9

2022-10-11 Thread Matheus Ferst
Move the interrupt masking logic out of cpu_has_work_POWER9 in a new
method, p9_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 126 +-
 1 file changed, 50 insertions(+), 76 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 304ebdc062..5fce293728 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6351,6 +6351,52 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
+static int p9_interrupt_powersave(CPUPPCState *env)
+{
+/* External Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_EEE)) {
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+if (!heic || !FIELD_EX64_HV(env->msr) ||
+FIELD_EX64(env->msr, MSR, PR)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+/* Decrementer Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_DEE)) {
+return PPC_INTERRUPT_DECR;
+}
+/* Machine Check or Hypervisor Maintenance Exception */
+if (env->spr[SPR_LPCR] & LPCR_OEE) {
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
+return PPC_INTERRUPT_HMI;
+}
+}
+/* Privileged Doorbell Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_PDEE)) {
+return PPC_INTERRUPT_DOORBELL;
+}
+/* Hypervisor Doorbell Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_HDEE)) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+/* Hypervisor virtualization exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
+(env->spr[SPR_LPCR] & LPCR_HVEE)) {
+return PPC_INTERRUPT_HVIRT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+return 0;
+}
+
 static bool cpu_has_work_POWER9(CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -6367,44 +6413,8 @@ static bool cpu_has_work_POWER9(CPUState *cs)
 if (!(psscr & PSSCR_EC)) {
 return true;
 }
-/* External Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_EEE)) {
-bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-if (!heic || !FIELD_EX64_HV(env->msr) ||
-FIELD_EX64(env->msr, MSR, PR)) {
-return true;
-}
-}
-/* Decrementer Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_DEE)) {
-return true;
-}
-/* Machine Check or Hypervisor Maintenance Exception */
-if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI))
-&& (env->spr[SPR_LPCR] & LPCR_OEE)) {
-return true;
-}
-/* Privileged Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_PDEE)) {
-return true;
-}
-/* Hypervisor Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_HDEE)) {
-return true;
-}
-/* Hypervisor virtualization exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
-(env->spr[SPR_LPCR] & LPCR_HVEE)) {
-return true;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return true;
-}
-return false;
+
+return p9_interrupt_powersave(env) != 0;
 } else {
 return FIELD_EX64(env->msr, MSR, EE) &&
(cs->interrupt_request & CPU_INTERRUPT_HARD);
@@ -6600,44 +6610,8 @@ static bool cpu_has_work_POWER10(CPUState *cs)
 if (!(psscr & PSSCR_EC)) {
 return true;
 }
-/* External Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_EEE)) {
-bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-if (!heic || !FIELD_EX64_HV(env->msr) ||
-FIELD_EX64(env->msr, MSR, PR)) {
-ret

[PATCH v3 12/29] target/ppc: create an interrupt masking method for POWER8

2022-10-11 Thread Matheus Ferst
The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 114 +++
 1 file changed, 114 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index d103820afa..19d352a1b2 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,6 +1679,118 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+static int p8_next_unmasked_interrupt(CPUPPCState *env)
+{
+bool async_deliver;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+#if 0 /* TODO */
+/* External debug exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+return PPC_INTERRUPT_DEBUG;
+}
+#endif
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)) {
+/* External critical interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+return PPC_INTERRUPT_CEXT;
+}
+}
+if (async_deliver != 0) {
+/* Watchdog timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+return PPC_INTERRUPT_WDT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+return PPC_INTERRUPT_CDOORBELL;
+}
+/* Fixed interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+return PPC_INTERRUPT_FIT;
+}
+/* Programmable interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+return PPC_INTERRUPT_PIT;
+}
+/* Decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+return PPC_INTERRUPT_DECR;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+return PPC_INTERRUPT_PERFM;
+}
+/* Thermal interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+return PPC_INTERRUPT_THERM;
+}
+/* EBB exception */
+if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+/*
+ * EBB exception must be taken in problem state and
+ * with BESCR_GE set.
+ */
+if (FIELD_EX64(env->msr, MSR, PR) &&
+(env->spr[SPR_BESCR] & BESCR_GE)) {
+return PPC_INTERRUPT_EBB;
+}
+}
+}
+
+return 0;
+}
+
 #define P9_UNUSED_INTERRUPTS \
 (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PP

[PATCH v3 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt

2022-10-11 Thread Matheus Ferst
Export p9_interrupt_powersave and use it in p9_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst 
---
Putting the prototype in internal.h for a lack of better place. However,
we will un-export p9_interrupt_powersave in future patches, so it's only
temporary.
---
 target/ppc/cpu_init.c|  2 +-
 target/ppc/excp_helper.c | 46 
 target/ppc/internal.h|  4 
 3 files changed, 38 insertions(+), 14 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 5fce293728..efdcf63282 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6351,7 +6351,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
-static int p9_interrupt_powersave(CPUPPCState *env)
+int p9_interrupt_powersave(CPUPPCState *env)
 {
 /* External Exception */
 if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index fd9745c37e..d103820afa 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1686,28 +1686,39 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p9_next_unmasked_interrupt(CPUPPCState *env)
 {
-bool async_deliver;
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = CPU(cpu);
+/* Ignore MSR[EE] when coming out of some power management states */
+bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
 assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
 
+if (cs->halted) {
+if (env->spr[SPR_PSSCR] & PSSCR_EC) {
+/*
+ * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can
+ * wakeup the processor
+ */
+return p9_interrupt_powersave(env);
+} else {
+/*
+ * When it's clear, any system-caused exception exits power-saving
+ * mode, even the ones that gate on MSR[EE].
+ */
+msr_ee = true;
+}
+}
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
 }
 
-/*
- * For interrupts that gate on MSR:EE, we need to do something a
- * bit more subtle, as we need to let them through even when EE is
- * clear when coming out of some power management states (in order
- * for them to become a 0x100).
- */
-async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
 /* Hypervisor decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
 /* LPCR will be clear when not supported so this will work */
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
 return PPC_INTERRUPT_HDECR;
 }
@@ -1717,7 +1728,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
 if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
 /* LPCR will be clear when not supported so this will work */
 bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) {
 return PPC_INTERRUPT_HVIRT;
 }
 }
@@ -1727,13 +1738,13 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
 bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
 /* HEIC blocks delivery to the hypervisor */
-if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
 return PPC_INTERRUPT_EXT;
 }
 }
-if (async_deliver != 0) {
+if (msr_ee != 0) {
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
@@ -1895,6 +1906,15 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 PowerPCCPU *cpu = env_archcpu(env);
 CPUState *cs = env_cpu(env);
 
+if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) &&
+!FIELD_EX64(env->msr, MSR, EE)) {
+/*
+ * A pending interrupt took us out of power-saving, but MSR[EE] says
+ * that we should return to NIP+4 instead of delivering it.
+ */
+return;
+}
+
 switch (interrupt) {
 case PPC_INTERRUPT_MCK: /* Machine check excep

[PATCH v3 07/29] target/ppc: create an interrupt deliver method for POWER9/POWER10

2022-10-11 Thread Matheus Ferst
The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 118 +++
 1 file changed, 118 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index da9c928350..9ebc0a0d31 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1889,6 +1889,118 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 }
 }
 
+#if defined(TARGET_PPC64)
+static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = env_cpu(env);
+
+switch (interrupt) {
+case PPC_INTERRUPT_RESET: /* External reset */
+env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+powerpc_excp(cpu, POWERPC_EXCP_RESET);
+break;
+case PPC_INTERRUPT_MCK: /* Machine check exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+break;
+#if 0 /* TODO */
+case PPC_INTERRUPT_DEBUG: /* External debug exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+break;
+#endif
+
+case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+/* HDEC clears on delivery */
+env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+break;
+case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+break;
+
+case PPC_INTERRUPT_EXT:
+if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+}
+break;
+case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+break;
+
+case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+powerpc_excp(cpu, POWERPC_EXCP_WDT);
+break;
+case PPC_INTERRUPT_CDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+break;
+case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+powerpc_excp(cpu, POWERPC_EXCP_FIT);
+break;
+case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
+env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+powerpc_excp(cpu, POWERPC_EXCP_PIT);
+break;
+case PPC_INTERRUPT_DECR: /* Decrementer exception */
+if (ppc_decr_clear_on_delivery(env)) {
+env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+}
+powerpc_excp(cpu, POWERPC_EXCP_DECR);
+break;
+case PPC_INTERRUPT_DOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+if (is_book3s_arch2x(env)) {
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+}
+break;
+case PPC_INTERRUPT_HDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+break;
+case PPC_INTERRUPT_PERFM:
+env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+break;
+case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+powerpc_excp(cpu, POWERPC_EXCP_THERM);
+break;
+case PPC_INTERRUPT_EBB: /* EBB exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+}
+break;
+case 0:
+/*
+ * This is a bug ! It means that has_work took us out of halt without
+ * anything to deliver while in a PM state that requires getting
+ * out via a 0x100
+ *
+ * This means we will incorrectly execute past the power management
+ * instruction instead of triggering a reset.
+ *
+ * It generally means a discrepancy between the wakeup conditions in 
the
+ * processor has_work implementation and the logic in this function.
+ */
+assert(!env->resume_as_sreset);
+break;
+default:
+cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
+}
+}
+#endif
+
 static void p

[PATCH v3 09/29] target/ppc: remove generic architecture checks from p9_deliver_interrupt

2022-10-11 Thread Matheus Ferst
Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 9 +
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index fb946385cc..fd9745c37e 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1919,18 +1919,11 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 break;
 
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
-if (ppc_decr_clear_on_delivery(env)) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-}
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
 case PPC_INTERRUPT_DOORBELL:
 env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-if (is_book3s_arch2x(env)) {
-powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-} else {
-powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-}
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
 break;
 case PPC_INTERRUPT_HDOORBELL:
 env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-- 
2.25.1




[PATCH v3 06/29] target/ppc: remove unused interrupts from p9_next_unmasked_interrupt

2022-10-11 Thread Matheus Ferst
Remove the following unused interrupts from the POWER9 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Critical Doorbell Interrupt: removed in Power ISA v3.0;
- Programmable Interval Timer: 40x-only.

Signed-off-by: Matheus Ferst 
---
v3:
 - Fixed method name in subject.
---
 target/ppc/excp_helper.c | 42 +++-
 1 file changed, 7 insertions(+), 35 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 834181cdaf..da9c928350 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,24 +1679,21 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P9_UNUSED_INTERRUPTS \
+(PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_CEXT |   \
+ PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |  \
+ PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM)
+
 static int p9_next_unmasked_interrupt(CPUPPCState *env)
 {
 bool async_deliver;
 
-/* External reset */
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
+assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
 }
-#if 0 /* TODO */
-/* External debug exception */
-if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-return PPC_INTERRUPT_DEBUG;
-}
-#endif
 
 /*
  * For interrupts that gate on MSR:EE, we need to do something a
@@ -1736,28 +1733,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-return PPC_INTERRUPT_CDOORBELL;
-}
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
@@ -1771,10 +1747,6 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
 if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
 return PPC_INTERRUPT_PERFM;
 }
-/* Thermal interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-return PPC_INTERRUPT_THERM;
-}
 /* EBB exception */
 if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
 /*
-- 
2.25.1




[PATCH v3 04/29] target/ppc: prepare to split interrupt masking and delivery by excp_model

2022-10-11 Thread Matheus Ferst
Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 20 ++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f92b6c2b18..7d196d1581 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,7 +1678,7 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
-static int ppc_next_unmasked_interrupt(CPUPPCState *env)
+static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env)
 {
 bool async_deliver;
 
@@ -1790,7 +1790,15 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 return 0;
 }
 
-static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
+static int ppc_next_unmasked_interrupt(CPUPPCState *env)
+{
+switch (env->excp_model) {
+default:
+return ppc_next_unmasked_interrupt_generic(env);
+}
+}
+
+static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt)
 {
 PowerPCCPU *cpu = env_archcpu(env);
 CPUState *cs = env_cpu(env);
@@ -1900,6 +1908,14 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 }
 }
 
+static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+switch (env->excp_model) {
+default:
+ppc_deliver_interrupt_generic(env, interrupt);
+}
+}
+
 void ppc_cpu_do_system_reset(CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
-- 
2.25.1




[PATCH v3 08/29] target/ppc: remove unused interrupts from p9_deliver_interrupt

2022-10-11 Thread Matheus Ferst
Remove the following unused interrupts from the POWER9 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Critical Doorbell Interrupt: removed in Power ISA v3.0;
- Programmable Interval Timer: 40x-only.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 33 -
 1 file changed, 33 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 9ebc0a0d31..fb946385cc 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1896,20 +1896,10 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 CPUState *cs = env_cpu(env);
 
 switch (interrupt) {
-case PPC_INTERRUPT_RESET: /* External reset */
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-break;
 case PPC_INTERRUPT_MCK: /* Machine check exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
 powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
 break;
-#if 0 /* TODO */
-case PPC_INTERRUPT_DEBUG: /* External debug exception */
-env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-break;
-#endif
 
 case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
 /* HDEC clears on delivery */
@@ -1927,26 +1917,7 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
 }
 break;
-case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-break;
 
-case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-break;
-case PPC_INTERRUPT_CDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-break;
-case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-break;
-case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-break;
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
 if (ppc_decr_clear_on_delivery(env)) {
 env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
@@ -1969,10 +1940,6 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
 powerpc_excp(cpu, POWERPC_EXCP_PERFM);
 break;
-case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-powerpc_excp(cpu, POWERPC_EXCP_THERM);
-break;
 case PPC_INTERRUPT_EBB: /* EBB exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
 if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-- 
2.25.1




[PATCH v3 05/29] target/ppc: create an interrupt masking method for POWER9/POWER10

2022-10-11 Thread Matheus Ferst
The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 119 +++
 1 file changed, 119 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 7d196d1581..834181cdaf 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,6 +1678,120 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
+#if defined(TARGET_PPC64)
+static int p9_next_unmasked_interrupt(CPUPPCState *env)
+{
+bool async_deliver;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+#if 0 /* TODO */
+/* External debug exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+return PPC_INTERRUPT_DEBUG;
+}
+#endif
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)) {
+/* External critical interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+return PPC_INTERRUPT_CEXT;
+}
+}
+if (async_deliver != 0) {
+/* Watchdog timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+return PPC_INTERRUPT_WDT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+return PPC_INTERRUPT_CDOORBELL;
+}
+/* Fixed interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+return PPC_INTERRUPT_FIT;
+}
+/* Programmable interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+return PPC_INTERRUPT_PIT;
+}
+/* Decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+return PPC_INTERRUPT_DECR;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+return PPC_INTERRUPT_PERFM;
+}
+/* Thermal interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+return PPC_INTERRUPT_THERM;
+}
+/* EBB exception */
+if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+/*
+ * EBB exception must be taken in problem state and
+ * with BESCR_GE set.
+ */
+if (FIELD_EX64(env->msr, MSR, PR) &&
+(env->spr[SPR_BESCR] & BESCR_GE)) {
+return PPC_INTERRUPT_EBB;
+}
+}
+}
+
+return 0;
+}
+#endif
+
 static int ppc_next_unmasked_interru

[PATCH v3 03/29] target/ppc: split interrupt masking and delivery from ppc_hw_interrupt

2022-10-11 Thread Matheus Ferst
Split ppc_hw_interrupt into an interrupt masking method,
ppc_next_unmasked_interrupt, and an interrupt processing method,
ppc_deliver_interrupt.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 207 +--
 1 file changed, 131 insertions(+), 76 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index c3c30c5d1b..f92b6c2b18 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,29 +1678,22 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
-static void ppc_hw_interrupt(CPUPPCState *env)
+static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 {
-PowerPCCPU *cpu = env_archcpu(env);
 bool async_deliver;
 
 /* External reset */
 if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-return;
+return PPC_INTERRUPT_RESET;
 }
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
-env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
-powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
-return;
+return PPC_INTERRUPT_MCK;
 }
 #if 0 /* TODO */
 /* External debug exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-return;
+return PPC_INTERRUPT_DEBUG;
 }
 #endif
 
@@ -1718,9 +1711,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
 if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
-env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
-powerpc_excp(cpu, POWERPC_EXCP_HDECR);
-return;
+return PPC_INTERRUPT_HDECR;
 }
 }
 
@@ -1729,8 +1720,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 || !FIELD_EX64_HV(env->msr)) && hvice) {
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-return;
+return PPC_INTERRUPT_HVIRT;
 }
 }
 
@@ -1742,77 +1732,47 @@ static void ppc_hw_interrupt(CPUPPCState *env)
 if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
-if (books_vhyp_promotes_external_to_hvirt(cpu)) {
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-} else {
-powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
-}
-return;
+return PPC_INTERRUPT_EXT;
 }
 }
 if (FIELD_EX64(env->msr, MSR, CE)) {
 /* External critical interrupt */
 if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-return;
+return PPC_INTERRUPT_CEXT;
 }
 }
 if (async_deliver != 0) {
 /* Watchdog timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-return;
+return PPC_INTERRUPT_WDT;
 }
 if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-return;
+return PPC_INTERRUPT_CDOORBELL;
 }
 /* Fixed interval timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-return;
+return PPC_INTERRUPT_FIT;
 }
 /* Programmable interval timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-return;
+return PPC_INTERRUPT_PIT;
 }
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
-if (ppc_decr_clear_on_delivery(env)) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-}
-powerpc_excp(cpu, POWERPC_EXCP_DECR);
-return;
+return PPC_INTERRUPT_DECR;
 }
 

[PATCH v3 01/29] target/ppc: define PPC_INTERRUPT_* values directly

2022-10-11 Thread Matheus Ferst
This enum defines the bit positions in env->pending_interrupts for each
interrupt. However, except for the comparison in kvmppc_set_interrupt,
the values are always used as (1 << PPC_INTERRUPT_*). Define them
directly like that to save some clutter. No functional change intended.

Reviewed-by: David Gibson 
Signed-off-by: Matheus Ferst 
---
 hw/ppc/ppc.c | 10 +++---
 hw/ppc/trace-events  |  2 +-
 target/ppc/cpu.h | 40 +++---
 target/ppc/cpu_init.c| 56 +++---
 target/ppc/excp_helper.c | 74 
 target/ppc/misc_helper.c |  6 ++--
 6 files changed, 94 insertions(+), 94 deletions(-)

diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 690f448cb9..77e611e81c 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -40,7 +40,7 @@
 static void cpu_ppc_tb_stop (CPUPPCState *env);
 static void cpu_ppc_tb_start (CPUPPCState *env);
 
-void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
+void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
 CPUState *cs = CPU(cpu);
 CPUPPCState *env = >env;
@@ -56,21 +56,21 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
 old_pending = env->pending_interrupts;
 
 if (level) {
-env->pending_interrupts |= 1 << n_IRQ;
+env->pending_interrupts |= irq;
 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
-env->pending_interrupts &= ~(1 << n_IRQ);
+env->pending_interrupts &= ~irq;
 if (env->pending_interrupts == 0) {
 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
 }
 
 if (old_pending != env->pending_interrupts) {
-kvmppc_set_interrupt(cpu, n_IRQ, level);
+kvmppc_set_interrupt(cpu, irq, level);
 }
 
 
-trace_ppc_irq_set_exit(env, n_IRQ, level, env->pending_interrupts,
+trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
 
 if (locked) {
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index a07d5aca0f..956938ebcd 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -127,7 +127,7 @@ ppc40x_set_tb_clk(uint32_t value) "new frequency %" PRIu32
 ppc40x_timers_init(uint32_t value) "frequency %" PRIu32
 
 ppc_irq_set(void *env, uint32_t pin, uint32_t level) "env [%p] pin %d level %d"
-ppc_irq_set_exit(void *env, uint32_t n_IRQ, uint32_t level, uint32_t pending, 
uint32_t request) "env [%p] n_IRQ %d level %d => pending 0x%08" PRIx32 " req 
0x%08" PRIx32
+ppc_irq_set_exit(void *env, uint32_t irq, uint32_t level, uint32_t pending, 
uint32_t request) "env [%p] irq 0x%05" PRIx32 " level %d => pending 0x%08" 
PRIx32 " req 0x%08" PRIx32
 ppc_irq_set_state(const char *name, uint32_t level) "\"%s\" level %d"
 ppc_irq_reset(const char *name) "%s"
 ppc_irq_cpu(const char *action) "%s"
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index cca6c4e51c..2433756973 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -2416,27 +2416,27 @@ enum {
 /* Hardware exceptions definitions */
 enum {
 /* External hardware exception sources */
-PPC_INTERRUPT_RESET = 0,  /* Reset exception  */
-PPC_INTERRUPT_WAKEUP, /* Wakeup exception */
-PPC_INTERRUPT_MCK,/* Machine check exception  */
-PPC_INTERRUPT_EXT,/* External interrupt   */
-PPC_INTERRUPT_SMI,/* System management interrupt  */
-PPC_INTERRUPT_CEXT,   /* Critical external interrupt  */
-PPC_INTERRUPT_DEBUG,  /* External debug exception */
-PPC_INTERRUPT_THERM,  /* Thermal exception*/
+PPC_INTERRUPT_RESET = 0x1,  /* Reset exception
*/
+PPC_INTERRUPT_WAKEUP= 0x2,  /* Wakeup exception   
*/
+PPC_INTERRUPT_MCK   = 0x4,  /* Machine check exception
*/
+PPC_INTERRUPT_EXT   = 0x8,  /* External interrupt 
*/
+PPC_INTERRUPT_SMI   = 0x00010,  /* System management interrupt
*/
+PPC_INTERRUPT_CEXT  = 0x00020,  /* Critical external interrupt
*/
+PPC_INTERRUPT_DEBUG = 0x00040,  /* External debug exception   
*/
+PPC_INTERRUPT_THERM = 0x00080,  /* Thermal exception  
*/
 /* Internal hardware exception sources */
-PPC_INTERRUPT_DECR,   /* Decrementer exception*/
-PPC_INTERRUPT_HDECR,  /* Hypervisor decrementer exception */
-PPC_INTERRUPT_PIT,/* Programmable interval timer interrupt */
-PPC_INTERRUPT_FIT,/* Fixed interval timer interrupt   */
-PPC_INTERRUPT_WDT, 

[PATCH v3 02/29] target/ppc: always use ppc_set_irq to set env->pending_interrupts

2022-10-11 Thread Matheus Ferst
Use ppc_set_irq to raise/clear interrupts to ensure CPU_INTERRUPT_HARD
will be set/reset accordingly.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 17 +++--
 target/ppc/misc_helper.c |  9 ++---
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 3f8ff9bcf3..c3c30c5d1b 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -23,6 +23,7 @@
 #include "exec/exec-all.h"
 #include "internal.h"
 #include "helper_regs.h"
+#include "hw/ppc/ppc.h"
 
 #include "trace.h"
 
@@ -2080,7 +2081,6 @@ void helper_rfebb(CPUPPCState *env, target_ulong s)
 static void do_ebb(CPUPPCState *env, int ebb_excp)
 {
 PowerPCCPU *cpu = env_archcpu(env);
-CPUState *cs = CPU(cpu);
 
 /*
  * FSCR_EBB and FSCR_IC_EBB are the same bits used with
@@ -2098,8 +2098,7 @@ static void do_ebb(CPUPPCState *env, int ebb_excp)
 if (FIELD_EX64(env->msr, MSR, PR)) {
 powerpc_excp(cpu, ebb_excp);
 } else {
-env->pending_interrupts |= PPC_INTERRUPT_EBB;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, PPC_INTERRUPT_EBB, 1);
 }
 }
 
@@ -2292,7 +2291,7 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb)
 return;
 }
 
-env->pending_interrupts &= ~irq;
+ppc_set_irq(env_archcpu(env), irq, 0);
 }
 
 void helper_msgsnd(target_ulong rb)
@@ -2311,8 +2310,7 @@ void helper_msgsnd(target_ulong rb)
 CPUPPCState *cenv = >env;
 
 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
-cenv->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, irq, 1);
 }
 }
 qemu_mutex_unlock_iothread();
@@ -2336,7 +2334,7 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong 
rb)
 return;
 }
 
-env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
 }
 
 static void book3s_msgsnd_common(int pir, int irq)
@@ -2350,8 +2348,7 @@ static void book3s_msgsnd_common(int pir, int irq)
 
 /* TODO: broadcast message to all threads of the same  processor */
 if (cenv->spr_cb[SPR_PIR].default_value == pir) {
-cenv->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, irq, 1);
 }
 }
 qemu_mutex_unlock_iothread();
@@ -2377,7 +2374,7 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong 
rb)
 return;
 }
 
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
 }
 
 /*
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 05e35572bc..a9bc1522e2 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -25,6 +25,7 @@
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
 #include "mmu-book3s-v3.h"
+#include "hw/ppc/ppc.h"
 
 #include "helper_regs.h"
 
@@ -173,7 +174,6 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
 void helper_store_dpdes(CPUPPCState *env, target_ulong val)
 {
 PowerPCCPU *cpu = env_archcpu(env);
-CPUState *cs = CPU(cpu);
 
 helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
 
@@ -184,12 +184,7 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
 return;
 }
 
-if (val & 0x1) {
-env->pending_interrupts |= PPC_INTERRUPT_DOORBELL;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
-} else {
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-}
+ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
 }
 #endif /* defined(TARGET_PPC64) */
 
-- 
2.25.1




[PATCH v3 00/29] PowerPC interrupt rework

2022-10-11 Thread Matheus Ferst
Link to v2: https://lists.gnu.org/archive/html/qemu-ppc/2022-09/msg00556.html
This series is also available as a git branch: 
https://github.com/PPC64/qemu/tree/ferst-interrupt-fix-v3
Patches without review: 3-27

This new version rebases the patch series on the current master and
fixes some problems pointed out by Fabiano on v2.

Matheus Ferst (29):
  target/ppc: define PPC_INTERRUPT_* values directly
  target/ppc: always use ppc_set_irq to set env->pending_interrupts
  target/ppc: split interrupt masking and delivery from ppc_hw_interrupt
  target/ppc: prepare to split interrupt masking and delivery by excp_model
  target/ppc: create an interrupt masking method for POWER9/POWER10
  target/ppc: remove unused interrupts from p9_next_unmasked_interrupt
  target/ppc: create an interrupt deliver method for POWER9/POWER10
  target/ppc: remove unused interrupts from p9_deliver_interrupt
  target/ppc: remove generic architecture checks from p9_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9
  target/ppc: add power-saving interrupt masking logic to 
p9_next_unmasked_interrupt
  target/ppc: create an interrupt masking method for POWER8
  target/ppc: remove unused interrupts from p8_next_unmasked_interrupt
  target/ppc: create an interrupt deliver method for POWER8
  target/ppc: remove unused interrupts from p8_deliver_interrupt
  target/ppc: remove generic architecture checks from p8_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8
  target/ppc: add power-saving interrupt masking logic to 
p8_next_unmasked_interrupt
  target/ppc: create an interrupt masking method for POWER7
  target/ppc: remove unused interrupts from p7_next_unmasked_interrupt
  target/ppc: create an interrupt deliver method for POWER7
  target/ppc: remove unused interrupts from p7_deliver_interrupt
  target/ppc: remove generic architecture checks from p7_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7
  target/ppc: add power-saving interrupt masking logic to 
p7_next_unmasked_interrupt
  target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds
  target/ppc: introduce ppc_maybe_interrupt
  target/ppc: unify cpu->has_work based on cs->interrupt_request
  target/ppc: move the p*_interrupt_powersave methods to excp_helper.c

 hw/ppc/pnv_core.c|   1 +
 hw/ppc/ppc.c |  17 +-
 hw/ppc/spapr_hcall.c |   6 +
 hw/ppc/spapr_rtas.c  |   2 +-
 hw/ppc/trace-events  |   2 +-
 target/ppc/cpu.c |   4 +
 target/ppc/cpu.h |  43 +-
 target/ppc/cpu_init.c| 212 +-
 target/ppc/excp_helper.c | 887 ++-
 target/ppc/helper.h  |   1 +
 target/ppc/helper_regs.c |   2 +
 target/ppc/misc_helper.c |  11 +-
 target/ppc/translate.c   |   2 +
 13 files changed, 833 insertions(+), 357 deletions(-)

-- 
2.25.1




[PATCH 3/6] target/ppc: fix REQUIRE_HV macro definition

2022-10-06 Thread Matheus Ferst
The macro is missing a '{' after the if condition. Any use of REQUIRE_HV
would cause a compilation error.

Fixes: fc34e81acd51 ("target/ppc: add macros to check privilege level")
Signed-off-by: Matheus Ferst 
---
 target/ppc/translate.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index eaac8670b1..435066c4a3 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6545,12 +6545,12 @@ static int64_t dw_compose_ea(DisasContext *ctx, int x)
 }   \
 } while (0)
 
-#define REQUIRE_HV(CTX) \
-do {\
-if (unlikely((CTX)->pr || !(CTX)->hv))  \
-gen_priv_opc(CTX);  \
-return true;\
-}   \
+#define REQUIRE_HV(CTX) \
+do {\
+if (unlikely((CTX)->pr || !(CTX)->hv)) {\
+gen_priv_opc(CTX);  \
+return true;\
+}   \
 } while (0)
 #else
 #define REQUIRE_SV(CTX) do { gen_priv_opc(CTX); return true; } while (0)
-- 
2.25.1




[PATCH 6/6] target/ppc: move msgsync to decodetree

2022-10-06 Thread Matheus Ferst
Signed-off-by: Matheus Ferst 
---
 target/ppc/insn32.decode   |  1 +
 target/ppc/translate.c | 14 --
 target/ppc/translate/processor-ctrl-impl.c.inc |  9 +
 3 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 5ba4a6807d..70a3b4de5e 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -915,3 +915,4 @@ MSGCLR  01 - - . 0011101110 -   
@X_rb
 MSGSND  01 - - . 0011001110 -   @X_rb
 MSGCLRP 01 - - . 0010101110 -   @X_rb
 MSGSNDP 01 - - . 0010001110 -   @X_rb
+MSGSYNC 01 - - - 1101110110 -
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 087ab8e69d..f092bbeb8b 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6239,18 +6239,6 @@ static void gen_icbt_440(DisasContext *ctx)
  */
 }
 
-/* Embedded.Processor Control */
-
-static void gen_msgsync(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
-GEN_PRIV(ctx);
-#else
-CHK_HV(ctx);
-#endif /* defined(CONFIG_USER_ONLY) */
-/* interpreted as no-op */
-}
-
 #if defined(TARGET_PPC64)
 static void gen_maddld(DisasContext *ctx)
 {
@@ -6853,8 +6841,6 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 
0x18, 0x0001,
PPC_NONE, PPC2_BOOKE206),
 GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x0381,
PPC_NONE, PPC2_BOOKE206),
-GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x,
-   PPC_NONE, PPC2_ISA300),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
 GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
 GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x, PPC_440_SPEC),
diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc 
b/target/ppc/translate/processor-ctrl-impl.c.inc
index 3703001f31..021e365a57 100644
--- a/target/ppc/translate/processor-ctrl-impl.c.inc
+++ b/target/ppc/translate/processor-ctrl-impl.c.inc
@@ -92,3 +92,12 @@ static bool trans_MSGSNDP(DisasContext *ctx, arg_X_rb *a)
 #endif
 return true;
 }
+
+static bool trans_MSGSYNC(DisasContext *ctx, arg_MSGSYNC *a)
+{
+REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+REQUIRE_HV(ctx);
+
+/* interpreted as no-op */
+return true;
+}
-- 
2.25.1




[PATCH 5/6] target/ppc: move msgclrp/msgsndp to decodetree

2022-10-06 Thread Matheus Ferst
Signed-off-by: Matheus Ferst 
---
 target/ppc/insn32.decode  |  2 ++
 target/ppc/translate.c| 26 ---
 .../ppc/translate/processor-ctrl-impl.c.inc   | 24 +
 3 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index bba49ded1b..5ba4a6807d 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -913,3 +913,5 @@ TLBIEL  01 . - .. . . . 0100010010 -
@X_tlbie
 
 MSGCLR  01 - - . 0011101110 -   @X_rb
 MSGSND  01 - - . 0011001110 -   @X_rb
+MSGCLRP 01 - - . 0010101110 -   @X_rb
+MSGSNDP 01 - - . 0010001110 -   @X_rb
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 889cca6325..087ab8e69d 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6241,28 +6241,6 @@ static void gen_icbt_440(DisasContext *ctx)
 
 /* Embedded.Processor Control */
 
-#if defined(TARGET_PPC64)
-static void gen_msgclrp(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
-GEN_PRIV(ctx);
-#else
-CHK_SV(ctx);
-gen_helper_book3s_msgclrp(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-
-static void gen_msgsndp(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
-GEN_PRIV(ctx);
-#else
-CHK_SV(ctx);
-gen_helper_book3s_msgsndp(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-#endif
-
 static void gen_msgsync(DisasContext *ctx)
 {
 #if defined(CONFIG_USER_ONLY)
@@ -6896,10 +6874,6 @@ GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x, 
PPC_ALTIVEC),
 GEN_HANDLER_E(maddhd_maddhdu, 0x04, 0x18, 0xFF, 0x, PPC_NONE,
   PPC2_ISA300),
 GEN_HANDLER_E(maddld, 0x04, 0x19, 0xFF, 0x, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER2_E(msgsndp, "msgsndp", 0x1F, 0x0E, 0x04, 0x03ff0001,
-   PPC_NONE, PPC2_ISA207S),
-GEN_HANDLER2_E(msgclrp, "msgclrp", 0x1F, 0x0E, 0x05, 0x03ff0001,
-   PPC_NONE, PPC2_ISA207S),
 #endif
 
 #undef GEN_INT_ARITH_ADD
diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc 
b/target/ppc/translate/processor-ctrl-impl.c.inc
index 0192b45c8f..3703001f31 100644
--- a/target/ppc/translate/processor-ctrl-impl.c.inc
+++ b/target/ppc/translate/processor-ctrl-impl.c.inc
@@ -68,3 +68,27 @@ static bool trans_MSGSND(DisasContext *ctx, arg_X_rb *a)
 #endif
 return true;
 }
+
+static bool trans_MSGCLRP(DisasContext *ctx, arg_X_rb *a)
+{
+REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
+REQUIRE_SV(ctx);
+#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
+gen_helper_book3s_msgclrp(cpu_env, cpu_gpr[a->rb]);
+#else
+qemu_build_not_reached();
+#endif
+return true;
+}
+
+static bool trans_MSGSNDP(DisasContext *ctx, arg_X_rb *a)
+{
+REQUIRE_INSNS_FLAGS2(ctx, ISA207S);
+REQUIRE_SV(ctx);
+#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
+gen_helper_book3s_msgsndp(cpu_env, cpu_gpr[a->rb]);
+#else
+qemu_build_not_reached();
+#endif
+return true;
+}
-- 
2.25.1




[PATCH 2/6] target/ppc: fix msgsync insns flags

2022-10-06 Thread Matheus Ferst
This instruction was added by Power ISA 3.0, using PPC2_PRCNTL makes it
available for older processors, like de e5500 and e6500.

Fixes: 7af1e7b02264 ("target/ppc: add support for hypervisor doorbells on 
book3s CPUs")
Signed-off-by: Matheus Ferst 
---
 target/ppc/translate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 37d7018d18..eaac8670b1 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6906,7 +6906,7 @@ GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 
0x03ff0001,
 GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001,
PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)),
 GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x,
-   PPC_NONE, PPC2_PRCNTL),
+   PPC_NONE, PPC2_ISA300),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
 GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
 GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x, PPC_440_SPEC),
-- 
2.25.1




[PATCH 4/6] target/ppc: move msgclr/msgsnd to decodetree

2022-10-06 Thread Matheus Ferst
Signed-off-by: Matheus Ferst 
---
 target/ppc/insn32.decode  |  5 ++
 target/ppc/translate.c| 34 +
 .../ppc/translate/processor-ctrl-impl.c.inc   | 70 +++
 3 files changed, 77 insertions(+), 32 deletions(-)
 create mode 100644 target/ppc/translate/processor-ctrl-impl.c.inc

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index a5249ee32c..bba49ded1b 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -908,3 +908,8 @@ SLBSYNC 01 - - - 0101010010 -
 
 TLBIE   01 . - .. . . . 0100110010 -@X_tlbie
 TLBIEL  01 . - .. . . . 0100010010 -@X_tlbie
+
+# Processor Control Instructions
+
+MSGCLR  01 - - . 0011101110 -   @X_rb
+MSGSND  01 - - . 0011001110 -   @X_rb
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 435066c4a3..889cca6325 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6241,34 +6241,6 @@ static void gen_icbt_440(DisasContext *ctx)
 
 /* Embedded.Processor Control */
 
-static void gen_msgclr(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
-GEN_PRIV(ctx);
-#else
-CHK_HV(ctx);
-if (is_book3s_arch2x(ctx)) {
-gen_helper_book3s_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-} else {
-gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]);
-}
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-
-static void gen_msgsnd(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
-GEN_PRIV(ctx);
-#else
-CHK_HV(ctx);
-if (is_book3s_arch2x(ctx)) {
-gen_helper_book3s_msgsnd(cpu_gpr[rB(ctx->opcode)]);
-} else {
-gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]);
-}
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-
 #if defined(TARGET_PPC64)
 static void gen_msgclrp(DisasContext *ctx)
 {
@@ -6628,6 +6600,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, 
arg_PLS_D *a)
 
 #include "translate/branch-impl.c.inc"
 
+#include "translate/processor-ctrl-impl.c.inc"
+
 #include "translate/storage-ctrl-impl.c.inc"
 
 /* Handles lfdp */
@@ -6901,10 +6875,6 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 
0x18, 0x0001,
PPC_NONE, PPC2_BOOKE206),
 GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x0381,
PPC_NONE, PPC2_BOOKE206),
-GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001,
-   PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)),
-GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001,
-   PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)),
 GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x,
PPC_NONE, PPC2_ISA300),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc 
b/target/ppc/translate/processor-ctrl-impl.c.inc
new file mode 100644
index 00..0192b45c8f
--- /dev/null
+++ b/target/ppc/translate/processor-ctrl-impl.c.inc
@@ -0,0 +1,70 @@
+/*
+ * Power ISA decode for Storage Control instructions
+ *
+ * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Processor Control Instructions
+ */
+
+static bool trans_MSGCLR(DisasContext *ctx, arg_X_rb *a)
+{
+if (!(ctx->insns_flags2 & PPC2_ISA207S)) {
+/*
+ * Before Power ISA 2.07, processor control instructions were only
+ * implemented in the "Embedded.Processor Control" category.
+ */
+REQUIRE_INSNS_FLAGS2(ctx, PRCNTL);
+}
+
+REQUIRE_HV(ctx);
+
+#if !defined(CONFIG_USER_ONLY)
+if (is_book3s_arch2x(ctx)) {
+gen_helper_book3s_msgclr(cpu_env, cpu_gpr[a->rb]);
+} else {
+gen_helper_msgclr(cpu_env, cpu_gpr[a->rb]);
+}
+#else
+qemu_build_not_reached();
+#endif
+return true;
+}
+
+static bool trans_MSGSND(DisasContext *ctx, arg_X_rb *a)
+{
+if (!(ctx->insns_flags2 & PPC2_ISA207S)) {
+/*
+ * Before Power ISA 2.07, processor control instructions were only
+ * implemented in the "Embedded.Processor Contro

[PATCH 1/6] target/ppc: fix msgclr/msgsnd insns flags

2022-10-06 Thread Matheus Ferst
On Power ISA v2.07, the category for these instructions became
"Embedded.Processor Control" or "Book S".

Signed-off-by: Matheus Ferst 
---
 target/ppc/translate.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index e810842925..37d7018d18 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6902,9 +6902,9 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 
0x18, 0x0001,
 GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x0381,
PPC_NONE, PPC2_BOOKE206),
 GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001,
-   PPC_NONE, PPC2_PRCNTL),
+   PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)),
 GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001,
-   PPC_NONE, PPC2_PRCNTL),
+   PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)),
 GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x,
PPC_NONE, PPC2_PRCNTL),
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
-- 
2.25.1




[PATCH 0/6] Enable doorbell instruction for POWER8 CPUs

2022-10-06 Thread Matheus Ferst
Reviewing the interrupt rework patch series, Fabiano noted[1] that the
POWER8 User's Manual lists the Directed Hypervisor Doorbell interrupt,
even without implementing the "Embedded.Processor Control" category. The
manual also lists the msgclr and msgsnd instructions, but the decode
legacy code currently gates them with the PPC2_PRCNTL flag, which is not
enabled for this CPU.

Reading the Power ISA v2.07, we noticed that the title of the
Processor Control chapter does not include the category information like
in Power ISA v2.06, and the instruction listing in the appendices says
that their category is "S\nE.PC". The document is not clear about this
notation, but since implementations should support only one environment
(embedded or server), I'd interpret this change as "these instructions
are now available if the processor implements the server environment or
E.PC category."

While reviewing the flag for those instructions, we also saw that the
msgsync, introduced in PowerISA v3.0, was available on all processors
with the PPC2_PRCNTL flag, which includes older CPUs like e500mc and
e6500.

This patch series fixes the instruction flags for these three
instructions. We then take this opportunity to move processor control
instruction to decodetree, fixing an embarrassing error in the
definition of the REQUIRE_HV macro along the way.

[1] https://lists.gnu.org/archive/html/qemu-ppc/2022-09/msg00586.html

Matheus Ferst (6):
  target/ppc: fix msgclr/msgsnd insns flags
  target/ppc: fix msgsync insns flags
  target/ppc: fix REQUIRE_HV macro definition
  target/ppc: move msgclr/msgsnd to decodetree
  target/ppc: move msgclrp/msgsndp to decodetree
  target/ppc: move msgsync to decodetree

 target/ppc/insn32.decode  |   8 ++
 target/ppc/translate.c|  86 ++-
 .../ppc/translate/processor-ctrl-impl.c.inc   | 103 ++
 3 files changed, 119 insertions(+), 78 deletions(-)
 create mode 100644 target/ppc/translate/processor-ctrl-impl.c.inc

-- 
2.25.1




[RFC PATCH v2 29/29] target/ppc: move the p*_interrupt_powersave methods to excp_helper.c

2022-09-27 Thread Matheus Ferst
Move the methods to excp_helper.c and make them static.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c| 102 ---
 target/ppc/excp_helper.c | 102 +++
 target/ppc/internal.h|   6 ---
 3 files changed, 102 insertions(+), 108 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 4d0064c7a5..a9c2726d51 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,30 +5960,6 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-int p7_interrupt_powersave(CPUPPCState *env)
-{
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
-return PPC_INTERRUPT_EXT;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
-return PPC_INTERRUPT_DECR;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return PPC_INTERRUPT_MCK;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return PPC_INTERRUPT_HMI;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
@@ -6120,38 +6096,6 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-int p8_interrupt_powersave(CPUPPCState *env)
-{
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
-return PPC_INTERRUPT_EXT;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
-return PPC_INTERRUPT_DECR;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return PPC_INTERRUPT_MCK;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return PPC_INTERRUPT_HMI;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
-return PPC_INTERRUPT_DOORBELL;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
-return PPC_INTERRUPT_HDOORBELL;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
@@ -6325,52 +6269,6 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
-int p9_interrupt_powersave(CPUPPCState *env)
-{
-/* External Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_EEE)) {
-bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-if (!heic || !FIELD_EX64_HV(env->msr) ||
-FIELD_EX64(env->msr, MSR, PR)) {
-return PPC_INTERRUPT_EXT;
-}
-}
-/* Decrementer Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_DEE)) {
-return PPC_INTERRUPT_DECR;
-}
-/* Machine Check or Hypervisor Maintenance Exception */
-if (env->spr[SPR_LPCR] & LPCR_OEE) {
-if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
-return PPC_INTERRUPT_MCK;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
-return PPC_INTERRUPT_HMI;
-}
-}
-/* Privileged Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_PDEE)) {
-return PPC_INTERRUPT_DOORBELL;
-}
-/* Hypervisor Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_HDEE)) {
-return PPC_INTERRUPT_HDOORBELL;
-}
-/* Hypervisor virtualization exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
-(env->spr[SPR_LPCR] & LPCR_HVEE)) {
-return PPC_INTERRUPT_HVIRT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
-return 0;
-}
-
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc 

[RFC PATCH v2 27/29] target/ppc: introduce ppc_maybe_interrupt

2022-09-27 Thread Matheus Ferst
The method checks if any pending interrupt is unmasked and calls
cpu_interrupt/cpu_reset_interrupt accordingly. Code that raises/lowers
or masks/unmasks interrupts should call this method to keep
CPU_INTERRUPT_HARD coherent with env->pending_interrupts.

Signed-off-by: Matheus Ferst 
---
v2:
  - Found many other places where ppc_maybe_interrupt had to be called
with the IO and kvm-nested tests that CĂ©dric suggested.
  - Create a helper to call ppc_maybe_interrupt to avoid using
helper_store_msr in WRTEE[I].

I couldn't find a better name for this method, so I used "maybe
interrupt" just like we have "maybe bswap" for gdbstub registers.
---
 hw/ppc/pnv_core.c|  1 +
 hw/ppc/ppc.c |  7 +--
 hw/ppc/spapr_hcall.c |  6 ++
 hw/ppc/spapr_rtas.c  |  2 +-
 target/ppc/cpu.c |  2 ++
 target/ppc/cpu.h |  1 +
 target/ppc/excp_helper.c | 29 +
 target/ppc/helper.h  |  1 +
 target/ppc/helper_regs.c |  2 ++
 target/ppc/translate.c   |  2 ++
 10 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 19e8eb885f..9ee79192dd 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -58,6 +58,7 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
 env->msr |= MSR_HVB; /* Hypervisor mode */
 env->spr[SPR_HRMOR] = pc->hrmor;
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 
 pcc->intc_reset(pc->chip, cpu);
 }
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 77e611e81c..dc86c1c7db 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -42,7 +42,6 @@ static void cpu_ppc_tb_start (CPUPPCState *env);
 
 void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
-CPUState *cs = CPU(cpu);
 CPUPPCState *env = >env;
 unsigned int old_pending;
 bool locked = false;
@@ -57,19 +56,15 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 
 if (level) {
 env->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 env->pending_interrupts &= ~irq;
-if (env->pending_interrupts == 0) {
-cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
-}
 }
 
 if (old_pending != env->pending_interrupts) {
+ppc_maybe_interrupt(env);
 kvmppc_set_interrupt(cpu, irq, level);
 }
 
-
 trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index a8d4a6bcf0..23aa41c879 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -490,6 +490,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 
 env->msr |= (1ULL << MSR_EE);
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 
 if (spapr_cpu->prod) {
 spapr_cpu->prod = false;
@@ -500,6 +501,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 cs->halted = 1;
 cs->exception_index = EXCP_HLT;
 cs->exit_request = 1;
+ppc_maybe_interrupt(env);
 }
 
 return H_SUCCESS;
@@ -521,6 +523,7 @@ static target_ulong h_confer_self(PowerPCCPU *cpu)
 cs->halted = 1;
 cs->exception_index = EXCP_HALTED;
 cs->exit_request = 1;
+ppc_maybe_interrupt(>env);
 
 return H_SUCCESS;
 }
@@ -633,6 +636,7 @@ static target_ulong h_prod(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
 spapr_cpu = spapr_cpu_state(tcpu);
 spapr_cpu->prod = true;
 cs->halted = 0;
+ppc_maybe_interrupt(>env);
 qemu_cpu_kick(cs);
 
 return H_SUCCESS;
@@ -1661,6 +1665,7 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu,
 spapr_cpu->in_nested = true;
 
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 tlb_flush(cs);
 env->reserve_addr = -1; /* Reset the reservation */
 
@@ -1802,6 +1807,7 @@ out_restore_l1:
 spapr_cpu->in_nested = false;
 
 hreg_compute_hflags(env);
+ppc_maybe_interrupt(env);
 tlb_flush(cs);
 env->reserve_addr = -1; /* Reset the reservation */
 
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index d58b65e88f..3f664ea02c 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -214,9 +214,9 @@ static void rtas_stop_self(PowerPCCPU *cpu, 
SpaprMachineState *spapr,
  * guest.
  * For the same reason, set PSSCR_EC.
  */
-ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
 env->spr[SPR_PSSCR] |= PSSCR_EC;
 cs->halted = 1;
+ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
 kvmppc_set_reg_ppc_online(cpu, 0);
 qemu_cpu_kick(cs);
 }
diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index e95b4c5ee1..1a97b41c6b 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -82,6 +82,8 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
  

[RFC PATCH v2 26/29] target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds

2022-09-27 Thread Matheus Ferst
Writes to LPCR are hypervisor privileged.

Signed-off-by: Matheus Ferst 
---
The method introduced in the next patch, ppc_maybe_interrupt, will be
called in ppc_store_lpcr and only available in !CONFIG_USER_ONLY builds.
---
 target/ppc/cpu.c | 2 ++
 target/ppc/cpu.h | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index 0ebac04bc4..e95b4c5ee1 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -73,6 +73,7 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value)
 hreg_store_msr(env, value, 0);
 }
 
+#if !defined(CONFIG_USER_ONLY)
 void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 {
 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
@@ -82,6 +83,7 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 /* The gtse bit affects hflags */
 hreg_compute_hflags(env);
 }
+#endif
 
 static inline void fpscr_set_rounding_mode(CPUPPCState *env)
 {
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 9ccd23db04..7b13d4cf86 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1370,9 +1370,9 @@ void ppc_translate_init(void);
 
 #if !defined(CONFIG_USER_ONLY)
 void ppc_store_sdr1(CPUPPCState *env, target_ulong value);
+void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
 #endif /* !defined(CONFIG_USER_ONLY) */
 void ppc_store_msr(CPUPPCState *env, target_ulong value);
-void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
 
 void ppc_cpu_list(void);
 
-- 
2.25.1




[RFC PATCH v2 19/29] target/ppc: create an interrupt masking method for POWER7

2022-09-27 Thread Matheus Ferst
The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.
No functional change intended.

Signed-off-by: Matheus Ferst 
---
v2:
  - Renamed the method from ppc_pending_interrupt_p7 to
p7_next_unmasked_interrupt;
  - Processor-specific stuff moved to the following patches to ease
review.
---
 target/ppc/excp_helper.c | 114 +++
 1 file changed, 114 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 609579f45f..8e1e18317d 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,6 +1679,118 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+static int p7_next_unmasked_interrupt(CPUPPCState *env)
+{
+bool async_deliver;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+#if 0 /* TODO */
+/* External debug exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+return PPC_INTERRUPT_DEBUG;
+}
+#endif
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)) {
+/* External critical interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+return PPC_INTERRUPT_CEXT;
+}
+}
+if (async_deliver != 0) {
+/* Watchdog timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+return PPC_INTERRUPT_WDT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+return PPC_INTERRUPT_CDOORBELL;
+}
+/* Fixed interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+return PPC_INTERRUPT_FIT;
+}
+/* Programmable interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+return PPC_INTERRUPT_PIT;
+}
+/* Decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+return PPC_INTERRUPT_DECR;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+return PPC_INTERRUPT_PERFM;
+}
+/* Thermal interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+return PPC_INTERRUPT_THERM;
+}
+/* EBB exception */
+if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+/*
+ * EBB exception must be taken in problem state and
+ * with BESCR_GE set.
+ */
+if (FIELD_EX64(env->msr, MSR, PR) &&
+(env->spr[SPR_BESCR]

[RFC PATCH v2 25/29] target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt

2022-09-27 Thread Matheus Ferst
Export p7_interrupt_powersave and use it in p7_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c|  2 +-
 target/ppc/excp_helper.c | 24 
 target/ppc/internal.h|  1 +
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index dd127cbeea..26686d1557 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,7 +5960,7 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-static int p7_interrupt_powersave(CPUPPCState *env)
+int p7_interrupt_powersave(CPUPPCState *env)
 {
 if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
 (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index ca594c3b9e..497a9889d1 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1687,10 +1687,18 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p7_next_unmasked_interrupt(CPUPPCState *env)
 {
-bool async_deliver;
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = CPU(cpu);
+/* Ignore MSR[EE] when coming out of some power management states */
+bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
 assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0);
 
+if (cs->halted) {
+/* LPCR[PECE] controls which interrupts can exit power-saving mode */
+return p7_interrupt_powersave(env);
+}
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
@@ -1702,19 +1710,11 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
 }
 #endif
 
-/*
- * For interrupts that gate on MSR:EE, we need to do something a
- * bit more subtle, as we need to let them through even when EE is
- * clear when coming out of some power management states (in order
- * for them to become a 0x100).
- */
-async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
 /* Hypervisor decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
 /* LPCR will be clear when not supported so this will work */
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
 return PPC_INTERRUPT_HDECR;
 }
@@ -1725,13 +1725,13 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
 bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
 /* HEIC blocks delivery to the hypervisor */
-if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
 return PPC_INTERRUPT_EXT;
 }
 }
-if (async_deliver != 0) {
+if (msr_ee != 0) {
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 9069874adb..25827ebf6f 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -309,6 +309,7 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int 
xmsk)
 #if defined(TARGET_PPC64)
 int p9_interrupt_powersave(CPUPPCState *env);
 int p8_interrupt_powersave(CPUPPCState *env);
+int p7_interrupt_powersave(CPUPPCState *env);
 #endif
 
 #endif /* PPC_INTERNAL_H */
-- 
2.25.1




[RFC PATCH v2 18/29] target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt

2022-09-27 Thread Matheus Ferst
Export p8_interrupt_powersave and use it in p8_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c|  2 +-
 target/ppc/excp_helper.c | 24 
 target/ppc/internal.h|  1 +
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 59e4c325c5..319d2355ec 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6133,7 +6133,7 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
-static int p8_interrupt_powersave(CPUPPCState *env)
+int p8_interrupt_powersave(CPUPPCState *env)
 {
 if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
 (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 2e8d4699a9..609579f45f 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1687,28 +1687,28 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p8_next_unmasked_interrupt(CPUPPCState *env)
 {
-bool async_deliver;
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = CPU(cpu);
+/* Ignore MSR[EE] when coming out of some power management states */
+bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
 assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0);
 
+if (cs->halted) {
+/* LPCR[PECE] controls which interrupts can exit power-saving mode */
+return p8_interrupt_powersave(env);
+}
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
 }
 
-/*
- * For interrupts that gate on MSR:EE, we need to do something a
- * bit more subtle, as we need to let them through even when EE is
- * clear when coming out of some power management states (in order
- * for them to become a 0x100).
- */
-async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
 /* Hypervisor decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
 /* LPCR will be clear when not supported so this will work */
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
 return PPC_INTERRUPT_HDECR;
 }
@@ -1719,13 +1719,13 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
 bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
 /* HEIC blocks delivery to the hypervisor */
-if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
 return PPC_INTERRUPT_EXT;
 }
 }
-if (async_deliver != 0) {
+if (msr_ee != 0) {
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 41e79adfdb..9069874adb 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -308,6 +308,7 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int 
xmsk)
 
 #if defined(TARGET_PPC64)
 int p9_interrupt_powersave(CPUPPCState *env);
+int p8_interrupt_powersave(CPUPPCState *env);
 #endif
 
 #endif /* PPC_INTERNAL_H */
-- 
2.25.1




[RFC PATCH v2 24/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7

2022-09-27 Thread Matheus Ferst
Move the interrupt masking logic out of cpu_has_work_POWER7 in a new
method, p7_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode. No functional change
intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 45 ---
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 319d2355ec..dd127cbeea 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5960,6 +5960,30 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
+static int p7_interrupt_powersave(CPUPPCState *env)
+{
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
+return PPC_INTERRUPT_EXT;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
+return PPC_INTERRUPT_DECR;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+return PPC_INTERRUPT_MCK;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+return PPC_INTERRUPT_HMI;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+return 0;
+}
+
 static bool cpu_has_work_POWER7(CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -5969,26 +5993,7 @@ static bool cpu_has_work_POWER7(CPUState *cs)
 if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
 return false;
 }
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return true;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return true;
-}
-return false;
+return p7_interrupt_powersave(env) != 0;
 } else {
 return FIELD_EX64(env->msr, MSR, EE) &&
(cs->interrupt_request & CPU_INTERRUPT_HARD);
-- 
2.25.1




[RFC PATCH v2 23/29] target/ppc: remove generic architecture checks from p7_deliver_interrupt

2022-09-27 Thread Matheus Ferst
No functional change intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index de6972d002..ca594c3b9e 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2072,9 +2072,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 break;
 
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
-if (ppc_decr_clear_on_delivery(env)) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-}
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
 case PPC_INTERRUPT_PERFM:
-- 
2.25.1




[RFC PATCH v2 15/29] target/ppc: remove unused interrupts from p8_deliver_interrupt

2022-09-27 Thread Matheus Ferst
Remove the following unused interrupts from the POWER8 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Hypervisor Doorbell, Doorbell, and Critical Doorbell: processor does
  not implement the "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 48 
 1 file changed, 48 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 0405fc8eee..4cbf6b29fc 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1979,29 +1979,16 @@ static void p8_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 CPUState *cs = env_cpu(env);
 
 switch (interrupt) {
-case PPC_INTERRUPT_RESET: /* External reset */
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-break;
 case PPC_INTERRUPT_MCK: /* Machine check exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
 powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
 break;
-#if 0 /* TODO */
-case PPC_INTERRUPT_DEBUG: /* External debug exception */
-env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-break;
-#endif
 
 case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
 /* HDEC clears on delivery */
 env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
 powerpc_excp(cpu, POWERPC_EXCP_HDECR);
 break;
-case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-break;
 
 case PPC_INTERRUPT_EXT:
 if (books_vhyp_promotes_external_to_hvirt(cpu)) {
@@ -2010,52 +1997,17 @@ static void p8_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
 }
 break;
-case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-break;
 
-case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-break;
-case PPC_INTERRUPT_CDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-break;
-case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-break;
-case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-break;
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
 if (ppc_decr_clear_on_delivery(env)) {
 env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
 }
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
-case PPC_INTERRUPT_DOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-if (is_book3s_arch2x(env)) {
-powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-} else {
-powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-}
-break;
-case PPC_INTERRUPT_HDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
-break;
 case PPC_INTERRUPT_PERFM:
 env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
 powerpc_excp(cpu, POWERPC_EXCP_PERFM);
 break;
-case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-powerpc_excp(cpu, POWERPC_EXCP_THERM);
-break;
 case PPC_INTERRUPT_EBB: /* EBB exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
 if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-- 
2.25.1




[RFC PATCH v2 22/29] target/ppc: remove unused interrupts from p7_deliver_interrupt

2022-09-27 Thread Matheus Ferst
Remove the following unused interrupts from the POWER7 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Hypervisor Doorbell and Event-Based Branch: introduced in
  Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Doorbell and Critical Doorbell Interrupt: processor does not implement
  the "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 50 
 1 file changed, 50 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f32472fb43..de6972d002 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2046,10 +2046,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 CPUState *cs = env_cpu(env);
 
 switch (interrupt) {
-case PPC_INTERRUPT_RESET: /* External reset */
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-break;
 case PPC_INTERRUPT_MCK: /* Machine check exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
 powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
@@ -2066,9 +2062,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
 powerpc_excp(cpu, POWERPC_EXCP_HDECR);
 break;
-case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-break;
 
 case PPC_INTERRUPT_EXT:
 if (books_vhyp_promotes_external_to_hvirt(cpu)) {
@@ -2077,60 +2070,17 @@ static void p7_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
 }
 break;
-case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-break;
 
-case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-break;
-case PPC_INTERRUPT_CDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-break;
-case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-break;
-case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-break;
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
 if (ppc_decr_clear_on_delivery(env)) {
 env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
 }
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
-case PPC_INTERRUPT_DOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-if (is_book3s_arch2x(env)) {
-powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-} else {
-powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-}
-break;
-case PPC_INTERRUPT_HDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
-break;
 case PPC_INTERRUPT_PERFM:
 env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
 powerpc_excp(cpu, POWERPC_EXCP_PERFM);
 break;
-case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-powerpc_excp(cpu, POWERPC_EXCP_THERM);
-break;
-case PPC_INTERRUPT_EBB: /* EBB exception */
-env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
-if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
-} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
-powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
-}
-break;
 case 0:
 /*
  * This is a bug ! It means that has_work took us out of halt without
-- 
2.25.1




[RFC PATCH v2 20/29] target/ppc: remove unused interrupts from p7_pending_interrupt

2022-09-27 Thread Matheus Ferst
Remove the following unused interrupts from the POWER7 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Hypervisor Doorbell and Event-Based Branch: introduced in
  Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Doorbell and Critical Doorbell Interrupt: processor does not implement
  the "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst 
---
v2:
  - Remove CDOORBELL and THERM interrupts (farosas);
  - Also remove RESET, DOORBELL, and HDOORBELL interrupts;
  - Assert for the removed interrupts.
---
 target/ppc/excp_helper.c | 63 +---
 1 file changed, 8 insertions(+), 55 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 8e1e18317d..d8522d0b17 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,14 +1679,18 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P7_UNUSED_INTERRUPTS \
+(PPC_INTERRUPT_RESET | PPC_INTERRUPT_HVIRT | PPC_INTERRUPT_CEXT |   \
+ PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |  \
+ PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \
+ PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB)
+
 static int p7_next_unmasked_interrupt(CPUPPCState *env)
 {
 bool async_deliver;
 
-/* External reset */
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
+assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0);
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
@@ -1716,15 +1720,6 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
 }
 }
 
-/* Hypervisor virtualization interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
-/* LPCR will be clear when not supported so this will work */
-bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-return PPC_INTERRUPT_HVIRT;
-}
-}
-
 /* External interrupt can ignore MSR:EE under some circumstances */
 if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
@@ -1736,56 +1731,14 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-return PPC_INTERRUPT_CDOORBELL;
-}
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
 }
-if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
-return PPC_INTERRUPT_DOORBELL;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
-return PPC_INTERRUPT_HDOORBELL;
-}
 if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
 return PPC_INTERRUPT_PERFM;
 }
-/* Thermal interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-return PPC_INTERRUPT_THERM;
-}
-/* EBB exception */
-if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
-/*
- * EBB exception must be taken in problem state and
- * with BESCR_GE set.
- */
-if (FIELD_EX64(env->msr, MSR, PR) &&
-(env->spr[SPR_BESCR] & BESCR_GE)) {
-return PPC_INTERRUPT_EBB;
-}
-}
 }
 
 return 0;
-- 
2.25.1




[RFC PATCH v2 12/29] target/ppc: create an interrupt masking method for POWER8

2022-09-27 Thread Matheus Ferst
The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.

Signed-off-by: Matheus Ferst 
---
v2:
  - Renamed the method from ppc_pending_interrupt_p8 to
p8_next_unmasked_interrupt
  - Processor-specific stuff were moved to the following patches to ease
review.
---
 target/ppc/excp_helper.c | 114 +++
 1 file changed, 114 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 5a0d2c11a2..f60d9826d8 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,6 +1679,118 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+static int p8_next_unmasked_interrupt(CPUPPCState *env)
+{
+bool async_deliver;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+#if 0 /* TODO */
+/* External debug exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+return PPC_INTERRUPT_DEBUG;
+}
+#endif
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)) {
+/* External critical interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+return PPC_INTERRUPT_CEXT;
+}
+}
+if (async_deliver != 0) {
+/* Watchdog timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+return PPC_INTERRUPT_WDT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+return PPC_INTERRUPT_CDOORBELL;
+}
+/* Fixed interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+return PPC_INTERRUPT_FIT;
+}
+/* Programmable interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+return PPC_INTERRUPT_PIT;
+}
+/* Decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+return PPC_INTERRUPT_DECR;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+return PPC_INTERRUPT_PERFM;
+}
+/* Thermal interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+return PPC_INTERRUPT_THERM;
+}
+/* EBB exception */
+if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+/*
+ * EBB exception must be taken in problem state and
+ * with BESCR_GE set.
+ */
+if (FIELD_EX64(env->msr, MSR, PR) &&
+(env->spr[SPR_BESCR] & BESCR_GE)) {
+ 

[RFC PATCH v2 21/29] target/ppc: create an interrupt delivery method for POWER7

2022-09-27 Thread Matheus Ferst
The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches. No functional
change intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 113 +++
 1 file changed, 113 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index d8522d0b17..f32472fb43 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2040,6 +2040,116 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 }
 
 #if defined(TARGET_PPC64)
+static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = env_cpu(env);
+
+switch (interrupt) {
+case PPC_INTERRUPT_RESET: /* External reset */
+env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+powerpc_excp(cpu, POWERPC_EXCP_RESET);
+break;
+case PPC_INTERRUPT_MCK: /* Machine check exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+break;
+#if 0 /* TODO */
+case PPC_INTERRUPT_DEBUG: /* External debug exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+break;
+#endif
+
+case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+/* HDEC clears on delivery */
+env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+break;
+case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+break;
+
+case PPC_INTERRUPT_EXT:
+if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+}
+break;
+case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+break;
+
+case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+powerpc_excp(cpu, POWERPC_EXCP_WDT);
+break;
+case PPC_INTERRUPT_CDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+break;
+case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+powerpc_excp(cpu, POWERPC_EXCP_FIT);
+break;
+case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
+env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+powerpc_excp(cpu, POWERPC_EXCP_PIT);
+break;
+case PPC_INTERRUPT_DECR: /* Decrementer exception */
+if (ppc_decr_clear_on_delivery(env)) {
+env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+}
+powerpc_excp(cpu, POWERPC_EXCP_DECR);
+break;
+case PPC_INTERRUPT_DOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+if (is_book3s_arch2x(env)) {
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+}
+break;
+case PPC_INTERRUPT_HDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+break;
+case PPC_INTERRUPT_PERFM:
+env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+break;
+case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+powerpc_excp(cpu, POWERPC_EXCP_THERM);
+break;
+case PPC_INTERRUPT_EBB: /* EBB exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+}
+break;
+case 0:
+/*
+ * This is a bug ! It means that has_work took us out of halt without
+ * anything to deliver while in a PM state that requires getting
+ * out via a 0x100
+ *
+ * This means we will incorrectly execute past the power management
+ * instruction instead of triggering a reset.
+ *
+ * It generally means a discrepancy between the wakeup conditions in 
the
+ * processor has_work implementation and the logic in this function.
+ */
+assert(env->resume_as_sreset != 0);
+break;
+default:
+cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
+}
+

[RFC PATCH v2 14/29] target/ppc: create an interrupt delivery method for POWER8

2022-09-27 Thread Matheus Ferst
The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches. No functional
change intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 113 +++
 1 file changed, 113 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 6ab03b2e12..0405fc8eee 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1973,6 +1973,116 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 }
 
 #if defined(TARGET_PPC64)
+static void p8_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = env_cpu(env);
+
+switch (interrupt) {
+case PPC_INTERRUPT_RESET: /* External reset */
+env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+powerpc_excp(cpu, POWERPC_EXCP_RESET);
+break;
+case PPC_INTERRUPT_MCK: /* Machine check exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+break;
+#if 0 /* TODO */
+case PPC_INTERRUPT_DEBUG: /* External debug exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+break;
+#endif
+
+case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+/* HDEC clears on delivery */
+env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+break;
+case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+break;
+
+case PPC_INTERRUPT_EXT:
+if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+}
+break;
+case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+break;
+
+case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+powerpc_excp(cpu, POWERPC_EXCP_WDT);
+break;
+case PPC_INTERRUPT_CDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+break;
+case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+powerpc_excp(cpu, POWERPC_EXCP_FIT);
+break;
+case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
+env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+powerpc_excp(cpu, POWERPC_EXCP_PIT);
+break;
+case PPC_INTERRUPT_DECR: /* Decrementer exception */
+if (ppc_decr_clear_on_delivery(env)) {
+env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+}
+powerpc_excp(cpu, POWERPC_EXCP_DECR);
+break;
+case PPC_INTERRUPT_DOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+if (is_book3s_arch2x(env)) {
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+}
+break;
+case PPC_INTERRUPT_HDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+break;
+case PPC_INTERRUPT_PERFM:
+env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+break;
+case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+powerpc_excp(cpu, POWERPC_EXCP_THERM);
+break;
+case PPC_INTERRUPT_EBB: /* EBB exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+}
+break;
+case 0:
+/*
+ * This is a bug ! It means that has_work took us out of halt without
+ * anything to deliver while in a PM state that requires getting
+ * out via a 0x100
+ *
+ * This means we will incorrectly execute past the power management
+ * instruction instead of triggering a reset.
+ *
+ * It generally means a discrepancy between the wakeup conditions in 
the
+ * processor has_work implementation and the logic in this function.
+ */
+assert(env->resume_as_sreset != 0);
+break;
+default:
+cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt);
+}
+

[RFC PATCH v2 11/29] target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt

2022-09-27 Thread Matheus Ferst
Export p9_interrupt_powersave and use it in p9_next_unmasked_interrupt.

Signed-off-by: Matheus Ferst 
---
Temporarily putting the prototype in internal.h for lack of a better place,
we will un-export p9_interrupt_powersave in future patches.
---
 target/ppc/cpu_init.c|  2 +-
 target/ppc/excp_helper.c | 46 
 target/ppc/internal.h|  4 
 3 files changed, 38 insertions(+), 14 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 1f8f6c6ef2..7889158c52 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6351,7 +6351,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
-static int p9_interrupt_powersave(CPUPPCState *env)
+int p9_interrupt_powersave(CPUPPCState *env)
 {
 /* External Exception */
 if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 67e73f30ab..5a0d2c11a2 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1686,28 +1686,39 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 
 static int p9_next_unmasked_interrupt(CPUPPCState *env)
 {
-bool async_deliver;
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = CPU(cpu);
+/* Ignore MSR[EE] when coming out of some power management states */
+bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
 
 assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
 
+if (cs->halted) {
+if (env->spr[SPR_PSSCR] & PSSCR_EC) {
+/*
+ * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can
+ * wakeup the processor
+ */
+return p9_interrupt_powersave(env);
+} else {
+/*
+ * When it's clear, any system-caused exception exits power-saving
+ * mode, even the ones that gate on MSR[EE].
+ */
+msr_ee = true;
+}
+}
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
 }
 
-/*
- * For interrupts that gate on MSR:EE, we need to do something a
- * bit more subtle, as we need to let them through even when EE is
- * clear when coming out of some power management states (in order
- * for them to become a 0x100).
- */
-async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
-
 /* Hypervisor decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
 /* LPCR will be clear when not supported so this will work */
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
 return PPC_INTERRUPT_HDECR;
 }
@@ -1717,7 +1728,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
 if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
 /* LPCR will be clear when not supported so this will work */
 bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) {
 return PPC_INTERRUPT_HVIRT;
 }
 }
@@ -1727,13 +1738,13 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
 bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
 /* HEIC blocks delivery to the hypervisor */
-if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
 return PPC_INTERRUPT_EXT;
 }
 }
-if (async_deliver != 0) {
+if (msr_ee != 0) {
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
@@ -1895,6 +1906,15 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 PowerPCCPU *cpu = env_archcpu(env);
 CPUState *cs = env_cpu(env);
 
+if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) &&
+!FIELD_EX64(env->msr, MSR, EE)) {
+/*
+ * A pending interrupt took us out of power-saving, but MSR[EE] says
+ * that we should return to NIP+4 instead of delivering it.
+ */
+return;
+}
+
 switch (interrupt) {
 case PPC_INTERRUPT_MCK: /* Machine check exception */
 env->pend

[RFC PATCH v2 16/29] target/ppc: remove generic architecture checks from p8_deliver_interrupt

2022-09-27 Thread Matheus Ferst
No functional change intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 4cbf6b29fc..2e8d4699a9 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1999,9 +1999,6 @@ static void p8_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 break;
 
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
-if (ppc_decr_clear_on_delivery(env)) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-}
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
 case PPC_INTERRUPT_PERFM:
-- 
2.25.1




[RFC PATCH v2 07/29] target/ppc: create an interrupt delivery method for POWER9/POWER10

2022-09-27 Thread Matheus Ferst
The new method is identical to ppc_deliver_interrupt, processor-specific
code will be added/removed in the following patches. No functional
change intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 118 +++
 1 file changed, 118 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index af2cab01a7..8a32acbc7f 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1889,6 +1889,118 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 }
 }
 
+#if defined(TARGET_PPC64)
+static void p9_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+PowerPCCPU *cpu = env_archcpu(env);
+CPUState *cs = env_cpu(env);
+
+switch (interrupt) {
+case PPC_INTERRUPT_RESET: /* External reset */
+env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
+powerpc_excp(cpu, POWERPC_EXCP_RESET);
+break;
+case PPC_INTERRUPT_MCK: /* Machine check exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
+powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
+break;
+#if 0 /* TODO */
+case PPC_INTERRUPT_DEBUG: /* External debug exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
+powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
+break;
+#endif
+
+case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
+/* HDEC clears on delivery */
+env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
+powerpc_excp(cpu, POWERPC_EXCP_HDECR);
+break;
+case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+break;
+
+case PPC_INTERRUPT_EXT:
+if (books_vhyp_promotes_external_to_hvirt(cpu)) {
+powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
+}
+break;
+case PPC_INTERRUPT_CEXT: /* External critical interrupt */
+powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
+break;
+
+case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
+powerpc_excp(cpu, POWERPC_EXCP_WDT);
+break;
+case PPC_INTERRUPT_CDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
+break;
+case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
+env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
+powerpc_excp(cpu, POWERPC_EXCP_FIT);
+break;
+case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
+env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
+powerpc_excp(cpu, POWERPC_EXCP_PIT);
+break;
+case PPC_INTERRUPT_DECR: /* Decrementer exception */
+if (ppc_decr_clear_on_delivery(env)) {
+env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
+}
+powerpc_excp(cpu, POWERPC_EXCP_DECR);
+break;
+case PPC_INTERRUPT_DOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+if (is_book3s_arch2x(env)) {
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
+} else {
+powerpc_excp(cpu, POWERPC_EXCP_DOORI);
+}
+break;
+case PPC_INTERRUPT_HDOORBELL:
+env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
+break;
+case PPC_INTERRUPT_PERFM:
+env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
+powerpc_excp(cpu, POWERPC_EXCP_PERFM);
+break;
+case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
+env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
+powerpc_excp(cpu, POWERPC_EXCP_THERM);
+break;
+case PPC_INTERRUPT_EBB: /* EBB exception */
+env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
+if (env->spr[SPR_BESCR] & BESCR_PMEO) {
+powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB);
+} else if (env->spr[SPR_BESCR] & BESCR_EEO) {
+powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB);
+}
+break;
+case 0:
+/*
+ * This is a bug ! It means that has_work took us out of halt without
+ * anything to deliver while in a PM state that requires getting
+ * out via a 0x100
+ *
+ * This means we will incorrectly execute past the power management
+ * instruction instead of triggering a reset.
+ *
+ * It generally means a discrepancy between the wakeup conditions in 
the
+ * processor has_work implementation and the logic in this function.
+ */
+assert(env->resume_as_sreset != 0);
+break;
+default:
+cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interr

[RFC PATCH v2 09/29] target/ppc: remove generic architecture checks from p9_deliver_interrupt

2022-09-27 Thread Matheus Ferst
No functional change intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 9 +
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 603c956588..67e73f30ab 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1919,18 +1919,11 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 break;
 
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
-if (ppc_decr_clear_on_delivery(env)) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-}
 powerpc_excp(cpu, POWERPC_EXCP_DECR);
 break;
 case PPC_INTERRUPT_DOORBELL:
 env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-if (is_book3s_arch2x(env)) {
-powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
-} else {
-powerpc_excp(cpu, POWERPC_EXCP_DOORI);
-}
+powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
 break;
 case PPC_INTERRUPT_HDOORBELL:
 env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
-- 
2.25.1




[RFC PATCH v2 17/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8

2022-09-27 Thread Matheus Ferst
Move the interrupt masking logic out of cpu_has_work_POWER8 in a new
method, p8_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode. No functional change
intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 61 +++
 1 file changed, 33 insertions(+), 28 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 7889158c52..59e4c325c5 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6133,6 +6133,38 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return true;
 }
 
+static int p8_interrupt_powersave(CPUPPCState *env)
+{
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
+return PPC_INTERRUPT_EXT;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
+return PPC_INTERRUPT_DECR;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+return PPC_INTERRUPT_MCK;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+return PPC_INTERRUPT_HMI;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+return 0;
+}
+
 static bool cpu_has_work_POWER8(CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -6142,34 +6174,7 @@ static bool cpu_has_work_POWER8(CPUState *cs)
 if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
 return false;
 }
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
-return true;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return true;
-}
-return false;
+return p8_interrupt_powersave(env) != 0;
 } else {
 return FIELD_EX64(env->msr, MSR, EE) &&
(cs->interrupt_request & CPU_INTERRUPT_HARD);
-- 
2.25.1




[RFC PATCH v2 13/29] target/ppc: remove unused interrupts from p8_pending_interrupt

2022-09-27 Thread Matheus Ferst
Remove the following unused interrupts from the POWER8 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Hypervisor Virtualization: introduced in Power ISA v3.0;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Hypervisor Doorbell, Doorbell, and Critical Doorbell: processor does
  not implement the "Embedded.Processor Control" category;
- Programmable Interval Timer: 40x-only;
- PPC_INTERRUPT_THERM: only raised for 970 and POWER5p;

Signed-off-by: Matheus Ferst 
---
v2:
  - Remove CDOORBELL and THERM interrupts (farosas);
  - Also remove RESET, DEBUG, DOORBELL, and HDOORBELL interrupts;
  - Assert for the removed interrupts.
---
 target/ppc/excp_helper.c | 58 ++--
 1 file changed, 8 insertions(+), 50 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f60d9826d8..6ab03b2e12 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,24 +1679,22 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P8_UNUSED_INTERRUPTS \
+(PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_HVIRT |  \
+PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL |  \
+PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL |\
+PPC_INTERRUPT_HDOORBELL | PPC_INTERRUPT_THERM)
+
 static int p8_next_unmasked_interrupt(CPUPPCState *env)
 {
 bool async_deliver;
 
-/* External reset */
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
+assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0);
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
 }
-#if 0 /* TODO */
-/* External debug exception */
-if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-return PPC_INTERRUPT_DEBUG;
-}
-#endif
 
 /*
  * For interrupts that gate on MSR:EE, we need to do something a
@@ -1716,15 +1714,6 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
 }
 }
 
-/* Hypervisor virtualization interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
-/* LPCR will be clear when not supported so this will work */
-bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-return PPC_INTERRUPT_HVIRT;
-}
-}
-
 /* External interrupt can ignore MSR:EE under some circumstances */
 if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
@@ -1736,45 +1725,14 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-return PPC_INTERRUPT_CDOORBELL;
-}
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
 }
-if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
-return PPC_INTERRUPT_DOORBELL;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
-return PPC_INTERRUPT_HDOORBELL;
-}
 if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
 return PPC_INTERRUPT_PERFM;
 }
-/* Thermal interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-return PPC_INTERRUPT_THERM;
-}
 /* EBB exception */
 if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
 /*
-- 
2.25.1




[RFC PATCH v2 08/29] target/ppc: remove unused interrupts from p9_deliver_interrupt

2022-09-27 Thread Matheus Ferst
Remove the following unused interrupts from the POWER9 interrupt
processing method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Critical Doorbell Interrupt: removed in Power ISA v3.0;
- Programmable Interval Timer: 40x-only.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 33 -
 1 file changed, 33 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 8a32acbc7f..603c956588 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1896,20 +1896,10 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 CPUState *cs = env_cpu(env);
 
 switch (interrupt) {
-case PPC_INTERRUPT_RESET: /* External reset */
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-break;
 case PPC_INTERRUPT_MCK: /* Machine check exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
 powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
 break;
-#if 0 /* TODO */
-case PPC_INTERRUPT_DEBUG: /* External debug exception */
-env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-break;
-#endif
 
 case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */
 /* HDEC clears on delivery */
@@ -1927,26 +1917,7 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
 }
 break;
-case PPC_INTERRUPT_CEXT: /* External critical interrupt */
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-break;
 
-case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-break;
-case PPC_INTERRUPT_CDOORBELL:
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-break;
-case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-break;
-case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded PowerPC 
*/
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-break;
 case PPC_INTERRUPT_DECR: /* Decrementer exception */
 if (ppc_decr_clear_on_delivery(env)) {
 env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
@@ -1969,10 +1940,6 @@ static void p9_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 env->pending_interrupts &= ~PPC_INTERRUPT_PERFM;
 powerpc_excp(cpu, POWERPC_EXCP_PERFM);
 break;
-case PPC_INTERRUPT_THERM:  /* Thermal interrupt */
-env->pending_interrupts &= ~PPC_INTERRUPT_THERM;
-powerpc_excp(cpu, POWERPC_EXCP_THERM);
-break;
 case PPC_INTERRUPT_EBB: /* EBB exception */
 env->pending_interrupts &= ~PPC_INTERRUPT_EBB;
 if (env->spr[SPR_BESCR] & BESCR_PMEO) {
-- 
2.25.1




[RFC PATCH v2 28/29] target/ppc: unify cpu->has_work based on cs->interrupt_request

2022-09-27 Thread Matheus Ferst
Now that cs->interrupt_request indicates if there is any unmasked
interrupt, checking if the CPU has work to do can be simplified to a
single check that works for all CPU models.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 94 +--
 1 file changed, 1 insertion(+), 93 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 26686d1557..4d0064c7a5 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5984,27 +5984,10 @@ int p7_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER7(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-return p7_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER7";
 dc->desc = "POWER7";
@@ -6013,7 +5996,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER7;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER7;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6170,27 +6152,10 @@ int p8_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER8(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-return p8_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER8";
 dc->desc = "POWER8";
@@ -6199,7 +6164,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER8;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER8;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6407,35 +6371,10 @@ int p9_interrupt_powersave(CPUPPCState *env)
 return 0;
 }
 
-static bool cpu_has_work_POWER9(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-uint64_t psscr = env->spr[SPR_PSSCR];
-
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-
-/* If EC is clear, just return true on any pending interrupt */
-if (!(psscr & PSSCR_EC)) {
-return true;
-}
-
-return p9_interrupt_powersave(env) != 0;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER9";
 dc->desc = "POWER9";
@@ -6445,7 +6384,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
  PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER9;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER9;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6604,35 +6542,10 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
-static bool cpu_has_work_POWER10(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-uint64_t psscr = env->spr[SPR_PSSCR];
-
-if (!(cs->interrupt_r

[RFC PATCH v2 06/29] target/ppc: remove unused interrupts from p9_pending_interrupt

2022-09-27 Thread Matheus Ferst
Remove the following unused interrupts from the POWER9 interrupt masking
method:
- PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p;
- Debug Interrupt: removed in Power ISA v2.07;
- Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined
  for embedded CPUs;
- Critical Doorbell Interrupt: removed in Power ISA v3.0;
- Programmable Interval Timer: 40x-only.

Signed-off-by: Matheus Ferst 
---
v2:
  - Remove CDOORBELL and THERM (farosas);
  - Also remove RESET and DEBUG, interrupts;
  - Assert for the removed interrupts.
---
 target/ppc/excp_helper.c | 42 +++-
 1 file changed, 7 insertions(+), 35 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f2b0845735..af2cab01a7 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1679,24 +1679,21 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 }
 
 #if defined(TARGET_PPC64)
+#define P9_UNUSED_INTERRUPTS \
+(PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_CEXT |   \
+ PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT |  \
+ PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM)
+
 static int p9_next_unmasked_interrupt(CPUPPCState *env)
 {
 bool async_deliver;
 
-/* External reset */
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return PPC_INTERRUPT_RESET;
-}
+assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0);
+
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
 return PPC_INTERRUPT_MCK;
 }
-#if 0 /* TODO */
-/* External debug exception */
-if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-return PPC_INTERRUPT_DEBUG;
-}
-#endif
 
 /*
  * For interrupts that gate on MSR:EE, we need to do something a
@@ -1736,28 +1733,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-return PPC_INTERRUPT_CDOORBELL;
-}
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
@@ -1771,10 +1747,6 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env)
 if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
 return PPC_INTERRUPT_PERFM;
 }
-/* Thermal interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
-return PPC_INTERRUPT_THERM;
-}
 /* EBB exception */
 if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
 /*
-- 
2.25.1




[RFC PATCH v2 10/29] target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9

2022-09-27 Thread Matheus Ferst
Move the interrupt masking logic out of cpu_has_work_POWER9 in a new
method, p9_interrupt_powersave, that only returns an interrupt if it can
wake the processor from power-saving mode. No functional change
intended.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 126 +-
 1 file changed, 50 insertions(+), 76 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 4b4b3feac9..1f8f6c6ef2 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -6351,6 +6351,52 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, 
uint32_t pvr, bool best)
 return false;
 }
 
+static int p9_interrupt_powersave(CPUPPCState *env)
+{
+/* External Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_EEE)) {
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+if (!heic || !FIELD_EX64_HV(env->msr) ||
+FIELD_EX64(env->msr, MSR, PR)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+/* Decrementer Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_DEE)) {
+return PPC_INTERRUPT_DECR;
+}
+/* Machine Check or Hypervisor Maintenance Exception */
+if (env->spr[SPR_LPCR] & LPCR_OEE) {
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
+return PPC_INTERRUPT_HMI;
+}
+}
+/* Privileged Doorbell Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_PDEE)) {
+return PPC_INTERRUPT_DOORBELL;
+}
+/* Hypervisor Doorbell Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_HDEE)) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+/* Hypervisor virtualization exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
+(env->spr[SPR_LPCR] & LPCR_HVEE)) {
+return PPC_INTERRUPT_HVIRT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+return 0;
+}
+
 static bool cpu_has_work_POWER9(CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -6367,44 +6413,8 @@ static bool cpu_has_work_POWER9(CPUState *cs)
 if (!(psscr & PSSCR_EC)) {
 return true;
 }
-/* External Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_EEE)) {
-bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-if (!heic || !FIELD_EX64_HV(env->msr) ||
-FIELD_EX64(env->msr, MSR, PR)) {
-return true;
-}
-}
-/* Decrementer Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_DEE)) {
-return true;
-}
-/* Machine Check or Hypervisor Maintenance Exception */
-if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI))
-&& (env->spr[SPR_LPCR] & LPCR_OEE)) {
-return true;
-}
-/* Privileged Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_PDEE)) {
-return true;
-}
-/* Hypervisor Doorbell Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_HDEE)) {
-return true;
-}
-/* Hypervisor virtualization exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
-(env->spr[SPR_LPCR] & LPCR_HVEE)) {
-return true;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return true;
-}
-return false;
+
+return p9_interrupt_powersave(env) != 0;
 } else {
 return FIELD_EX64(env->msr, MSR, EE) &&
(cs->interrupt_request & CPU_INTERRUPT_HARD);
@@ -6600,44 +6610,8 @@ static bool cpu_has_work_POWER10(CPUState *cs)
 if (!(psscr & PSSCR_EC)) {
 return true;
 }
-/* External Exception */
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_EEE)) {
-bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
-if (!heic || !FIELD_EX64_HV(env->msr) ||
-FIELD_EX64(env-

[RFC PATCH v2 03/29] target/ppc: split interrupt masking and delivery from ppc_hw_interrupt

2022-09-27 Thread Matheus Ferst
Split ppc_hw_interrupt into an interrupt masking method,
ppc_next_unmasked_interrupt, and an interrupt processing method,
ppc_deliver_interrupt.

Signed-off-by: Matheus Ferst 
---
v2:
  - ppc_hw_interrupt renamed as ppc_deliver_interrupt (farosas);
  - Handle the "Wakeup from PM state but interrupt Undelivered" case
as an assert in ppc_deliver_interrupt (farosas).
---
 target/ppc/excp_helper.c | 207 +--
 1 file changed, 131 insertions(+), 76 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index c3c30c5d1b..c6381489b6 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,29 +1678,22 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
-static void ppc_hw_interrupt(CPUPPCState *env)
+static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 {
-PowerPCCPU *cpu = env_archcpu(env);
 bool async_deliver;
 
 /* External reset */
 if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-return;
+return PPC_INTERRUPT_RESET;
 }
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
-env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
-powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
-return;
+return PPC_INTERRUPT_MCK;
 }
 #if 0 /* TODO */
 /* External debug exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-return;
+return PPC_INTERRUPT_DEBUG;
 }
 #endif
 
@@ -1718,9 +1711,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
 if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
-env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
-powerpc_excp(cpu, POWERPC_EXCP_HDECR);
-return;
+return PPC_INTERRUPT_HDECR;
 }
 }
 
@@ -1729,8 +1720,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 || !FIELD_EX64_HV(env->msr)) && hvice) {
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-return;
+return PPC_INTERRUPT_HVIRT;
 }
 }
 
@@ -1742,77 +1732,47 @@ static void ppc_hw_interrupt(CPUPPCState *env)
 if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
-if (books_vhyp_promotes_external_to_hvirt(cpu)) {
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-} else {
-powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
-}
-return;
+return PPC_INTERRUPT_EXT;
 }
 }
 if (FIELD_EX64(env->msr, MSR, CE)) {
 /* External critical interrupt */
 if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-return;
+return PPC_INTERRUPT_CEXT;
 }
 }
 if (async_deliver != 0) {
 /* Watchdog timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-return;
+return PPC_INTERRUPT_WDT;
 }
 if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-return;
+return PPC_INTERRUPT_CDOORBELL;
 }
 /* Fixed interval timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-return;
+return PPC_INTERRUPT_FIT;
 }
 /* Programmable interval timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-return;
+return PPC_INTERRUPT_PIT;
 }
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
-if (ppc_decr_clear_on_delivery(env)) {
-   

[RFC PATCH v2 05/29] target/ppc: create an interrupt masking method for POWER9/POWER10

2022-09-27 Thread Matheus Ferst
The new method is identical to ppc_next_unmasked_interrupt_generic,
processor-specific code will be added/removed in the following patches.
No functional change intended.

Signed-off-by: Matheus Ferst 
---
v2:
  - Renamed the method from ppc_pending_interrupt_p9 to
p9_next_unmasked_interrupt
  - Processor-specific stuff were moved to the following patches to ease
review.
---
 target/ppc/excp_helper.c | 119 +++
 1 file changed, 119 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 6da4dba616..f2b0845735 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,6 +1678,120 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
+#if defined(TARGET_PPC64)
+static int p9_next_unmasked_interrupt(CPUPPCState *env)
+{
+bool async_deliver;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+#if 0 /* TODO */
+/* External debug exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
+return PPC_INTERRUPT_DEBUG;
+}
+#endif
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)) {
+/* External critical interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+return PPC_INTERRUPT_CEXT;
+}
+}
+if (async_deliver != 0) {
+/* Watchdog timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+return PPC_INTERRUPT_WDT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+return PPC_INTERRUPT_CDOORBELL;
+}
+/* Fixed interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+return PPC_INTERRUPT_FIT;
+}
+/* Programmable interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+return PPC_INTERRUPT_PIT;
+}
+/* Decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+return PPC_INTERRUPT_DECR;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+return PPC_INTERRUPT_PERFM;
+}
+/* Thermal interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
+return PPC_INTERRUPT_THERM;
+}
+/* EBB exception */
+if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
+/*
+ * EBB exception must be taken in problem state and
+ * with BESCR_GE set.
+ */
+if (FIELD_EX64(env->msr, MSR, PR) &

[RFC PATCH v2 04/29] target/ppc: prepare to split interrupt masking and delivery by excp_model

2022-09-27 Thread Matheus Ferst
No functional change intended.

Signed-off-by: Matheus Ferst 
---
v2:
  - Use "generic" instead of "legacy" to name the original methods (farosas).
---
 target/ppc/excp_helper.c | 20 ++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index c6381489b6..6da4dba616 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,7 +1678,7 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
-static int ppc_next_unmasked_interrupt(CPUPPCState *env)
+static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env)
 {
 bool async_deliver;
 
@@ -1790,7 +1790,15 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
 return 0;
 }
 
-static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
+static int ppc_next_unmasked_interrupt(CPUPPCState *env)
+{
+switch (env->excp_model) {
+default:
+return ppc_next_unmasked_interrupt_generic(env);
+}
+}
+
+static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt)
 {
 PowerPCCPU *cpu = env_archcpu(env);
 CPUState *cs = env_cpu(env);
@@ -1900,6 +1908,14 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int 
interrupt)
 }
 }
 
+static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt)
+{
+switch (env->excp_model) {
+default:
+ppc_deliver_interrupt_generic(env, interrupt);
+}
+}
+
 void ppc_cpu_do_system_reset(CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
-- 
2.25.1




[RFC PATCH v2 02/29] target/ppc: always use ppc_set_irq to set env->pending_interrupts

2022-09-27 Thread Matheus Ferst
Use ppc_set_irq to raise/clear interrupts to ensure CPU_INTERRUPT_HARD
will be set/reset accordingly.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 17 +++--
 target/ppc/misc_helper.c |  9 ++---
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 3f8ff9bcf3..c3c30c5d1b 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -23,6 +23,7 @@
 #include "exec/exec-all.h"
 #include "internal.h"
 #include "helper_regs.h"
+#include "hw/ppc/ppc.h"
 
 #include "trace.h"
 
@@ -2080,7 +2081,6 @@ void helper_rfebb(CPUPPCState *env, target_ulong s)
 static void do_ebb(CPUPPCState *env, int ebb_excp)
 {
 PowerPCCPU *cpu = env_archcpu(env);
-CPUState *cs = CPU(cpu);
 
 /*
  * FSCR_EBB and FSCR_IC_EBB are the same bits used with
@@ -2098,8 +2098,7 @@ static void do_ebb(CPUPPCState *env, int ebb_excp)
 if (FIELD_EX64(env->msr, MSR, PR)) {
 powerpc_excp(cpu, ebb_excp);
 } else {
-env->pending_interrupts |= PPC_INTERRUPT_EBB;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, PPC_INTERRUPT_EBB, 1);
 }
 }
 
@@ -2292,7 +2291,7 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb)
 return;
 }
 
-env->pending_interrupts &= ~irq;
+ppc_set_irq(env_archcpu(env), irq, 0);
 }
 
 void helper_msgsnd(target_ulong rb)
@@ -2311,8 +2310,7 @@ void helper_msgsnd(target_ulong rb)
 CPUPPCState *cenv = >env;
 
 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
-cenv->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, irq, 1);
 }
 }
 qemu_mutex_unlock_iothread();
@@ -2336,7 +2334,7 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong 
rb)
 return;
 }
 
-env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
 }
 
 static void book3s_msgsnd_common(int pir, int irq)
@@ -2350,8 +2348,7 @@ static void book3s_msgsnd_common(int pir, int irq)
 
 /* TODO: broadcast message to all threads of the same  processor */
 if (cenv->spr_cb[SPR_PIR].default_value == pir) {
-cenv->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, irq, 1);
 }
 }
 qemu_mutex_unlock_iothread();
@@ -2377,7 +2374,7 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong 
rb)
 return;
 }
 
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
 }
 
 /*
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 05e35572bc..a9bc1522e2 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -25,6 +25,7 @@
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
 #include "mmu-book3s-v3.h"
+#include "hw/ppc/ppc.h"
 
 #include "helper_regs.h"
 
@@ -173,7 +174,6 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
 void helper_store_dpdes(CPUPPCState *env, target_ulong val)
 {
 PowerPCCPU *cpu = env_archcpu(env);
-CPUState *cs = CPU(cpu);
 
 helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
 
@@ -184,12 +184,7 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
 return;
 }
 
-if (val & 0x1) {
-env->pending_interrupts |= PPC_INTERRUPT_DOORBELL;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
-} else {
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-}
+ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
 }
 #endif /* defined(TARGET_PPC64) */
 
-- 
2.25.1




[RFC PATCH v2 00/29] PowerPC interrupt rework

2022-09-27 Thread Matheus Ferst
   | 166,91 ± 8,37 | 918,06 ± 114,78 |
|PowerNV patch series | 166,25 ± 8,85 | 916,91 ± 107,56 |
|pSeries master   | 175,70 ± 8,22 | 958,73 ± 115,09 |
|pSeries patch series | 173,62 ± 8,13 | 893,42 ±  87,77 |
+-+---+-+

The scp data shows little difference, while testing just network shows
that it's a bit slower with the patch series applied (although, with
this variation, we'd probably need to repeat this test more times to
have a more robust result...)

[1] https://github.com/legoater/qemu-ppc-boot
[2] https://artifact.ci.freebsd.org/snapshot/14.0-CURRENT/latest_vm/powerpc
[3] https://lists.gnu.org/archive/html/qemu-ppc/2022-06/msg00336.html

Matheus Ferst (29):
  target/ppc: define PPC_INTERRUPT_* values directly
  target/ppc: always use ppc_set_irq to set env->pending_interrupts
  target/ppc: split interrupt masking and delivery from ppc_hw_interrupt
  target/ppc: prepare to split interrupt masking and delivery by excp_model
  target/ppc: create an interrupt masking method for POWER9/POWER10
  target/ppc: remove unused interrupts from p9_pending_interrupt
  target/ppc: create an interrupt deliver method for POWER9/POWER10
  target/ppc: remove unused interrupts from p9_deliver_interrupt
  target/ppc: remove generic architecture checks from p9_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9
  target/ppc: add power-saving interrupt masking logic to 
p9_next_unmasked_interrupt
  target/ppc: create an interrupt masking method for POWER8
  target/ppc: remove unused interrupts from p8_pending_interrupt
  target/ppc: create an interrupt deliver method for POWER8
  target/ppc: remove unused interrupts from p8_deliver_interrupt
  target/ppc: remove generic architecture checks from p8_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8
  target/ppc: add power-saving interrupt masking logic to 
p8_next_unmasked_interrupt
  target/ppc: create an interrupt masking method for POWER7
  target/ppc: remove unused interrupts from p7_pending_interrupt
  target/ppc: create an interrupt deliver method for POWER7
  target/ppc: remove unused interrupts from p7_deliver_interrupt
  target/ppc: remove generic architecture checks from p7_deliver_interrupt
  target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7
  target/ppc: add power-saving interrupt masking logic to 
p7_next_unmasked_interrupt
  target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds
  target/ppc: introduce ppc_maybe_interrupt
  target/ppc: unify cpu->has_work based on cs->interrupt_request
  target/ppc: move the p*_interrupt_powersave methods to excp_helper.c

 hw/ppc/pnv_core.c|   1 +
 hw/ppc/ppc.c |  17 +-
 hw/ppc/spapr_hcall.c |   6 +
 hw/ppc/spapr_rtas.c  |   2 +-
 hw/ppc/trace-events  |   2 +-
 target/ppc/cpu.c |   4 +
 target/ppc/cpu.h |  43 +-
 target/ppc/cpu_init.c| 212 +-
 target/ppc/excp_helper.c | 857 ++-
 target/ppc/helper.h  |   1 +
 target/ppc/helper_regs.c |   2 +
 target/ppc/misc_helper.c |  11 +-
 target/ppc/translate.c   |   2 +
 13 files changed, 803 insertions(+), 357 deletions(-)

-- 
2.25.1




[RFC PATCH v2 01/29] target/ppc: define PPC_INTERRUPT_* values directly

2022-09-27 Thread Matheus Ferst
This enum defines the bit positions in env->pending_interrupts for each
interrupt. However, except for the comparison in kvmppc_set_interrupt,
the values are always used as (1 << PPC_INTERRUPT_*). Define them
directly like that to save some clutter. No functional change intended.

Reviewed-by: David Gibson 
Signed-off-by: Matheus Ferst 
---
 hw/ppc/ppc.c | 10 +++---
 hw/ppc/trace-events  |  2 +-
 target/ppc/cpu.h | 40 +++---
 target/ppc/cpu_init.c| 56 +++---
 target/ppc/excp_helper.c | 74 
 target/ppc/misc_helper.c |  6 ++--
 6 files changed, 94 insertions(+), 94 deletions(-)

diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 690f448cb9..77e611e81c 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -40,7 +40,7 @@
 static void cpu_ppc_tb_stop (CPUPPCState *env);
 static void cpu_ppc_tb_start (CPUPPCState *env);
 
-void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
+void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
 CPUState *cs = CPU(cpu);
 CPUPPCState *env = >env;
@@ -56,21 +56,21 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
 old_pending = env->pending_interrupts;
 
 if (level) {
-env->pending_interrupts |= 1 << n_IRQ;
+env->pending_interrupts |= irq;
 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
-env->pending_interrupts &= ~(1 << n_IRQ);
+env->pending_interrupts &= ~irq;
 if (env->pending_interrupts == 0) {
 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
 }
 
 if (old_pending != env->pending_interrupts) {
-kvmppc_set_interrupt(cpu, n_IRQ, level);
+kvmppc_set_interrupt(cpu, irq, level);
 }
 
 
-trace_ppc_irq_set_exit(env, n_IRQ, level, env->pending_interrupts,
+trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
 
 if (locked) {
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index a07d5aca0f..956938ebcd 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -127,7 +127,7 @@ ppc40x_set_tb_clk(uint32_t value) "new frequency %" PRIu32
 ppc40x_timers_init(uint32_t value) "frequency %" PRIu32
 
 ppc_irq_set(void *env, uint32_t pin, uint32_t level) "env [%p] pin %d level %d"
-ppc_irq_set_exit(void *env, uint32_t n_IRQ, uint32_t level, uint32_t pending, 
uint32_t request) "env [%p] n_IRQ %d level %d => pending 0x%08" PRIx32 " req 
0x%08" PRIx32
+ppc_irq_set_exit(void *env, uint32_t irq, uint32_t level, uint32_t pending, 
uint32_t request) "env [%p] irq 0x%05" PRIx32 " level %d => pending 0x%08" 
PRIx32 " req 0x%08" PRIx32
 ppc_irq_set_state(const char *name, uint32_t level) "\"%s\" level %d"
 ppc_irq_reset(const char *name) "%s"
 ppc_irq_cpu(const char *action) "%s"
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7f73e2ac81..9ccd23db04 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -2416,27 +2416,27 @@ enum {
 /* Hardware exceptions definitions */
 enum {
 /* External hardware exception sources */
-PPC_INTERRUPT_RESET = 0,  /* Reset exception  */
-PPC_INTERRUPT_WAKEUP, /* Wakeup exception */
-PPC_INTERRUPT_MCK,/* Machine check exception  */
-PPC_INTERRUPT_EXT,/* External interrupt   */
-PPC_INTERRUPT_SMI,/* System management interrupt  */
-PPC_INTERRUPT_CEXT,   /* Critical external interrupt  */
-PPC_INTERRUPT_DEBUG,  /* External debug exception */
-PPC_INTERRUPT_THERM,  /* Thermal exception*/
+PPC_INTERRUPT_RESET = 0x1,  /* Reset exception
*/
+PPC_INTERRUPT_WAKEUP= 0x2,  /* Wakeup exception   
*/
+PPC_INTERRUPT_MCK   = 0x4,  /* Machine check exception
*/
+PPC_INTERRUPT_EXT   = 0x8,  /* External interrupt 
*/
+PPC_INTERRUPT_SMI   = 0x00010,  /* System management interrupt
*/
+PPC_INTERRUPT_CEXT  = 0x00020,  /* Critical external interrupt
*/
+PPC_INTERRUPT_DEBUG = 0x00040,  /* External debug exception   
*/
+PPC_INTERRUPT_THERM = 0x00080,  /* Thermal exception  
*/
 /* Internal hardware exception sources */
-PPC_INTERRUPT_DECR,   /* Decrementer exception*/
-PPC_INTERRUPT_HDECR,  /* Hypervisor decrementer exception */
-PPC_INTERRUPT_PIT,/* Programmable interval timer interrupt */
-PPC_INTERRUPT_FIT,/* Fixed interval timer interrupt   */
-PPC_INTERRUPT_WDT, 

[RFC PATCH 11/13] target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds

2022-08-15 Thread Matheus Ferst
Writes to LPCR are hypervisor privileged.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu.c | 2 ++
 target/ppc/cpu.h | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index 401b6f9e63..9f261bde8e 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -73,6 +73,7 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value)
 hreg_store_msr(env, value, 0);
 }
 
+#if !defined(CONFIG_USER_ONLY)
 void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 {
 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
@@ -82,6 +83,7 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
 /* The gtse bit affects hflags */
 hreg_compute_hflags(env);
 }
+#endif
 
 static inline void fpscr_set_rounding_mode(CPUPPCState *env)
 {
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index c7864bb3b1..5018296f02 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1370,9 +1370,9 @@ void ppc_translate_init(void);
 
 #if !defined(CONFIG_USER_ONLY)
 void ppc_store_sdr1(CPUPPCState *env, target_ulong value);
+void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
 #endif /* !defined(CONFIG_USER_ONLY) */
 void ppc_store_msr(CPUPPCState *env, target_ulong value);
-void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
 
 void ppc_cpu_list(void);
 
-- 
2.25.1




[RFC PATCH 13/13] target/ppc: unify cpu->has_work based on cs->interrupt_request

2022-08-15 Thread Matheus Ferst
Now that cs->interrupt_request indicates if there is any unmasked
interrupt, checking if the CPU has work to do can be simplified to a
single check that works for all CPU models.

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu_init.c | 212 +-
 1 file changed, 1 insertion(+), 211 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 850334545a..303e81596d 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5923,46 +5923,10 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, 
uint32_t pvr)
 return false;
 }
 
-static bool cpu_has_work_POWER7(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
-return true;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return true;
-}
-return false;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER7";
 dc->desc = "POWER7";
@@ -5971,7 +5935,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER7;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER7;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6087,54 +6050,10 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, 
uint32_t pvr)
 return false;
 }
 
-static bool cpu_has_work_POWER8(CPUState *cs)
-{
-PowerPCCPU *cpu = POWERPC_CPU(cs);
-CPUPPCState *env = >env;
-
-if (cs->halted) {
-if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
-return false;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
-return true;
-}
-if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
-(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
-return true;
-}
-if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-return true;
-}
-return false;
-} else {
-return FIELD_EX64(env->msr, MSR, EE) &&
-   (cs->interrupt_request & CPU_INTERRUPT_HARD);
-}
-}
-
 POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-CPUClass *cc = CPU_CLASS(oc);
 
 dc->fw_name = "PowerPC,POWER8";
 dc->desc = "POWER8";
@@ -6143,7 +6062,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
 pcc->init_proc = init_proc_POWER8;
 pcc->check_pow = check_pow_nocheck;
-cc->has_work = cpu_has_work_POWER8;
 pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | P

[RFC PATCH 12/13] target/ppc: introduce ppc_maybe_interrupt

2022-08-15 Thread Matheus Ferst
This new method will check if any pending interrupt was unmasked and
then call cpu_interrupt/cpu_reset_interrupt accordingly. Code that
raises/lowers or masks/unmasks interrupts should call this method to
keep CPU_INTERRUPT_HARD coherent with env->pending_interrupts.

Signed-off-by: Matheus Ferst 
---
 hw/ppc/ppc.c |  7 +--
 target/ppc/cpu.h |  1 +
 target/ppc/excp_helper.c | 19 +++
 target/ppc/helper_regs.c |  2 ++
 target/ppc/translate.c   |  8 ++--
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 77e611e81c..dc86c1c7db 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -42,7 +42,6 @@ static void cpu_ppc_tb_start (CPUPPCState *env);
 
 void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
-CPUState *cs = CPU(cpu);
 CPUPPCState *env = >env;
 unsigned int old_pending;
 bool locked = false;
@@ -57,19 +56,15 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 
 if (level) {
 env->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 env->pending_interrupts &= ~irq;
-if (env->pending_interrupts == 0) {
-cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
-}
 }
 
 if (old_pending != env->pending_interrupts) {
+ppc_maybe_interrupt(env);
 kvmppc_set_interrupt(cpu, irq, level);
 }
 
-
 trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
 
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 5018296f02..f65e0d7de8 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1358,6 +1358,7 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, 
CPUState *cs,
 int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
 #ifndef CONFIG_USER_ONLY
+void ppc_maybe_interrupt(CPUPPCState *env);
 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);
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index b4c1198ea2..788dcd732a 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2143,6 +2143,23 @@ static int ppc_pending_interrupt(CPUPPCState *env)
 }
 }
 
+void ppc_maybe_interrupt(CPUPPCState *env)
+{
+CPUState *cs = env_cpu(env);
+
+if (ppc_pending_interrupt(env)) {
+if (!qemu_mutex_iothread_locked()) {
+qemu_mutex_lock_iothread();
+cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+qemu_mutex_unlock_iothread();
+} else {
+cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+}
+} else {
+cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+}
+}
+
 static void ppc_hw_interrupt(CPUPPCState *env, int pending_interrupt)
 {
 PowerPCCPU *cpu = env_archcpu(env);
@@ -2380,6 +2397,8 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t 
insn)
 /* Condition for waking up at 0x100 */
 env->resume_as_sreset = (insn != PPC_PM_STOP) ||
 (env->spr[SPR_PSSCR] & PSSCR_EC);
+
+ppc_maybe_interrupt(env);
 }
 #endif /* defined(TARGET_PPC64) */
 
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 12235ea2e9..2e85e124ab 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -260,6 +260,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, 
int alter_hv)
 env->msr = value;
 hreg_compute_hflags(env);
 #if !defined(CONFIG_USER_ONLY)
+ppc_maybe_interrupt(env);
+
 if (unlikely(FIELD_EX64(env->msr, MSR, POW))) {
 if (!env->pending_interrupts && (*env->check_pow)(env)) {
 cs->halted = 1;
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 388337f81b..60dd66f736 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6174,7 +6174,8 @@ static void gen_wrtee(DisasContext *ctx)
 t0 = tcg_temp_new();
 tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE));
 tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
-tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
+tcg_gen_or_tl(t0, cpu_msr, t0);
+gen_helper_store_msr(cpu_env, t0);
 tcg_temp_free(t0);
 /*
  * Stop translation to have a chance to raise an exception if we
@@ -6192,7 +6193,10 @@ static void gen_wrteei(DisasContext *ctx)
 #else
 CHK_SV(ctx);
 if (ctx->opcode & 0x8000) {
-tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
+TCGv t0 = tcg_temp_new();
+tcg_gen_ori_tl(t0, cpu_msr, (1 << MSR_EE));
+gen_helper_store_msr(cpu_env, t0);
+tcg_temp_free(t0);
 /* Stop translation to have a chance to raise an exception */
 ctx->base.is_jmp = DISAS_EXIT_UPDATE;
 } else {
-- 
2.25.1




[RFC PATCH 09/13] target/ppc: create an interrupt masking method for POWER7

2022-08-15 Thread Matheus Ferst
The new method is based on cpu_has_work_POWER7 and
ppc_pending_interrupt_legacy.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 130 +++
 1 file changed, 130 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 0dbd385bf0..a67ab28661 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,6 +1678,134 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
+static int ppc_pending_interrupt_p7(CPUPPCState *env)
+{
+CPUState *cs = env_cpu(env);
+bool async_deliver;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+
+if (cs->halted) {
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE0)) {
+return PPC_INTERRUPT_EXT;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE1)) {
+return PPC_INTERRUPT_DECR;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+return PPC_INTERRUPT_MCK;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+(env->spr[SPR_LPCR] & LPCR_P7_PECE2)) {
+return PPC_INTERRUPT_HMI;
+}
+return 0;
+}
+
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)) {
+/* External critical interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+return PPC_INTERRUPT_CEXT;
+}
+}
+if (async_deliver != 0) {
+/* Watchdog timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+return PPC_INTERRUPT_WDT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+return PPC_INTERRUPT_CDOORBELL;
+}
+/* Fixed interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+return PPC_INTERRUPT_FIT;
+}
+/* Programmable interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+return PPC_INTERRUPT_PIT;
+}
+/* Decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+return PPC_INTERRUPT_DECR;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_PERFM) {
+return PPC_INTERRUPT_PERFM;
+}
+/* Thermal interrupt */
+if (e

[RFC PATCH 07/13] target/ppc: create an interrupt masking method for POWER8

2022-08-15 Thread Matheus Ferst
Create an interrupt masking method for POWER8. The new method is based
on cpu_has_work_POWER8 and ppc_pending_interrupt_legacy.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 138 +++
 1 file changed, 138 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 42b57019ba..13c2d5e2ce 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,6 +1678,142 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
+static int ppc_pending_interrupt_p8(CPUPPCState *env)
+{
+CPUState *cs = env_cpu(env);
+bool async_deliver = false;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+
+if (cs->halted) {
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE2)) {
+return PPC_INTERRUPT_EXT;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE3)) {
+return PPC_INTERRUPT_DECR;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_MCK) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+return PPC_INTERRUPT_MCK;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HMI) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE4)) {
+return PPC_INTERRUPT_HMI;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE0)) {
+return PPC_INTERRUPT_DOORBELL;
+}
+if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_P8_PECE1)) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+return 0;
+}
+
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver |= FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)) {
+/* External critical interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
+return PPC_INTERRUPT_CEXT;
+}
+}
+if (async_deliver != 0) {
+/* Watchdog timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
+return PPC_INTERRUPT_WDT;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
+return PPC_INTERRUPT_CDOORBELL;
+}
+/* Fixed interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
+return PPC_INTERRUPT_FIT;
+}
+/* Programmable interval timer on embedded PowerPC */
+if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
+return PPC_INTERRUPT_PIT;
+}
+/* Decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
+return PPC_INTERRUPT_DECR;
+   

[RFC PATCH 08/13] target/ppc: remove unused interrupts from ppc_pending_interrupt_p8

2022-08-15 Thread Matheus Ferst
The Hypervisor Virtualization Interrupt was introduced in PowerISA v3.0.
Critical Input, Watchdog Timer, and Fixed Interval Timer are only
defined for embedded CPUs. The Programmable Interval Timer is 40x-only.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 27 ---
 1 file changed, 27 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 13c2d5e2ce..0dbd385bf0 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1739,15 +1739,6 @@ static int ppc_pending_interrupt_p8(CPUPPCState *env)
 }
 }
 
-/* Hypervisor virtualization interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
-/* LPCR will be clear when not supported so this will work */
-bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-return PPC_INTERRUPT_HVIRT;
-}
-}
-
 /* External interrupt can ignore MSR:EE under some circumstances */
 if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
@@ -1759,28 +1750,10 @@ static int ppc_pending_interrupt_p8(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
 if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
 return PPC_INTERRUPT_CDOORBELL;
 }
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
-- 
2.25.1




[RFC PATCH 10/13] target/ppc: remove unused interrupts from ppc_pending_interrupt_p7

2022-08-15 Thread Matheus Ferst
The Hypervisor Virtualization Interrupt was introduced in PowerISA v3.0.
Critical Input, Watchdog Timer, and Fixed Interval Timer are only
defined for embedded CPUs. The Programmable Interval Timer is 40x-only.
The Event-Based Branch Facility was added in PowerISA v2.07.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 38 --
 1 file changed, 38 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index a67ab28661..b4c1198ea2 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1731,15 +1731,6 @@ static int ppc_pending_interrupt_p7(CPUPPCState *env)
 }
 }
 
-/* Hypervisor virtualization interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
-/* LPCR will be clear when not supported so this will work */
-bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
-if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
-return PPC_INTERRUPT_HVIRT;
-}
-}
-
 /* External interrupt can ignore MSR:EE under some circumstances */
 if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
 bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
@@ -1751,28 +1742,10 @@ static int ppc_pending_interrupt_p7(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
 if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
 return PPC_INTERRUPT_CDOORBELL;
 }
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
@@ -1790,17 +1763,6 @@ static int ppc_pending_interrupt_p7(CPUPPCState *env)
 if (env->pending_interrupts & PPC_INTERRUPT_THERM) {
 return PPC_INTERRUPT_THERM;
 }
-/* EBB exception */
-if (env->pending_interrupts & PPC_INTERRUPT_EBB) {
-/*
- * EBB exception must be taken in problem state and
- * with BESCR_GE set.
- */
-if (FIELD_EX64(env->msr, MSR, PR) &&
-(env->spr[SPR_BESCR] & BESCR_GE)) {
-return PPC_INTERRUPT_EBB;
-}
-}
 }
 
 return 0;
-- 
2.25.1




[RFC PATCH 04/13] target/ppc: prepare to split ppc_interrupt_pending by excp_model

2022-08-15 Thread Matheus Ferst
Rename the method to ppc_interrupt_pending_legacy and create a new
ppc_interrupt_pending that will call the appropriate interrupt masking
method based on env->excp_model.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 8690017c70..59981efd16 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,7 +1678,7 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
-static int ppc_pending_interrupt(CPUPPCState *env)
+static int ppc_pending_interrupt_legacy(CPUPPCState *env)
 {
 bool async_deliver;
 
@@ -1790,6 +1790,14 @@ static int ppc_pending_interrupt(CPUPPCState *env)
 return 0;
 }
 
+static int ppc_pending_interrupt(CPUPPCState *env)
+{
+switch (env->excp_model) {
+default:
+return ppc_pending_interrupt_legacy(env);
+}
+}
+
 static void ppc_hw_interrupt(CPUPPCState *env, int pending_interrupt)
 {
 PowerPCCPU *cpu = env_archcpu(env);
-- 
2.25.1




[RFC PATCH 05/13] target/ppc: create an interrupt masking method for POWER9/POWER10

2022-08-15 Thread Matheus Ferst
Create an interrupt masking method for the POWER9 and POWER10
processors. The new method is based on cpu_has_work_POWER{9,10} and
ppc_pending_interrupt_legacy.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 160 +++
 1 file changed, 160 insertions(+)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 59981efd16..2ca6a917b2 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,6 +1678,163 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
+static int ppc_pending_interrupt_p9(CPUPPCState *env)
+{
+CPUState *cs = env_cpu(env);
+bool async_deliver = false;
+
+/* External reset */
+if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
+return PPC_INTERRUPT_RESET;
+}
+
+if (cs->halted) {
+uint64_t psscr = env->spr[SPR_PSSCR];
+
+if (!(psscr & PSSCR_EC)) {
+/* If EC is clear, return any system-caused interrupt */
+async_deliver = true;
+} else {
+/* External Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_EXT) &&
+(env->spr[SPR_LPCR] & LPCR_EEE)) {
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+if (!heic || !FIELD_EX64_HV(env->msr) ||
+FIELD_EX64(env->msr, MSR, PR)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+/* Decrementer Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_DECR) &&
+(env->spr[SPR_LPCR] & LPCR_DEE)) {
+return PPC_INTERRUPT_DECR;
+}
+/* Machine Check or Hypervisor Maintenance Exception */
+if (env->spr[SPR_LPCR] & LPCR_OEE) {
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+if (env->pending_interrupts & PPC_INTERRUPT_HMI) {
+return PPC_INTERRUPT_HMI;
+}
+}
+/* Privileged Doorbell Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_PDEE)) {
+return PPC_INTERRUPT_DOORBELL;
+}
+/* Hypervisor Doorbell Exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) &&
+(env->spr[SPR_LPCR] & LPCR_HDEE)) {
+return PPC_INTERRUPT_HDOORBELL;
+}
+/* Hypervisor virtualization exception */
+if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) &&
+(env->spr[SPR_LPCR] & LPCR_HVEE)) {
+return PPC_INTERRUPT_HVIRT;
+}
+return 0;
+}
+}
+
+/* Machine check exception */
+if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
+return PPC_INTERRUPT_MCK;
+}
+
+/*
+ * For interrupts that gate on MSR:EE, we need to do something a
+ * bit more subtle, as we need to let them through even when EE is
+ * clear when coming out of some power management states (in order
+ * for them to become a 0x100).
+ */
+async_deliver |= FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset;
+
+/* Hypervisor decrementer exception */
+if (env->pending_interrupts & PPC_INTERRUPT_HDECR) {
+/* LPCR will be clear when not supported so this will work */
+bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
+/* HDEC clears on delivery */
+return PPC_INTERRUPT_HDECR;
+}
+}
+
+/* Hypervisor virtualization interrupt */
+if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) {
+/* LPCR will be clear when not supported so this will work */
+bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
+if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) {
+return PPC_INTERRUPT_HVIRT;
+}
+}
+
+/* External interrupt can ignore MSR:EE under some circumstances */
+if (env->pending_interrupts & PPC_INTERRUPT_EXT) {
+bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
+/* HEIC blocks delivery to the hypervisor */
+if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
+!FIELD_EX64(env->msr, MSR, PR))) ||
+(env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
+return PPC_INTERRUPT_EXT;
+}
+}
+if (FIELD_EX64(env->msr, MSR, CE)

[RFC PATCH 06/13] target/ppc: remove embedded interrupts from ppc_pending_interrupt_p9

2022-08-15 Thread Matheus Ferst
Critical Input, Watchdog Timer, and Fixed Interval Timer are only
defined for embedded CPUs. The Programmable Interval Timer is 40x-only.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 18 --
 1 file changed, 18 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 2ca6a917b2..42b57019ba 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1780,28 +1780,10 @@ static int ppc_pending_interrupt_p9(CPUPPCState *env)
 return PPC_INTERRUPT_EXT;
 }
 }
-if (FIELD_EX64(env->msr, MSR, CE)) {
-/* External critical interrupt */
-if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-return PPC_INTERRUPT_CEXT;
-}
-}
 if (async_deliver != 0) {
-/* Watchdog timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-return PPC_INTERRUPT_WDT;
-}
 if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
 return PPC_INTERRUPT_CDOORBELL;
 }
-/* Fixed interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-return PPC_INTERRUPT_FIT;
-}
-/* Programmable interval timer on embedded PowerPC */
-if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-return PPC_INTERRUPT_PIT;
-}
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
 return PPC_INTERRUPT_DECR;
-- 
2.25.1




[RFC PATCH 01/13] target/ppc: define PPC_INTERRUPT_* values directly

2022-08-15 Thread Matheus Ferst
This enum defines the bit positions in env->pending_interrupts for each
interrupt. However, except for the comparison in kvmppc_set_interrupt,
the values are always used as (1 << PPC_INTERRUPT_*). Define them
directly like that to save some clutter. No functional change intended.

Signed-off-by: Matheus Ferst 
---
 hw/ppc/ppc.c | 10 +++---
 hw/ppc/trace-events  |  2 +-
 target/ppc/cpu.h | 40 +++---
 target/ppc/cpu_init.c| 56 +++---
 target/ppc/excp_helper.c | 74 
 target/ppc/misc_helper.c |  6 ++--
 6 files changed, 94 insertions(+), 94 deletions(-)

diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 690f448cb9..77e611e81c 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -40,7 +40,7 @@
 static void cpu_ppc_tb_stop (CPUPPCState *env);
 static void cpu_ppc_tb_start (CPUPPCState *env);
 
-void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
+void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
 {
 CPUState *cs = CPU(cpu);
 CPUPPCState *env = >env;
@@ -56,21 +56,21 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
 old_pending = env->pending_interrupts;
 
 if (level) {
-env->pending_interrupts |= 1 << n_IRQ;
+env->pending_interrupts |= irq;
 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
-env->pending_interrupts &= ~(1 << n_IRQ);
+env->pending_interrupts &= ~irq;
 if (env->pending_interrupts == 0) {
 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
 }
 
 if (old_pending != env->pending_interrupts) {
-kvmppc_set_interrupt(cpu, n_IRQ, level);
+kvmppc_set_interrupt(cpu, irq, level);
 }
 
 
-trace_ppc_irq_set_exit(env, n_IRQ, level, env->pending_interrupts,
+trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
 
 if (locked) {
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index 5c0a215cad..c9ee1285b8 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -116,7 +116,7 @@ ppc40x_set_tb_clk(uint32_t value) "new frequency %" PRIu32
 ppc40x_timers_init(uint32_t value) "frequency %" PRIu32
 
 ppc_irq_set(void *env, uint32_t pin, uint32_t level) "env [%p] pin %d level %d"
-ppc_irq_set_exit(void *env, uint32_t n_IRQ, uint32_t level, uint32_t pending, 
uint32_t request) "env [%p] n_IRQ %d level %d => pending 0x%08" PRIx32 " req 
0x%08" PRIx32
+ppc_irq_set_exit(void *env, uint32_t irq, uint32_t level, uint32_t pending, 
uint32_t request) "env [%p] irq 0x%05" PRIx32 " level %d => pending 0x%08" 
PRIx32 " req 0x%08" PRIx32
 ppc_irq_set_state(const char *name, uint32_t level) "\"%s\" level %d"
 ppc_irq_reset(const char *name) "%s"
 ppc_irq_cpu(const char *action) "%s"
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index a4c893cfad..c7864bb3b1 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -2418,27 +2418,27 @@ enum {
 /* Hardware exceptions definitions */
 enum {
 /* External hardware exception sources */
-PPC_INTERRUPT_RESET = 0,  /* Reset exception  */
-PPC_INTERRUPT_WAKEUP, /* Wakeup exception */
-PPC_INTERRUPT_MCK,/* Machine check exception  */
-PPC_INTERRUPT_EXT,/* External interrupt   */
-PPC_INTERRUPT_SMI,/* System management interrupt  */
-PPC_INTERRUPT_CEXT,   /* Critical external interrupt  */
-PPC_INTERRUPT_DEBUG,  /* External debug exception */
-PPC_INTERRUPT_THERM,  /* Thermal exception*/
+PPC_INTERRUPT_RESET = 0x1,  /* Reset exception
*/
+PPC_INTERRUPT_WAKEUP= 0x2,  /* Wakeup exception   
*/
+PPC_INTERRUPT_MCK   = 0x4,  /* Machine check exception
*/
+PPC_INTERRUPT_EXT   = 0x8,  /* External interrupt 
*/
+PPC_INTERRUPT_SMI   = 0x00010,  /* System management interrupt
*/
+PPC_INTERRUPT_CEXT  = 0x00020,  /* Critical external interrupt
*/
+PPC_INTERRUPT_DEBUG = 0x00040,  /* External debug exception   
*/
+PPC_INTERRUPT_THERM = 0x00080,  /* Thermal exception  
*/
 /* Internal hardware exception sources */
-PPC_INTERRUPT_DECR,   /* Decrementer exception*/
-PPC_INTERRUPT_HDECR,  /* Hypervisor decrementer exception */
-PPC_INTERRUPT_PIT,/* Programmable interval timer interrupt */
-PPC_INTERRUPT_FIT,/* Fixed interval timer interrupt   */
-PPC_INTERRUPT_WDT,/* Watchdog timer interrupt

[RFC PATCH 02/13] target/ppc: always use ppc_set_irq to set env->pending_interrupts

2022-08-15 Thread Matheus Ferst
Use ppc_set_irq to raise/clear interrupts to ensure CPU_INTERRUPT_HARD
will be set/reset accordingly.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 17 +++--
 target/ppc/misc_helper.c |  9 ++---
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index b9476b5d03..ae9576546f 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -23,6 +23,7 @@
 #include "exec/exec-all.h"
 #include "internal.h"
 #include "helper_regs.h"
+#include "hw/ppc/ppc.h"
 
 #include "trace.h"
 
@@ -2080,7 +2081,6 @@ void helper_rfebb(CPUPPCState *env, target_ulong s)
 static void do_ebb(CPUPPCState *env, int ebb_excp)
 {
 PowerPCCPU *cpu = env_archcpu(env);
-CPUState *cs = CPU(cpu);
 
 /*
  * FSCR_EBB and FSCR_IC_EBB are the same bits used with
@@ -2098,8 +2098,7 @@ static void do_ebb(CPUPPCState *env, int ebb_excp)
 if (FIELD_EX64(env->msr, MSR, PR)) {
 powerpc_excp(cpu, ebb_excp);
 } else {
-env->pending_interrupts |= PPC_INTERRUPT_EBB;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, PPC_INTERRUPT_EBB, 1);
 }
 }
 
@@ -2209,7 +2208,7 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb)
 return;
 }
 
-env->pending_interrupts &= ~irq;
+ppc_set_irq(env_archcpu(env), irq, 0);
 }
 
 void helper_msgsnd(target_ulong rb)
@@ -2228,8 +2227,7 @@ void helper_msgsnd(target_ulong rb)
 CPUPPCState *cenv = >env;
 
 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
-cenv->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, irq, 1);
 }
 }
 qemu_mutex_unlock_iothread();
@@ -2253,7 +2251,7 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong 
rb)
 return;
 }
 
-env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL;
+ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
 }
 
 static void book3s_msgsnd_common(int pir, int irq)
@@ -2267,8 +2265,7 @@ static void book3s_msgsnd_common(int pir, int irq)
 
 /* TODO: broadcast message to all threads of the same  processor */
 if (cenv->spr_cb[SPR_PIR].default_value == pir) {
-cenv->pending_interrupts |= irq;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ppc_set_irq(cpu, irq, 1);
 }
 }
 qemu_mutex_unlock_iothread();
@@ -2294,7 +2291,7 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong 
rb)
 return;
 }
 
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
+ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0);
 }
 
 /*
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 05e35572bc..a9bc1522e2 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -25,6 +25,7 @@
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
 #include "mmu-book3s-v3.h"
+#include "hw/ppc/ppc.h"
 
 #include "helper_regs.h"
 
@@ -173,7 +174,6 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
 void helper_store_dpdes(CPUPPCState *env, target_ulong val)
 {
 PowerPCCPU *cpu = env_archcpu(env);
-CPUState *cs = CPU(cpu);
 
 helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
 
@@ -184,12 +184,7 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
 return;
 }
 
-if (val & 0x1) {
-env->pending_interrupts |= PPC_INTERRUPT_DOORBELL;
-cpu_interrupt(cs, CPU_INTERRUPT_HARD);
-} else {
-env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL;
-}
+ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
 }
 #endif /* defined(TARGET_PPC64) */
 
-- 
2.25.1




[RFC PATCH 03/13] target/ppc: move interrupt masking out of ppc_hw_interrupt

2022-08-15 Thread Matheus Ferst
Move the interrupt masking logic to a new method, ppc_pending_interrupt,
and only handle the interrupt processing in ppc_hw_interrupt.

Signed-off-by: Matheus Ferst 
---
 target/ppc/excp_helper.c | 228 ---
 1 file changed, 141 insertions(+), 87 deletions(-)

diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index ae9576546f..8690017c70 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1678,29 +1678,22 @@ void ppc_cpu_do_interrupt(CPUState *cs)
 powerpc_excp(cpu, cs->exception_index);
 }
 
-static void ppc_hw_interrupt(CPUPPCState *env)
+static int ppc_pending_interrupt(CPUPPCState *env)
 {
-PowerPCCPU *cpu = env_archcpu(env);
 bool async_deliver;
 
 /* External reset */
 if (env->pending_interrupts & PPC_INTERRUPT_RESET) {
-env->pending_interrupts &= ~PPC_INTERRUPT_RESET;
-powerpc_excp(cpu, POWERPC_EXCP_RESET);
-return;
+return PPC_INTERRUPT_RESET;
 }
 /* Machine check exception */
 if (env->pending_interrupts & PPC_INTERRUPT_MCK) {
-env->pending_interrupts &= ~PPC_INTERRUPT_MCK;
-powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
-return;
+return PPC_INTERRUPT_MCK;
 }
 #if 0 /* TODO */
 /* External debug exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG;
-powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
-return;
+return PPC_INTERRUPT_DEBUG;
 }
 #endif
 
@@ -1718,9 +1711,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
 bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
 if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) {
 /* HDEC clears on delivery */
-env->pending_interrupts &= ~PPC_INTERRUPT_HDECR;
-powerpc_excp(cpu, POWERPC_EXCP_HDECR);
-return;
+return PPC_INTERRUPT_HDECR;
 }
 }
 
@@ -1729,8 +1720,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 || !FIELD_EX64_HV(env->msr)) && hvice) {
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-return;
+return PPC_INTERRUPT_HVIRT;
 }
 }
 
@@ -1742,77 +1732,47 @@ static void ppc_hw_interrupt(CPUPPCState *env)
 if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) &&
 !FIELD_EX64(env->msr, MSR, PR))) ||
 (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) {
-if (books_vhyp_promotes_external_to_hvirt(cpu)) {
-powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
-} else {
-powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
-}
-return;
+return PPC_INTERRUPT_EXT;
 }
 }
 if (FIELD_EX64(env->msr, MSR, CE)) {
 /* External critical interrupt */
 if (env->pending_interrupts & PPC_INTERRUPT_CEXT) {
-powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
-return;
+return PPC_INTERRUPT_CEXT;
 }
 }
 if (async_deliver != 0) {
 /* Watchdog timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_WDT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_WDT;
-powerpc_excp(cpu, POWERPC_EXCP_WDT);
-return;
+return PPC_INTERRUPT_WDT;
 }
 if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) {
-env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL;
-powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
-return;
+return PPC_INTERRUPT_CDOORBELL;
 }
 /* Fixed interval timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_FIT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_FIT;
-powerpc_excp(cpu, POWERPC_EXCP_FIT);
-return;
+return PPC_INTERRUPT_FIT;
 }
 /* Programmable interval timer on embedded PowerPC */
 if (env->pending_interrupts & PPC_INTERRUPT_PIT) {
-env->pending_interrupts &= ~PPC_INTERRUPT_PIT;
-powerpc_excp(cpu, POWERPC_EXCP_PIT);
-return;
+return PPC_INTERRUPT_PIT;
 }
 /* Decrementer exception */
 if (env->pending_interrupts & PPC_INTERRUPT_DECR) {
-if (ppc_decr_clear_on_delivery(env)) {
-env->pending_interrupts &= ~PPC_INTERRUPT_DECR;
-}
-powerpc_excp(cpu, POWERPC_EXCP_DECR);
-return;
+return PPC_INTERRUPT_DECR;
 }
 if (env->pendin

[RFC PATCH 00/13] PowerPC interrupt rework

2022-08-15 Thread Matheus Ferst
Currently, PowerPC interrupts are handled as follows:

1) The CPU_INTERRUPT_HARD bit of cs->interrupt_request gates all
   interrupts;
2) The bits of env->pending_interrupts identify which particular
   interrupt is raised;
3) ppc_set_irq can be used to set/clear env->pending_interrupt bit and
   CPU_INTERRUPT_HARD, but some places access env->pending_interrupt
   directly;
4) ppc_cpu_exec_interrupt is called by cpu_handle_interrupt when
   cs->interrupt_request indicates that there is some interrupt pending.
   This method checks CPU_INTERRUPT_HARD and calls ppc_hw_interrupt. If
   env->pending_interrupt is zero after this call, CPU_INTERRUPT_HARD
   will be cleared.
5) ppc_hw_interrupt checks if there is any unmasked interrupt and calls
   powerpc_excp with the appropriate POWERPC_EXCP_* value. The method
   will also reset the corresponding bit in env->pending_interrupt for
   interrupts that clear on delivery.

If all pending interrupts are masked, CPU_INTERRUPT_HARD will be set,
but ppc_hw_interrupt will not deliver or clear the interrupt, so
CPU_INTERRUPT_HARD will not be reset by ppc_cpu_exec_interrupt. With
that, cs->has_work keeps returning true, creating a loop that acquires
and release qemu_mutex_lock_iothread, causing the poor performance
reported in [1].

This patch series attempts to rework the PowerPC interrupt code to set
CPU_INTERRUPT_HARD only when there are unmasked interrupts. Then
cs->has_work can be simplified to a check of CPU_INTERRUPT_HARD, so it
also only returns true when at least one interrupt can be delivered.

To achieve that, we are basically following Alex Bannée's suggestion[2]
in the original thread: the interrupt masking logic will be factored
out of ppc_hw_interrupt in a new method, ppc_pending_interrupts. This
method is then used to decide if CPU_INTERRUPT_HARD should be set or
cleared after changes to MSR, LPCR, env->pending_interrupts, and
power-management instructions.

We used [3] to check for regressions at each patch in this series. After
patch 12, booting a powernv machine with a newer skiboot with "-smp 4"
goes from 1m09s to 20.79s.

[1] https://lists.gnu.org/archive/html/qemu-ppc/2022-06/msg00336.html
[2] https://lists.gnu.org/archive/html/qemu-ppc/2022-06/msg00372.html
[3] https://github.com/legoater/qemu-ppc-boot

Matheus Ferst (13):
  target/ppc: define PPC_INTERRUPT_* values directly
  target/ppc: always use ppc_set_irq to set env->pending_interrupts
  target/ppc: move interrupt masking out of ppc_hw_interrupt
  target/ppc: prepare to split ppc_interrupt_pending by excp_model
  target/ppc: create a interrupt masking method for POWER9/POWER10
  target/ppc: remove embedded interrupts from ppc_pending_interrupt_p9
  target/ppc: create a interrupt masking method for POWER8
  target/ppc: remove unused interrupts from ppc_pending_interrupt_p8
  target/ppc: create a interrupt masking method for POWER7
  target/ppc: remove unused interrupts from ppc_pending_interrupt_p7
  target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds
  target/ppc: introduce ppc_maybe_interrupt
  target/ppc: unify cpu->has_work based on cs->interrupt_request

 hw/ppc/ppc.c |  17 +-
 hw/ppc/trace-events  |   2 +-
 target/ppc/cpu.c |   2 +
 target/ppc/cpu.h |  43 +--
 target/ppc/cpu_init.c| 212 +
 target/ppc/excp_helper.c | 651 ---
 target/ppc/helper_regs.c |   2 +
 target/ppc/misc_helper.c |  11 +-
 target/ppc/translate.c   |   8 +-
 9 files changed, 580 insertions(+), 368 deletions(-)

-- 
2.25.1




[PATCH v3] target/ppc: check tb_env != 0 before printing TBU/TBL/DECR

2022-07-14 Thread Matheus Ferst
When using "-machine none", env->tb_env is not allocated, causing the
segmentation fault reported in issue #85 (launchpad bug #811683). To
avoid this problem, check if the pointer != NULL before calling the
methods to print TBU/TBL/DECR.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/85
Signed-off-by: Matheus Ferst 
---
v3:
  - Only check env->tb_env in softmmu, linux-user get timebase from
elsewhere. Also, try to make the qemu_fprintf call more readable.
  - Link to v2: 
https://lists.gnu.org/archive/html/qemu-ppc/2022-07/msg00193.html
---
 target/ppc/cpu_init.c | 18 --
 target/ppc/monitor.c  |  9 +
 2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 86ad28466a..313c8bb300 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7476,17 +7476,15 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int 
flags)
  "%08x iidx %d didx %d\n",
  env->msr, env->spr[SPR_HID0], env->hflags,
  cpu_mmu_index(env, true), cpu_mmu_index(env, false));
-#if !defined(NO_TIMER_DUMP)
-qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
 #if !defined(CONFIG_USER_ONLY)
- " DECR " TARGET_FMT_lu
-#endif
- "\n",
- cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
-#if !defined(CONFIG_USER_ONLY)
- , cpu_ppc_load_decr(env)
-#endif
-);
+if (env->tb_env) {
+qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
+ " DECR " TARGET_FMT_lu "\n", cpu_ppc_load_tbu(env),
+ cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
+}
+#else
+qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 "\n", cpu_ppc_load_tbu(env),
+ cpu_ppc_load_tbl(env));
 #endif
 for (i = 0; i < 32; i++) {
 if ((i & (RGPL - 1)) == 0) {
diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c
index 0b805ef6e9..8250b1304e 100644
--- a/target/ppc/monitor.c
+++ b/target/ppc/monitor.c
@@ -55,6 +55,9 @@ static target_long monitor_get_decr(Monitor *mon, const 
struct MonitorDef *md,
 int val)
 {
 CPUArchState *env = mon_get_cpu_env(mon);
+if (!env->tb_env) {
+return 0;
+}
 return cpu_ppc_load_decr(env);
 }
 
@@ -62,6 +65,9 @@ static target_long monitor_get_tbu(Monitor *mon, const struct 
MonitorDef *md,
int val)
 {
 CPUArchState *env = mon_get_cpu_env(mon);
+if (!env->tb_env) {
+return 0;
+}
 return cpu_ppc_load_tbu(env);
 }
 
@@ -69,6 +75,9 @@ static target_long monitor_get_tbl(Monitor *mon, const struct 
MonitorDef *md,
int val)
 {
 CPUArchState *env = mon_get_cpu_env(mon);
+if (!env->tb_env) {
+return 0;
+}
 return cpu_ppc_load_tbl(env);
 }
 
-- 
2.25.1




[PATCH v2] target/ppc: check tb_env != 0 before printing TBU/TBL/DECR

2022-07-13 Thread Matheus Ferst
When using "-machine none", env->tb_env is not allocated, causing the
segmentation fault reported in issue #85 (launchpad bug #811683). To
avoid this problem, check if the pointer != NULL before calling the
methods to print TBU/TBL/DECR.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/85
Signed-off-by: Matheus Ferst 
---
v2:
 - Added checks in monitor_get_decr, monitor_get_tbu, and monitor_get_tbl.
 - Link to v1: https://lists.gnu.org/archive/html/qemu-ppc/2022-07/msg00173.html
---
 target/ppc/cpu_init.c | 16 
 target/ppc/monitor.c  |  9 +
 2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 86ad28466a..7e96baac9f 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7476,18 +7476,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int 
flags)
  "%08x iidx %d didx %d\n",
  env->msr, env->spr[SPR_HID0], env->hflags,
  cpu_mmu_index(env, true), cpu_mmu_index(env, false));
-#if !defined(NO_TIMER_DUMP)
-qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
+if (env->tb_env) {
+qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
 #if !defined(CONFIG_USER_ONLY)
- " DECR " TARGET_FMT_lu
+ " DECR " TARGET_FMT_lu
 #endif
- "\n",
- cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
+ "\n",
+ cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
 #if !defined(CONFIG_USER_ONLY)
- , cpu_ppc_load_decr(env)
-#endif
-);
+ , cpu_ppc_load_decr(env)
 #endif
+);
+}
 for (i = 0; i < 32; i++) {
 if ((i & (RGPL - 1)) == 0) {
 qemu_fprintf(f, "GPR%02d", i);
diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c
index 0b805ef6e9..8250b1304e 100644
--- a/target/ppc/monitor.c
+++ b/target/ppc/monitor.c
@@ -55,6 +55,9 @@ static target_long monitor_get_decr(Monitor *mon, const 
struct MonitorDef *md,
 int val)
 {
 CPUArchState *env = mon_get_cpu_env(mon);
+if (!env->tb_env) {
+return 0;
+}
 return cpu_ppc_load_decr(env);
 }
 
@@ -62,6 +65,9 @@ static target_long monitor_get_tbu(Monitor *mon, const struct 
MonitorDef *md,
int val)
 {
 CPUArchState *env = mon_get_cpu_env(mon);
+if (!env->tb_env) {
+return 0;
+}
 return cpu_ppc_load_tbu(env);
 }
 
@@ -69,6 +75,9 @@ static target_long monitor_get_tbl(Monitor *mon, const struct 
MonitorDef *md,
int val)
 {
 CPUArchState *env = mon_get_cpu_env(mon);
+if (!env->tb_env) {
+return 0;
+}
 return cpu_ppc_load_tbl(env);
 }
 
-- 
2.25.1




[RFC PATCH] target/ppc: don't print TB in ppc_cpu_dump_state if it's not initialized

2022-07-12 Thread Matheus Ferst
When using "-machine none", env->tb_env is not allocated, causing the
segmentation fault reported in issue #85 (launchpad bug #811683). To
avoid this problem, check if the pointer != NULL before calling the
methods to print TBU/TBL/DECR.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/85
Signed-off-by: Matheus Ferst 
---
This patch fixes the reported problem, but may be an incomplete solution
since many other places dereference env->tb_env without checking for
NULL. AFAICS, "-machine none" is the only way to trigger this problem,
and I'm not familiar with the use-cases for this option.

Should we stop assuming env->tb_env != NULL and add checks everywhere?
Or should we find a way to provide Time Base/Decrementer for
"-machine none"?
---
 target/ppc/cpu_init.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 86ad28466a..7e96baac9f 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7476,18 +7476,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int 
flags)
  "%08x iidx %d didx %d\n",
  env->msr, env->spr[SPR_HID0], env->hflags,
  cpu_mmu_index(env, true), cpu_mmu_index(env, false));
-#if !defined(NO_TIMER_DUMP)
-qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
+if (env->tb_env) {
+qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
 #if !defined(CONFIG_USER_ONLY)
- " DECR " TARGET_FMT_lu
+ " DECR " TARGET_FMT_lu
 #endif
- "\n",
- cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
+ "\n",
+ cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
 #if !defined(CONFIG_USER_ONLY)
- , cpu_ppc_load_decr(env)
-#endif
-);
+ , cpu_ppc_load_decr(env)
 #endif
+);
+}
 for (i = 0; i < 32; i++) {
 if ((i & (RGPL - 1)) == 0) {
 qemu_fprintf(f, "GPR%02d", i);
-- 
2.25.1




[PATCH 0/6] Fix gen_*_exception error codes

2022-06-27 Thread Matheus Ferst
The first patch of this series is the RFC of [1] (hence the r-b in v1).
Patches 2~4 follow the other problems that Laurent pointed out, and
patches 5-6 fix similar problems that I found.

[1] https://lists.gnu.org/archive/html/qemu-ppc/2022-01/msg00400.html

Matheus Ferst (6):
  target/ppc: Fix gen_priv_exception error value in mfspr/mtspr
  target/ppc: fix exception error value in slbfee
  target/ppc: remove mfdcrux and mtdcrux
  target/ppc: fix exception error code in helper_{load,store}_dcr
  target/ppc: fix PMU Group A register read/write exceptions
  target/ppc: fix exception error code in spr_write_excp_vector

 target/ppc/cpu.h |  6 ++
 target/ppc/helper.h  |  2 +-
 target/ppc/power8-pmu-regs.c.inc | 10 -
 target/ppc/timebase_helper.c |  6 +++---
 target/ppc/translate.c   | 36 
 5 files changed, 20 insertions(+), 40 deletions(-)

-- 
2.25.1




[PATCH 6/6] target/ppc: fix exception error code in spr_write_excp_vector

2022-06-27 Thread Matheus Ferst
The 'error' argument of gen_inval_exception will be or-ed with
POWERPC_EXCP_INVAL, so it should always be a constant prefixed with
POWERPC_EXCP_INVAL_. No functional change is intended,
spr_write_excp_vector is only used by register_BookE_sprs, and
powerpc_excp_booke ignores the lower 4 bits of the error code on
POWERPC_EXCP_INVAL exceptions.

Also, take the opportunity to replace printf with qemu_log_mask.

Signed-off-by: Matheus Ferst 
---
 target/ppc/translate.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 30dd524959..da11472877 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -907,9 +907,9 @@ void spr_write_excp_vector(DisasContext *ctx, int sprn, int 
gprn)
 } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) {
 sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38;
 } else {
-printf("Trying to write an unknown exception vector %d %03x\n",
-   sprn, sprn);
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+qemu_log_mask(LOG_GUEST_ERROR, "Trying to write an unknown exception"
+  " vector 0x%03x\n", sprn);
+gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
 return;
 }
 
-- 
2.25.1




[PATCH 3/6] target/ppc: remove mfdcrux and mtdcrux

2022-06-27 Thread Matheus Ferst
The only PowerPC implementations with these insns were the 460 and 460F,
which had their definitions removed in [1].

[1] 7ff26aa6c657 ("target/ppc: Remove unused PPC 460 and 460F definitions")

Signed-off-by: Matheus Ferst 
---
 target/ppc/cpu.h   |  6 ++
 target/ppc/translate.c | 18 --
 2 files changed, 2 insertions(+), 22 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 6d78078f37..80664446e6 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -2203,8 +2203,6 @@ enum {
 PPC_DCR= 0x1000ULL,
 /* DCR extended accesse  */
 PPC_DCRX   = 0x2000ULL,
-/* user-mode DCR access, implemented in PowerPC 460  */
-PPC_DCRUX  = 0x4000ULL,
 /* popcntw and popcntd instructions  */
 PPC_POPCNTWD   = 0x8000ULL,
 
@@ -2228,8 +2226,8 @@ enum {
 | PPC_405_MAC | PPC_440_SPEC | PPC_BOOKE \
 | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \
 | PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \
-| PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \
-| PPC_POPCNTWD | PPC_CILDST)
+| PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_POPCNTWD \
+| PPC_CILDST)
 
 /* extended type values */
 
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index d7e5670c20..30dd524959 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -5907,22 +5907,6 @@ static void gen_mtdcrx(DisasContext *ctx)
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
-/* mfdcrux (PPC 460) : user-mode access to DCR */
-static void gen_mfdcrux(DisasContext *ctx)
-{
-gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
-cpu_gpr[rA(ctx->opcode)]);
-/* Note: Rc update flag set leads to undefined state of Rc0 */
-}
-
-/* mtdcrux (PPC 460) : user-mode access to DCR */
-static void gen_mtdcrux(DisasContext *ctx)
-{
-gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
- cpu_gpr[rS(ctx->opcode)]);
-/* Note: Rc update flag set leads to undefined state of Rc0 */
-}
-
 /* dccci */
 static void gen_dccci(DisasContext *ctx)
 {
@@ -6958,8 +6942,6 @@ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x0001, PPC_DCR),
 GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x0001, PPC_DCR),
 GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x, PPC_DCRX),
 GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x, PPC_DCRX),
-GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x, PPC_DCRUX),
-GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x, PPC_DCRUX),
 GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E1, PPC_4xx_COMMON),
 GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x0001, PPC_4xx_COMMON),
 GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E1, PPC_40x_ICBT),
-- 
2.25.1




[PATCH 4/6] target/ppc: fix exception error code in helper_{load, store}_dcr

2022-06-27 Thread Matheus Ferst
POWERPC_EXCP_INVAL should only be or-ed with other constants prefixed
with POWERPC_EXCP_INVAL_. Also, take the opportunity to move both
helpers under #if !defined(CONFIG_USER_ONLY) as the instructions that
use them are privileged.

No functional change is intended, the lower 4 bits of the error code are
ignored by all powerpc_excp_* methods on POWERPC_EXCP_INVAL exceptions.

Reported-by: Laurent Vivier 
Signed-off-by: Matheus Ferst 
---
 target/ppc/helper.h  | 2 +-
 target/ppc/timebase_helper.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 6233e28d85..c6895f2f99 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -684,10 +684,10 @@ DEF_HELPER_2(book3s_msgclr, void, env, tl)
 DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
 #if !defined(CONFIG_USER_ONLY)
 DEF_HELPER_2(rac, tl, env, tl)
-#endif
 
 DEF_HELPER_2(load_dcr, tl, env, tl)
 DEF_HELPER_3(store_dcr, void, env, tl, tl)
+#endif
 
 DEF_HELPER_2(load_dump_spr, void, env, i32)
 DEF_HELPER_2(store_dump_spr, void, env, i32)
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index 86d01d6e4e..b80f56af7e 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -143,7 +143,6 @@ void helper_store_booke_tsr(CPUPPCState *env, target_ulong 
val)
 {
 store_booke_tsr(env, val);
 }
-#endif
 
 /*/
 /* Embedded PowerPC specific helpers */
@@ -169,7 +168,7 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong 
dcrn)
   (uint32_t)dcrn, (uint32_t)dcrn);
 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL |
-   POWERPC_EXCP_PRIV_REG, GETPC());
+   POWERPC_EXCP_INVAL_INVAL, GETPC());
 }
 }
 return val;
@@ -192,7 +191,8 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, 
target_ulong val)
   (uint32_t)dcrn, (uint32_t)dcrn);
 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL |
-   POWERPC_EXCP_PRIV_REG, GETPC());
+   POWERPC_EXCP_INVAL_INVAL, GETPC());
 }
 }
 }
+#endif
-- 
2.25.1




[PATCH 2/6] target/ppc: fix exception error value in slbfee

2022-06-27 Thread Matheus Ferst
Testing on a POWER9 DD2.3, we observed that the Linux kernel delivers a
signal with si_code ILL_PRVOPC (5) when a userspace application tries to
use slbfee. To obtain this behavior on linux-user, we should use
POWERPC_EXCP_PRIV with POWERPC_EXCP_PRIV_OPC.

No functional change is intended for softmmu targets as
gen_hvpriv_exception uses the same 'exception' argument
(POWERPC_EXCP_HV_EMU) for raise_exception_*, and the powerpc_excp_*
methods do not use lower bits of the exception error code when handling
POWERPC_EXCP_{INVAL,PRIV}.

Reported-by: Laurent Vivier 
Signed-off-by: Matheus Ferst 
---
 target/ppc/translate.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 55f34eb490..d7e5670c20 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -5386,12 +5386,12 @@ static void gen_slbmfev(DisasContext *ctx)
 static void gen_slbfee_(DisasContext *ctx)
 {
 #if defined(CONFIG_USER_ONLY)
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
 #else
 TCGLabel *l1, *l2;
 
 if (unlikely(ctx->pr)) {
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
 return;
 }
 gen_helper_find_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env,
-- 
2.25.1




[PATCH 5/6] target/ppc: fix PMU Group A register read/write exceptions

2022-06-27 Thread Matheus Ferst
A call to "gen_(hv)priv_exception" should use POWERPC_EXCP_PRIV_* as the
'error' argument instead of POWERPC_EXCP_INVAL_*, and POWERPC_EXCP_FU is
an exception type, not an exception error code. To correctly set
FSCR[IC], we should raise Facility Unavailable with this exception type
and IC value as the error code.

Fixes: 565cb1096733 ("target/ppc: add user read/write functions for MMCR0")
Signed-off-by: Matheus Ferst 
---
 target/ppc/power8-pmu-regs.c.inc | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/target/ppc/power8-pmu-regs.c.inc b/target/ppc/power8-pmu-regs.c.inc
index 2bab6cece7..c3cc919ee4 100644
--- a/target/ppc/power8-pmu-regs.c.inc
+++ b/target/ppc/power8-pmu-regs.c.inc
@@ -22,7 +22,7 @@
 static bool spr_groupA_read_allowed(DisasContext *ctx)
 {
 if (!ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
-gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
+gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU);
 return false;
 }
 
@@ -46,10 +46,10 @@ static bool spr_groupA_write_allowed(DisasContext *ctx)
 
 if (ctx->mmcr0_pmcc1) {
 /* PMCC = 0b01 */
-gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
+gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU);
 } else {
 /* PMCC = 0b00 */
-gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_REG);
 }
 
 return false;
@@ -214,7 +214,7 @@ void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int 
sprn)
  * Interrupt.
  */
 if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
-gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
+gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU);
 return;
 }
 
@@ -249,7 +249,7 @@ void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int 
gprn)
  * Interrupt.
  */
 if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
-gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
+gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU);
 return;
 }
 
-- 
2.25.1




[PATCH 1/6] target/ppc: Fix gen_priv_exception error value in mfspr/mtspr

2022-06-27 Thread Matheus Ferst
The code in linux-user/ppc/cpu_loop.c expects POWERPC_EXCP_PRIV
exception with error POWERPC_EXCP_PRIV_OPC or POWERPC_EXCP_PRIV_REG,
while POWERPC_EXCP_INVAL_SPR is expected in POWERPC_EXCP_INVAL
exceptions. This mismatch caused an EXCP_DUMP with the message "Unknown
privilege violation (03)", as seen in [1].

[1] https://gitlab.com/qemu-project/qemu/-/issues/588

Fixes: 9b2fadda3e01 ("ppc: Rework generation of priv and inval interrupts")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/588
Reviewed-by: Fabiano Rosas 
Signed-off-by: Matheus Ferst 
---
This patch was split from
https://lists.gnu.org/archive/html/qemu-ppc/2022-01/msg00400.html
---
 target/ppc/translate.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 1d6daa4608..55f34eb490 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -4789,11 +4789,11 @@ static inline void gen_op_mfspr(DisasContext *ctx)
  */
 if (sprn & 0x10) {
 if (ctx->pr) {
-gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG);
 }
 } else {
 if (ctx->pr || sprn == 0 || sprn == 4 || sprn == 5 || sprn == 6) {
-gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_REG);
 }
 }
 }
@@ -4976,11 +4976,11 @@ static void gen_mtspr(DisasContext *ctx)
  */
 if (sprn & 0x10) {
 if (ctx->pr) {
-gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG);
 }
 } else {
 if (ctx->pr || sprn == 0) {
-gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
+gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_REG);
 }
 }
 }
-- 
2.25.1




[PATCH 4/7] target/ppc: use int128.h methods in vaddcuq

2022-06-06 Thread Matheus Ferst
And also move the insn to decodetree.

Signed-off-by: Matheus Ferst 
---
 target/ppc/helper.h |  2 +-
 target/ppc/insn32.decode|  1 +
 target/ppc/int_helper.c | 12 ++--
 target/ppc/translate/vmx-impl.c.inc |  2 +-
 target/ppc/translate/vmx-ops.c.inc  |  1 -
 5 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index f699adbedc..f6b1b2fad2 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -207,7 +207,7 @@ DEF_HELPER_FLAGS_5(vsubuws, TCG_CALL_NO_RWG, void, avr, 
avr, avr, avr, i32)
 DEF_HELPER_FLAGS_3(VADDUQM, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_4(VADDECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
 DEF_HELPER_FLAGS_4(VADDEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
-DEF_HELPER_FLAGS_3(vaddcuq, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VADDCUQ, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_3(vsubuqm, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_4(vsubecuq, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
 DEF_HELPER_FLAGS_4(vsubeuqm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 139aa3caeb..35252ddd4f 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -550,6 +550,7 @@ VRLQNM  000100 . . . 00101000101@VX
 
 ## Vector Integer Arithmetic Instructions
 
+VADDCUQ 000100 . . . 0010100@VX
 VADDUQM 000100 . . . 001@VX
 
 VADDEUQM000100 . . . . 00   @VA
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index c5d820f4b1..a12f2831ac 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -2225,18 +2225,10 @@ void helper_VADDEUQM(ppc_avr_t *r, ppc_avr_t *a, 
ppc_avr_t *b, ppc_avr_t *c)
  int128_make64(int128_getlo(c->s128) & 1));
 }
 
-void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VADDCUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
 {
-#ifdef CONFIG_INT128
-r->u128 = (~a->u128 < b->u128);
-#else
-ppc_avr_t not_a;
-
-avr_qw_not(_a, *a);
-
+r->VsrD(1) = int128_ult(int128_not(a->s128), b->s128);
 r->VsrD(0) = 0;
-r->VsrD(1) = (avr_qw_cmpu(not_a, *b) < 0);
-#endif
 }
 
 void helper_VADDECUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
diff --git a/target/ppc/translate/vmx-impl.c.inc 
b/target/ppc/translate/vmx-impl.c.inc
index 4ec6b841b3..8c0e5bcc03 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -1234,7 +1234,6 @@ GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26);
 GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28);
 GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29);
 GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30);
-GEN_VXFORM(vaddcuq, 0, 5);
 GEN_VXFORM(vsubuqm, 0, 20);
 GEN_VXFORM(vsubcuq, 0, 21);
 GEN_VXFORM3(vsubeuqm, 31, 0);
@@ -3098,6 +3097,7 @@ static bool do_vx_helper(DisasContext *ctx, arg_VX *a,
 return true;
 }
 
+TRANS_FLAGS2(ALTIVEC_207, VADDCUQ, do_vx_helper, gen_helper_VADDCUQ)
 TRANS_FLAGS2(ALTIVEC_207, VADDUQM, do_vx_helper, gen_helper_VADDUQM)
 
 TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD)
diff --git a/target/ppc/translate/vmx-ops.c.inc 
b/target/ppc/translate/vmx-ops.c.inc
index f8a512f920..33e05929cb 100644
--- a/target/ppc/translate/vmx-ops.c.inc
+++ b/target/ppc/translate/vmx-ops.c.inc
@@ -126,7 +126,6 @@ GEN_VXFORM(vsubuws, 0, 26),
 GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300),
 GEN_VXFORM(vsubshs, 0, 29),
 GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_207(vaddcuq, 0, 5),
 GEN_VXFORM_DUAL(vsubuqm, bcdtrunc, 0, 20, PPC2_ALTIVEC_207, PPC2_ISA300),
 GEN_VXFORM_DUAL(vsubcuq, bcdutrunc, 0, 21, PPC2_ALTIVEC_207, PPC2_ISA300),
 GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
-- 
2.25.1




[PATCH 3/7] target/ppc: use int128.h methods in vaddecuq and vaddeuqm

2022-06-06 Thread Matheus Ferst
And also move the insns to decodetree and remove the now unused
avr_qw_addc method.

Signed-off-by: Matheus Ferst 
---
 target/ppc/helper.h |  4 +--
 target/ppc/insn32.decode|  3 ++
 target/ppc/int_helper.c | 53 +
 target/ppc/translate/vmx-impl.c.inc |  7 ++--
 target/ppc/translate/vmx-ops.c.inc  |  1 -
 5 files changed, 17 insertions(+), 51 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index c6fbe4b6da..f699adbedc 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -205,8 +205,8 @@ DEF_HELPER_FLAGS_5(vsububs, TCG_CALL_NO_RWG, void, avr, 
avr, avr, avr, i32)
 DEF_HELPER_FLAGS_5(vsubuhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
 DEF_HELPER_FLAGS_5(vsubuws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
 DEF_HELPER_FLAGS_3(VADDUQM, TCG_CALL_NO_RWG, void, avr, avr, avr)
-DEF_HELPER_FLAGS_4(vaddecuq, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
-DEF_HELPER_FLAGS_4(vaddeuqm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
+DEF_HELPER_FLAGS_4(VADDECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
+DEF_HELPER_FLAGS_4(VADDEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
 DEF_HELPER_FLAGS_3(vaddcuq, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_3(vsubuqm, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_4(vsubecuq, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index d6bfc2c768..139aa3caeb 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -552,6 +552,9 @@ VRLQNM  000100 . . . 00101000101@VX
 
 VADDUQM 000100 . . . 001@VX
 
+VADDEUQM000100 . . . . 00   @VA
+VADDECUQ000100 . . . . 01   @VA
+
 VEXTSB2W000100 . 1 . 1100010@VX_tb
 VEXTSH2W000100 . 10001 . 1100010@VX_tb
 VEXTSB2D000100 . 11000 . 1100010@VX_tb
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index c32b252639..c5d820f4b1 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -2212,16 +2212,6 @@ static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, 
ppc_avr_t b)
  (~a.VsrD(1) < b.VsrD(1));
 }
 
-static int avr_qw_addc(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
-{
-ppc_avr_t not_a;
-t->VsrD(1) = a.VsrD(1) + b.VsrD(1);
-t->VsrD(0) = a.VsrD(0) + b.VsrD(0) +
- (~a.VsrD(1) < b.VsrD(1));
-avr_qw_not(_a, a);
-return avr_qw_cmpu(not_a, b) < 0;
-}
-
 #endif
 
 void helper_VADDUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
@@ -2229,23 +2219,10 @@ void helper_VADDUQM(ppc_avr_t *r, ppc_avr_t *a, 
ppc_avr_t *b)
 r->s128 = int128_add(a->s128, b->s128);
 }
 
-void helper_vaddeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_VADDEUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
 {
-#ifdef CONFIG_INT128
-r->u128 = a->u128 + b->u128 + (c->u128 & 1);
-#else
-
-if (c->VsrD(1) & 1) {
-ppc_avr_t tmp;
-
-tmp.VsrD(0) = 0;
-tmp.VsrD(1) = c->VsrD(1) & 1;
-avr_qw_add(, *a, tmp);
-avr_qw_add(r, tmp, *b);
-} else {
-avr_qw_add(r, *a, *b);
-}
-#endif
+r->s128 = int128_add(int128_add(a->s128, b->s128),
+ int128_make64(int128_getlo(c->s128) & 1));
 }
 
 void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
@@ -2262,30 +2239,18 @@ void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, 
ppc_avr_t *b)
 #endif
 }
 
-void helper_vaddecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_VADDECUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
 {
-#ifdef CONFIG_INT128
-int carry_out = (~a->u128 < b->u128);
-if (!carry_out && (c->u128 & 1)) {
-carry_out = ((a->u128 + b->u128 + 1) == 0) &&
-((a->u128 != 0) || (b->u128 != 0));
-}
-r->u128 = carry_out;
-#else
-
-int carry_in = c->VsrD(1) & 1;
-int carry_out = 0;
-ppc_avr_t tmp;
-
-carry_out = avr_qw_addc(, *a, *b);
+bool carry_out = int128_ult(int128_not(a->s128), b->s128),
+ carry_in = int128_getlo(c->s128) & 1;
 
 if (!carry_out && carry_in) {
-ppc_avr_t one = QW_ONE;
-carry_out = avr_qw_addc(, tmp, one);
+carry_out = (int128_nz(a->s128) || int128_nz(b->s128)) &&
+int128_eq(int128_add(a->s128, b->s128), 
int128_makes64(-1));
 }
+
 r->VsrD(0) = 0;
 r->VsrD(1) = carry_out;
-#endif
 }
 
 void helper_vsubuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
diff --git a/target/ppc/translate/vmx-impl.c.inc 
b/target/ppc/translate/vmx-impl.c.inc
index 3fb48404d9..4ec6b841b3 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/tr

[PATCH 2/7] target/ppc: use int128.h methods in vadduqm

2022-06-06 Thread Matheus Ferst
And also move the insn to decodetree.

Signed-off-by: Matheus Ferst 
---
 target/ppc/helper.h | 2 +-
 target/ppc/insn32.decode| 2 ++
 target/ppc/int_helper.c | 8 ++--
 target/ppc/translate/vmx-impl.c.inc | 3 ++-
 target/ppc/translate/vmx-ops.c.inc  | 1 -
 5 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 39ad114c97..c6fbe4b6da 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -204,7 +204,7 @@ DEF_HELPER_FLAGS_5(vadduws, TCG_CALL_NO_RWG, void, avr, 
avr, avr, avr, i32)
 DEF_HELPER_FLAGS_5(vsububs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
 DEF_HELPER_FLAGS_5(vsubuhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
 DEF_HELPER_FLAGS_5(vsubuws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_3(vadduqm, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VADDUQM, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_4(vaddecuq, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
 DEF_HELPER_FLAGS_4(vaddeuqm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
 DEF_HELPER_FLAGS_3(vaddcuq, TCG_CALL_NO_RWG, void, avr, avr, avr)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 0772729c6e..d6bfc2c768 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -550,6 +550,8 @@ VRLQNM  000100 . . . 00101000101@VX
 
 ## Vector Integer Arithmetic Instructions
 
+VADDUQM 000100 . . . 001@VX
+
 VEXTSB2W000100 . 1 . 1100010@VX_tb
 VEXTSH2W000100 . 10001 . 1100010@VX_tb
 VEXTSB2D000100 . 11000 . 1100010@VX_tb
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 67aaa8edf5..c32b252639 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -2224,13 +2224,9 @@ static int avr_qw_addc(ppc_avr_t *t, ppc_avr_t a, 
ppc_avr_t b)
 
 #endif
 
-void helper_vadduqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VADDUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
 {
-#ifdef CONFIG_INT128
-r->u128 = a->u128 + b->u128;
-#else
-avr_qw_add(r, *a, *b);
-#endif
+r->s128 = int128_add(a->s128, b->s128);
 }
 
 void helper_vaddeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
diff --git a/target/ppc/translate/vmx-impl.c.inc 
b/target/ppc/translate/vmx-impl.c.inc
index 4c2a36405b..3fb48404d9 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -1234,7 +1234,6 @@ GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26);
 GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28);
 GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29);
 GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30);
-GEN_VXFORM(vadduqm, 0, 4);
 GEN_VXFORM(vaddcuq, 0, 5);
 GEN_VXFORM3(vaddeuqm, 30, 0);
 GEN_VXFORM3(vaddecuq, 30, 0);
@@ -3100,6 +3099,8 @@ static bool do_vx_helper(DisasContext *ctx, arg_VX *a,
 return true;
 }
 
+TRANS_FLAGS2(ALTIVEC_207, VADDUQM, do_vx_helper, gen_helper_VADDUQM)
+
 TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD)
 
 static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even,
diff --git a/target/ppc/translate/vmx-ops.c.inc 
b/target/ppc/translate/vmx-ops.c.inc
index 26c1d957ee..065b0ba414 100644
--- a/target/ppc/translate/vmx-ops.c.inc
+++ b/target/ppc/translate/vmx-ops.c.inc
@@ -126,7 +126,6 @@ GEN_VXFORM(vsubuws, 0, 26),
 GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300),
 GEN_VXFORM(vsubshs, 0, 29),
 GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_207(vadduqm, 0, 4),
 GEN_VXFORM_207(vaddcuq, 0, 5),
 GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
 GEN_VXFORM_DUAL(vsubuqm, bcdtrunc, 0, 20, PPC2_ALTIVEC_207, PPC2_ISA300),
-- 
2.25.1




[PATCH 7/7] target/ppc: use int128.h methods in vsubcuq

2022-06-06 Thread Matheus Ferst
And also move the insn to decodetree and remove the now unused
avr_qw_not, avr_qw_cmpu, and avr_qw_add methods.

Signed-off-by: Matheus Ferst 
---
 target/ppc/helper.h |  2 +-
 target/ppc/insn32.decode|  1 +
 target/ppc/int_helper.c | 51 +++--
 target/ppc/translate/vmx-impl.c.inc |  5 +--
 target/ppc/translate/vmx-ops.c.inc  |  2 +-
 5 files changed, 9 insertions(+), 52 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 04ced6ef70..84a41d85b0 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -211,7 +211,7 @@ DEF_HELPER_FLAGS_3(VADDCUQ, TCG_CALL_NO_RWG, void, avr, 
avr, avr)
 DEF_HELPER_FLAGS_3(VSUBUQM, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_4(VSUBECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
 DEF_HELPER_FLAGS_4(VSUBEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
-DEF_HELPER_FLAGS_3(vsubcuq, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VSUBCUQ, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_4(vsldoi, TCG_CALL_NO_RWG, void, avr, avr, avr, i32)
 DEF_HELPER_FLAGS_3(vextractub, TCG_CALL_NO_RWG, void, avr, avr, i32)
 DEF_HELPER_FLAGS_3(vextractuh, TCG_CALL_NO_RWG, void, avr, avr, i32)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 5e6f3b668e..65a6a42f78 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -556,6 +556,7 @@ VADDUQM 000100 . . . 001@VX
 VADDEUQM000100 . . . . 00   @VA
 VADDECUQ000100 . . . . 01   @VA
 
+VSUBCUQ 000100 . . . 1010100@VX
 VSUBUQM 000100 . . . 101@VX
 
 VSUBECUQ000100 . . . . 11   @VA
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index c995f8de77..f1a9fbf0c5 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -2176,38 +2176,6 @@ VGENERIC_DO(popcntd, u64)
 
 #undef VGENERIC_DO
 
-#ifndef CONFIG_INT128
-
-static inline void avr_qw_not(ppc_avr_t *t, ppc_avr_t a)
-{
-t->u64[0] = ~a.u64[0];
-t->u64[1] = ~a.u64[1];
-}
-
-static int avr_qw_cmpu(ppc_avr_t a, ppc_avr_t b)
-{
-if (a.VsrD(0) < b.VsrD(0)) {
-return -1;
-} else if (a.VsrD(0) > b.VsrD(0)) {
-return 1;
-} else if (a.VsrD(1) < b.VsrD(1)) {
-return -1;
-} else if (a.VsrD(1) > b.VsrD(1)) {
-return 1;
-} else {
-return 0;
-}
-}
-
-static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
-{
-t->VsrD(1) = a.VsrD(1) + b.VsrD(1);
-t->VsrD(0) = a.VsrD(0) + b.VsrD(0) +
- (~a.VsrD(1) < b.VsrD(1));
-}
-
-#endif
-
 void helper_VADDUQM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
 {
 r->s128 = int128_add(a->s128, b->s128);
@@ -2250,22 +2218,13 @@ void helper_VSUBEUQM(ppc_avr_t *r, ppc_avr_t *a, 
ppc_avr_t *b, ppc_avr_t *c)
  int128_make64(int128_getlo(c->s128) & 1));
 }
 
-void helper_vsubcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VSUBCUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
 {
-#ifdef CONFIG_INT128
-r->u128 = (~a->u128 < ~b->u128) ||
- (a->u128 + ~b->u128 == (__uint128_t)-1);
-#else
-int carry = (avr_qw_cmpu(*a, *b) > 0);
-if (!carry) {
-ppc_avr_t tmp;
-avr_qw_not(, *b);
-avr_qw_add(, *a, tmp);
-carry = ((tmp.VsrSD(0) == -1ull) && (tmp.VsrSD(1) == -1ull));
-}
+Int128 tmp = int128_not(b->s128);
+
+r->VsrD(1) = int128_ult(int128_not(a->s128), tmp) ||
+ int128_eq(int128_add(a->s128, tmp), int128_makes64(-1));
 r->VsrD(0) = 0;
-r->VsrD(1) = carry;
-#endif
 }
 
 void helper_VSUBECUQ(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
diff --git a/target/ppc/translate/vmx-impl.c.inc 
b/target/ppc/translate/vmx-impl.c.inc
index 671992f7d1..e644ad3236 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -1234,7 +1234,6 @@ GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26);
 GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28);
 GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29);
 GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30);
-GEN_VXFORM(vsubcuq, 0, 21);
 GEN_VXFORM_TRANS(vsl, 2, 7);
 GEN_VXFORM_TRANS(vsr, 2, 11);
 GEN_VXFORM_ENV(vpkuhum, 7, 0);
@@ -2856,9 +2855,6 @@ GEN_VXFORM_DUAL(vsubuwm, PPC_ALTIVEC, PPC_NONE, \
 bcdus, PPC_NONE, PPC2_ISA300)
 GEN_VXFORM_DUAL(vsubsbs, PPC_ALTIVEC, PPC_NONE, \
 bcdtrunc, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM_DUAL(vsubcuq, PPC2_ALTIVEC_207, PPC_NONE, \
-bcdutrunc, PPC_NONE, PPC2_ISA300)
-
 
 static void gen_vsbox(DisasContext *ctx)
 {
@@ -3098,6 +3094,7 @@ TRANS_FLAGS2(ALTIVEC_207, VADDUQM, do_vx_helper, 
gen_helper_VADDUQM)
 
 TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD)
 
+TRAN

[PATCH 1/7] target/ppc: use int128.h methods in vpmsumd

2022-06-06 Thread Matheus Ferst
Also drop VECTOR_FOR_INORDER_I usage since there is no need to access
the elements in any particular order, and move the instruction to
decodetree.

Signed-off-by: Matheus Ferst 
---
 target/ppc/helper.h |  2 +-
 target/ppc/insn32.decode|  4 +++
 target/ppc/int_helper.c | 46 ++---
 target/ppc/translate/vmx-impl.c.inc |  3 +-
 target/ppc/translate/vmx-ops.c.inc  |  1 -
 5 files changed, 16 insertions(+), 40 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index d627cfe6ed..39ad114c97 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -318,7 +318,7 @@ DEF_HELPER_FLAGS_3(vbpermq, TCG_CALL_NO_RWG, void, avr, 
avr, avr)
 DEF_HELPER_FLAGS_3(vpmsumb, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_3(vpmsumh, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_3(vpmsumw, TCG_CALL_NO_RWG, void, avr, avr, avr)
-DEF_HELPER_FLAGS_3(vpmsumd, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VPMSUMD, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_2(vextublx, TCG_CALL_NO_RWG, tl, tl, avr)
 DEF_HELPER_FLAGS_2(vextuhlx, TCG_CALL_NO_RWG, tl, tl, avr)
 DEF_HELPER_FLAGS_2(vextuwlx, TCG_CALL_NO_RWG, tl, tl, avr)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 6ea48d5163..0772729c6e 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -426,6 +426,10 @@ DSCLIQ  11 . . .. 00110 .   
@Z22_tap_sh_rc
 DSCRI   111011 . . .. 001100010 .   @Z22_ta_sh_rc
 DSCRIQ  11 . . .. 001100010 .   @Z22_tap_sh_rc
 
+## Vector Exclusive-OR-based Instructions
+
+VPMSUMD 000100 . . . 10011001000@VX
+
 ## Vector Integer Instructions
 
 VCMPEQUB000100 . . . . 000110   @VC
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 16357c0900..67aaa8edf5 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -1484,52 +1484,24 @@ PMSUM(vpmsumb, u8, u16, uint16_t)
 PMSUM(vpmsumh, u16, u32, uint32_t)
 PMSUM(vpmsumw, u32, u64, uint64_t)
 
-void helper_vpmsumd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_VPMSUMD(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
 {
-
-#ifdef CONFIG_INT128
 int i, j;
-__uint128_t prod[2];
+Int128 tmp, prod[2] = {int128_zero(), int128_zero()};
 
-VECTOR_FOR_INORDER_I(i, u64) {
-prod[i] = 0;
-for (j = 0; j < 64; j++) {
-if (a->u64[i] & (1ull << j)) {
-prod[i] ^= (((__uint128_t)b->u64[i]) << j);
+for (j = 0; j < 64; j++) {
+for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
+if (a->VsrD(i) & (1ull << j)) {
+tmp = int128_make64(b->VsrD(i));
+tmp = int128_lshift(tmp, j);
+prod[i] = int128_xor(prod[i], tmp);
 }
 }
 }
 
-r->u128 = prod[0] ^ prod[1];
-
-#else
-int i, j;
-ppc_avr_t prod[2];
-
-VECTOR_FOR_INORDER_I(i, u64) {
-prod[i].VsrD(1) = prod[i].VsrD(0) = 0;
-for (j = 0; j < 64; j++) {
-if (a->u64[i] & (1ull << j)) {
-ppc_avr_t bshift;
-if (j == 0) {
-bshift.VsrD(0) = 0;
-bshift.VsrD(1) = b->u64[i];
-} else {
-bshift.VsrD(0) = b->u64[i] >> (64 - j);
-bshift.VsrD(1) = b->u64[i] << j;
-}
-prod[i].VsrD(1) ^= bshift.VsrD(1);
-prod[i].VsrD(0) ^= bshift.VsrD(0);
-}
-}
-}
-
-r->VsrD(1) = prod[0].VsrD(1) ^ prod[1].VsrD(1);
-r->VsrD(0) = prod[0].VsrD(0) ^ prod[1].VsrD(0);
-#endif
+r->s128 = int128_xor(prod[0], prod[1]);
 }
 
-
 #if HOST_BIG_ENDIAN
 #define PKBIG 1
 #else
diff --git a/target/ppc/translate/vmx-impl.c.inc 
b/target/ppc/translate/vmx-impl.c.inc
index 0b563bed37..4c2a36405b 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -2717,7 +2717,6 @@ GEN_VXFORM_TRANS(vgbbd, 6, 20);
 GEN_VXFORM(vpmsumb, 4, 16)
 GEN_VXFORM(vpmsumh, 4, 17)
 GEN_VXFORM(vpmsumw, 4, 18)
-GEN_VXFORM(vpmsumd, 4, 19)
 
 #define GEN_BCD(op) \
 static void gen_##op(DisasContext *ctx) \
@@ -3101,6 +3100,8 @@ static bool do_vx_helper(DisasContext *ctx, arg_VX *a,
 return true;
 }
 
+TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD)
+
 static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even,
  void (*gen_mul)(TCGv_i64, TCGv_i64, TCGv_i64, 
TCGv_i64))
 {
diff --git a/target/ppc/translate/vmx-ops.c.inc 
b/target/ppc/translate/vmx-ops.c.inc
index d7cc57868e..26c1d957ee 100644
--- a/target/ppc/translate/vmx-ops.c.inc
+++ b/target/ppc/translate/vmx-ops.c.inc
@@ -237,7 +237,6 @@ GEN_VXFORM_207(vgbbd, 6, 20),
 GEN_VXFORM_207(vpmsumb

  1   2   3   4   5   6   7   >