diff mbox series

[RFC,v2,12/12] target/ppc: Do not enable all interrupts when running KVM

Message ID 20211220181903.3456898-13-farosas@linux.ibm.com
State Superseded
Headers show
Series target/ppc: powerpc_excp improvements | expand

Commit Message

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

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

Patch

diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
index 6f956029fd..be2755b1a8 100644
--- a/target/ppc/interrupts.c
+++ b/target/ppc/interrupts.c
@@ -11,7 +11,9 @@ 
 #include "cpu.h"
 #include "ppc_intr.h"
 #include "trace.h"
+#include "sysemu/kvm.h"
 
+#ifdef CONFIG_TCG
 /* for hreg_swap_gpr_tgpr */
 #include "helper_regs.h"
 
@@ -43,56 +45,6 @@  void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     }
 }
 
-void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    CPUState *cs = CPU(cpu);
-    CPUPPCState *env = &cpu->env;
-    int excp_model = env->excp_model;
-
-    if (msr_me == 0) {
-        /*
-         * Machine check exception is not enabled.  Enter
-         * checkstop state.
-         */
-        fprintf(stderr, "Machine check while not allowed. "
-                "Entering checkstop state\n");
-        if (qemu_log_separate()) {
-            qemu_log("Machine check while not allowed. "
-                     "Entering checkstop state\n");
-        }
-        cs->halted = 1;
-        cpu_interrupt_exittb(cs);
-    }
-    if (env->msr_mask & MSR_HVB) {
-        /*
-         * ISA specifies HV, but can be delivered to guest with HV
-         * clear (e.g., see FWNMI in PAPR).
-         */
-        regs->new_msr |= (target_ulong)MSR_HVB;
-    }
-
-    /* machine check exceptions don't have ME set */
-    regs->new_msr &= ~((target_ulong)1 << MSR_ME);
-
-    /* XXX: should also have something loaded in DAR / DSISR */
-    switch (excp_model) {
-    case POWERPC_EXCP_40x:
-        regs->sprn_srr0 = SPR_40x_SRR2;
-        regs->sprn_srr1 = SPR_40x_SRR3;
-        break;
-    case POWERPC_EXCP_BOOKE:
-        /* FIXME: choose one or the other based on CPU type */
-        regs->sprn_srr0 = SPR_BOOKE_MCSRR0;
-        regs->sprn_srr1 = SPR_BOOKE_MCSRR1;
-
-        env->spr[SPR_BOOKE_CSRR0] = regs->nip;
-        env->spr[SPR_BOOKE_CSRR1] = regs->msr;
-        break;
-    default:
-        break;
-    }
-}
-
 void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
     CPUPPCState *env = &cpu->env;
@@ -165,51 +117,6 @@  void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
 }
 
-void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    CPUState *cs = CPU(cpu);
-    CPUPPCState *env = &cpu->env;
-
-    switch (env->error_code & ~0xF) {
-    case POWERPC_EXCP_FP:
-        if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
-            trace_ppc_excp_fp_ignore();
-            cs->exception_index = POWERPC_EXCP_NONE;
-            env->error_code = 0;
-
-            *ignore = true;
-            return;
-        }
-
-        /*
-         * FP exceptions always have NIP pointing to the faulting
-         * instruction, so always use store_next and claim we are
-         * precise in the MSR.
-         */
-        regs->msr |= 0x00100000;
-        env->spr[SPR_BOOKE_ESR] = ESR_FP;
-        break;
-    case POWERPC_EXCP_INVAL:
-        trace_ppc_excp_inval(regs->nip);
-        regs->msr |= 0x00080000;
-        env->spr[SPR_BOOKE_ESR] = ESR_PIL;
-        break;
-    case POWERPC_EXCP_PRIV:
-        regs->msr |= 0x00040000;
-        env->spr[SPR_BOOKE_ESR] = ESR_PPR;
-        break;
-    case POWERPC_EXCP_TRAP:
-        regs->msr |= 0x00020000;
-        env->spr[SPR_BOOKE_ESR] = ESR_PTR;
-        break;
-    default:
-        /* Should never occur */
-        cpu_abort(cs, "Invalid program exception %d. Aborting\n",
-                  env->error_code);
-        break;
-    }
-}
-
 static inline void dump_syscall(CPUPPCState *env)
 {
     qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
@@ -334,30 +241,6 @@  void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
     env->spr[SPR_BOOKE_ESR] = ESR_SPV;
 }
 
