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