PPC CPU has TYPE_INTERRUPT_STATS_PROVIDER interface but it does not
implement the print_info function. This causes 'info pic' to print
a line like:

    Interrupt controller information not available for
    power10_v2.0-powerpc64-cpu.

Add a print_info panel for CPUs with irq delivery status.

Signed-off-by: Nicholas Piggin <npig...@gmail.com>
---
 target/ppc/cpu.h         |   3 +
 target/ppc/cpu_init.c    |   1 +
 target/ppc/excp_helper.c | 116 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 120 insertions(+)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index ff14f5b8a7f..dca84ca23cd 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -27,6 +27,7 @@
 #include "cpu-qom.h"
 #include "qom/object.h"
 #include "hw/registerfields.h"
+#include "hw/intc/intc.h"
 
 #define CPU_RESOLVING_TYPE TYPE_POWERPC_CPU
 
@@ -1604,6 +1605,7 @@ int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, 
CPUState *cs,
 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_irq_print_info(InterruptStatsProvider *obj, GString *buf);
 void ppc_cpu_do_system_reset(CPUState *cs);
 void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector);
 extern const VMStateDescription vmstate_ppc_cpu;
@@ -2686,6 +2688,7 @@ enum {
 #endif
 
 /* Hardware exceptions definitions */
+/* Keep powerpc_intr_name in sync */
 enum {
     /* External hardware exception sources */
     PPC_INTERRUPT_RESET     = 0x00001,  /* Reset exception                    
*/
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index b3d6599abd2..36742136309 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7527,6 +7527,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void 
*data)
 #ifndef CONFIG_USER_ONLY
     cc->sysemu_ops = &ppc_sysemu_ops;
     INTERRUPT_STATS_PROVIDER_CLASS(oc)->get_statistics = ppc_get_irq_stats;
+    INTERRUPT_STATS_PROVIDER_CLASS(oc)->print_info = ppc_cpu_irq_print_info;
 
     /* check_prot_access_type relies on MMU access and PAGE bits relations */
     qemu_build_assert(MMU_DATA_LOAD == 0 && MMU_DATA_STORE == 1 &&
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 1890ec9ccb6..7ea5798e95b 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -104,6 +104,49 @@ static const char *powerpc_excp_name(int excp)
     }
 }
 
+static const char *powerpc_intr_name(uint32_t intr)
+{
+    switch (intr) {
+    case PPC_INTERRUPT_RESET:      return "RSET";
+    case PPC_INTERRUPT_WAKEUP:     return "WAKE";
+    case PPC_INTERRUPT_MCK:        return "MCHK";
+    case PPC_INTERRUPT_EXT:        return "EXTN";
+    case PPC_INTERRUPT_SMI:        return "SMI";
+    case PPC_INTERRUPT_CEXT:       return "CEXT";
+    case PPC_INTERRUPT_DEBUG:      return "DEBG";
+    case PPC_INTERRUPT_THERM:      return "THRM";
+    case PPC_INTERRUPT_DECR:       return "DECR";
+    case PPC_INTERRUPT_HDECR:      return "HDEC";
+    case PPC_INTERRUPT_PIT:        return "PIT";
+    case PPC_INTERRUPT_FIT:        return "FIT";
+    case PPC_INTERRUPT_WDT:        return "WDT";
+    case PPC_INTERRUPT_CDOORBELL:  return "CDBL";
+    case PPC_INTERRUPT_DOORBELL:   return "DBL";
+    case PPC_INTERRUPT_PERFM:      return "PMU";
+    case PPC_INTERRUPT_HMI:        return "HMI";
+    case PPC_INTERRUPT_HDOORBELL:  return "HDBL";
+    case PPC_INTERRUPT_HVIRT:      return "HVRT";
+    case PPC_INTERRUPT_EBB:        return "EBB";
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static bool powerpc_is_hv_intr(uint32_t intr)
+{
+    switch (intr) {
+    case PPC_INTERRUPT_RESET:
+    case PPC_INTERRUPT_MCK:
+    case PPC_INTERRUPT_HDECR:
+    case PPC_INTERRUPT_HMI:
+    case PPC_INTERRUPT_HDOORBELL:
+    case PPC_INTERRUPT_HVIRT:
+        return true;
+    default:
+        return false;
+    }
+}
+
 static void dump_syscall(CPUPPCState *env)
 {
     qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
@@ -2438,6 +2481,79 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int 
interrupt)
     }
 }
 
+void ppc_cpu_irq_print_info(InterruptStatsProvider *obj, GString *buf)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(obj);
+    CPUPPCState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
+    const char *priv1 = "";
+    const char *priv2;
+    bool none;
+    int i;
+
+    g_string_append_printf(buf, "CPU[%x] interrupt info\n", cs->cpu_index);
+
+    g_string_append_printf(buf, "    state:%s",
+                           cs->halted ? "stopped" : "running");
+    if (env->resume_as_sreset) {
+        g_string_append_printf(buf, "(wake with sreset)");
+    }
+
+    if (FIELD_EX64(env->msr, MSR, PR)) {
+        priv2 = "user";
+    } else {
+        priv2 = "privileged";
+    }
+    if (env->has_hv_mode) {
+        if (FIELD_EX64_HV(env->msr)) {
+            priv1 = "host-";
+        } else {
+            priv1 = "guest-";
+        }
+    }
+    g_string_append_printf(buf, " mode:%s%s\n", priv1, priv2);
+
+    if (env->has_hv_mode) {
+        g_string_append_printf(buf, "    hypervisor irqs:%s\n",
+                !FIELD_EX64_HV(env->msr) || FIELD_EX64(env->msr, MSR, EE) ?
+                    "enabled" : "disabled");
+    }
+    g_string_append_printf(buf, "    supervisor irqs:%s\n",
+            FIELD_EX64(env->msr, MSR, EE) ? "enabled" : "disabled");
+
+    if (env->has_hv_mode) {
+        none = true;
+        g_string_append_printf(buf, "    pending hypervisor interrupts: ");
+        for (i = 0; i < 32; i++) {
+            uint32_t intr = (1U << i);
+            if (powerpc_is_hv_intr(intr) && (env->pending_interrupts & intr)) {
+                none = false;
+                g_string_append_printf(buf, "%s ", powerpc_intr_name(intr));
+            }
+        }
+        if (none) {
+            g_string_append_printf(buf, "none\n");
+        } else {
+            g_string_append_printf(buf, "\n");
+        }
+    }
+
+    none = true;
+    g_string_append_printf(buf, "    pending supervisor interrupts: ");
+    for (i = 0; i < 32; i++) {
+        uint32_t intr = (1U << i);
+        if (!powerpc_is_hv_intr(intr) && (env->pending_interrupts & intr)) {
+            none = false;
+            g_string_append_printf(buf, "%s ", powerpc_intr_name(intr));
+        }
+    }
+    if (none) {
+        g_string_append_printf(buf, "none\n");
+    } else {
+        g_string_append_printf(buf, "\n");
+    }
+}
+
 /*
  * system reset is not delivered via normal irq method, so have to set
  * halted = 0 to resume CPU running if it was halted. Possibly we should
-- 
2.47.1


Reply via email to