-void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
-{
-    CPUPPCState *env = &cpu->env;
-
-    /* A power-saving exception sets ME, otherwise it is unchanged */
-    if (msr_pow) {
-        /* indicate that we resumed from power save mode */
-        regs->msr |= 0x10000;
-        regs->new_msr |= ((target_ulong)1 << MSR_ME);
-    }
-    if (env->msr_mask & MSR_HVB) {
-        /*
-         * ISA specifies HV, but can be delivered to guest with HV
-         * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
-         */
-        regs->new_msr |= (target_ulong)MSR_HVB;
-    } else {
-        if (msr_pow) {
-            cpu_abort(CPU(cpu), "Trying to deliver power-saving system reset "
-                      "exception with no HV support\n");
-        }
-    }
-}
-
 #ifdef TARGET_PPC64
 void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
 {
@@ -455,6 +338,149 @@  void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
         break;
     }
 }
+#endif /* CONFIG_TCG */
+
+void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    int excp_model = env->excp_model;
+
+    if (msr_me == 0) {
+        /*
+         * Machine check exception is not enabled.  Enter
+         * checkstop state.
+         */
+        fprintf(stderr, "Machine check while not allowed. "
+                "Entering checkstop state\n");
+        if (qemu_log_separate()) {
+            qemu_log("Machine check while not allowed. "
+                     "Entering checkstop state\n");
+        }
+        cs->halted = 1;
+#if defined(CONFIG_TCG)
+        cpu_interrupt_exittb(cs);
+#endif
+    }
+    if (env->msr_mask & MSR_HVB) {
+        /*
+         * ISA specifies HV, but can be delivered to guest with HV
+         * clear (e.g., see FWNMI in PAPR).
+         */
+        regs->new_msr |= (target_ulong)MSR_HVB;
+    }
+
+    /* machine check exceptions don't have ME set */
+    regs->new_msr &= ~((target_ulong)1 << MSR_ME);
+
+    /* XXX: should also have something loaded in DAR / DSISR */
+    switch (excp_model) {
+    case POWERPC_EXCP_40x:
+        regs->sprn_srr0 = SPR_40x_SRR2;
+        regs->sprn_srr1 = SPR_40x_SRR3;
+        break;
+    case POWERPC_EXCP_BOOKE:
+        /* FIXME: choose one or the other based on CPU type */
+        regs->sprn_srr0 = SPR_BOOKE_MCSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_MCSRR1;
+
+        env->spr[SPR_BOOKE_CSRR0] = regs->nip;
+        env->spr[SPR_BOOKE_CSRR1] = regs->msr;
+        break;
+    default:
+        break;
+    }
+}
+
+void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    switch (env->error_code & ~0xF) {
+    case POWERPC_EXCP_FP:
+        if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+            trace_ppc_excp_fp_ignore();
+            cs->exception_index = POWERPC_EXCP_NONE;
+            env->error_code = 0;
+
+            *ignore = true;
+            return;
+        }
+
+        /*
+         * FP exceptions always have NIP pointing to the faulting
+         * instruction, so always use store_next and claim we are
+         * precise in the MSR.
+         */
+        regs->msr |= 0x00100000;
+        env->spr[SPR_BOOKE_ESR] = ESR_FP;
+        break;
+    case POWERPC_EXCP_INVAL:
+        trace_ppc_excp_inval(regs->nip);
+        regs->msr |= 0x00080000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PIL;
+        break;
+    case POWERPC_EXCP_PRIV:
+        regs->msr |= 0x00040000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PPR;
+        break;
+    case POWERPC_EXCP_TRAP:
+        regs->msr |= 0x00020000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PTR;
+        break;
+    default:
+        /* Should never occur */
+        cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+                  env->error_code);
+        break;
+    }
+}
+
+void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    /* A power-saving exception sets ME, otherwise it is unchanged */
+    if (msr_pow) {
+        /* indicate that we resumed from power save mode */
+        regs->msr |= 0x10000;
+        regs->new_msr |= ((target_ulong)1 << MSR_ME);
+    }
+    if (env->msr_mask & MSR_HVB) {
+        /*
+         * ISA specifies HV, but can be delivered to guest with HV
+         * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
+         */
+        regs->new_msr |= (target_ulong)MSR_HVB;
+    } else {
+        if (msr_pow) {
+            cpu_abort(CPU(cpu), "Trying to deliver power-saving system reset "
+                      "exception with no HV support\n");
+        }
+    }
+}
+
+/*
+ * Book3S and BookE support KVM, but QEMU only dispatches a small
+ * set of interrupts in very specific ocasions. All other
+ * interrupts are dispatched by the real harware and QEMU knows
+ * nothing about them.
+ */
+PPCInterrupt interrupts_kvm[POWERPC_EXCP_NB] = {
+
+    [POWERPC_EXCP_MCHECK] = {
+        "Machine check", ppc_intr_machine_check
+    },
+
+    [POWERPC_EXCP_PROGRAM] = {
+        "Program", ppc_intr_program
+    },
+
+    [POWERPC_EXCP_RESET] = {
+        "System reset", ppc_intr_system_reset
+    },
+};
 
 int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
                      PPCIntrArgs *regs, int excp)
@@ -464,6 +490,10 @@  int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
     PPCInterrupt *intr;
     bool ignore = false;
 
+    if (kvm_enabled()) {
+        interrupts = interrupts_kvm;
+    }
+
     intr = &interrupts[excp];
     if (!intr->name) {
         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
diff --git a/target/ppc/intr-book3s.c b/target/ppc/intr-book3s.c
index cd279de346..a475c668ed 100644
--- a/target/ppc/intr-book3s.c
+++ b/target/ppc/intr-book3s.c
@@ -11,6 +11,7 @@ 
 #include "ppc_intr.h"
 
 static PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = {
+#ifdef CONFIG_TCG
     [POWERPC_EXCP_ALIGN] = {
         "Alignment", ppc_intr_alignment
     },
@@ -88,6 +89,7 @@  static PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = {
     [POWERPC_EXCP_SDOOR]    = { "Server doorbell" },
     [POWERPC_EXCP_THERM]    = { "Thermal management" },
     [POWERPC_EXCP_VPUA]     = { "Vector assist" },
+#endif
 };
 
 static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
diff --git a/target/ppc/intr-booke.c b/target/ppc/intr-booke.c
index 598d372069..9297b14ed6 100644
--- a/target/ppc/intr-booke.c
+++ b/target/ppc/intr-booke.c
@@ -11,6 +11,7 @@ 
 #include "ppc_intr.h"
 
 static PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = {
+#ifdef CONFIG_TCG
     [POWERPC_EXCP_ALIGN] = {
         "Alignment", ppc_intr_alignment
     },
@@ -76,6 +77,7 @@  static PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = {
 /* Not impleemented */
     [POWERPC_EXCP_EFPDI]    = { "Embedded floating-point data" },
     [POWERPC_EXCP_EFPRI]    = { "Embedded floating-point round" },
+#endif
 };
 
 void booke_excp(PowerPCCPU *cpu, int excp)
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
index a0362f4248..4aab37ea28 100644
--- a/target/ppc/ppc_intr.h
+++ b/target/ppc/ppc_intr.h
@@ -19,6 +19,7 @@  struct PPCInterrupt {
     ppc_intr_fn_t fn;
 };
 
+#ifdef CONFIG_TCG
 void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
@@ -28,14 +29,11 @@  void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_noop(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_programmable_timer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_system_call(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
@@ -43,7 +41,13 @@  void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
-#endif
+#endif /* TARGET_PPC64 */
+
+#endif /* CONFIG_TCG */
+
+void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
 
 int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts,
                      PPCIntrArgs *regs, int excp);