Like commit 9cb805fd26 ("cpus: Define callback for QEMU "nmi" command") this implements a machine check injection command framework and defines a monitor command for ppc.
Signed-off-by: Nicholas Piggin <npig...@gmail.com> --- include/hw/nmi.h | 20 ++++++++++++ include/monitor/hmp-target.h | 1 - include/monitor/hmp.h | 1 + hw/core/nmi.c | 61 ++++++++++++++++++++++++++++++++++++ monitor/hmp-cmds.c | 1 + target/ppc/ppc-qmp-cmds.c | 10 ++++++ hmp-commands.hx | 20 +++++++++++- 7 files changed, 112 insertions(+), 2 deletions(-) diff --git a/include/hw/nmi.h b/include/hw/nmi.h index fff41bebc6..09f9ca122a 100644 --- a/include/hw/nmi.h +++ b/include/hw/nmi.h @@ -42,4 +42,24 @@ struct NMIClass { void nmi_monitor_handle(int cpu_index, Error **errp); + +#define TYPE_MCE "mce" + +#define MCE_CLASS(klass) \ + OBJECT_CLASS_CHECK(MCEClass, (klass), TYPE_MCE) +#define MCE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(MCEClass, (obj), TYPE_MCE) +#define MCE(obj) \ + INTERFACE_CHECK(MCEState, (obj), TYPE_MCE) + +typedef struct MCEState MCEState; + +typedef struct MCEClass { + InterfaceClass parent_class; + + void (*mce_monitor_handler)(MCEState *n, const QDict *qdict, Error **errp); +} MCEClass; + +void mce_monitor_handle(const QDict *qdict, Error **errp); + #endif /* NMI_H */ diff --git a/include/monitor/hmp-target.h b/include/monitor/hmp-target.h index d78e979f05..dec6dba8e5 100644 --- a/include/monitor/hmp-target.h +++ b/include/monitor/hmp-target.h @@ -46,7 +46,6 @@ CPUState *mon_get_cpu(Monitor *mon); void hmp_info_mem(Monitor *mon, const QDict *qdict); void hmp_info_tlb(Monitor *mon, const QDict *qdict); -void hmp_mce(Monitor *mon, const QDict *qdict); void hmp_info_local_apic(Monitor *mon, const QDict *qdict); void hmp_info_sev(Monitor *mon, const QDict *qdict); void hmp_info_sgx(Monitor *mon, const QDict *qdict); diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 13f9a2dedb..fe14a855a0 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -56,6 +56,7 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict); void hmp_cont(Monitor *mon, const QDict *qdict); void hmp_system_wakeup(Monitor *mon, const QDict *qdict); void hmp_nmi(Monitor *mon, const QDict *qdict); +void hmp_mce(Monitor *mon, const QDict *qdict); void hmp_info_network(Monitor *mon, const QDict *qdict); void hmp_set_link(Monitor *mon, const QDict *qdict); void hmp_balloon(Monitor *mon, const QDict *qdict); diff --git a/hw/core/nmi.c b/hw/core/nmi.c index a7bce8a04a..d653f054eb 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -85,3 +85,64 @@ static void nmi_register_types(void) } type_init(nmi_register_types) + +struct do_mce_s { + const QDict *qdict; + Error *err; + bool handled; +}; + +static void mce_children(Object *o, struct do_mce_s *ns); + +static int do_mce(Object *o, void *opaque) +{ + struct do_mce_s *ms = opaque; + MCEState *m = (MCEState *) object_dynamic_cast(o, TYPE_MCE); + + if (m) { + MCEClass *mc = MCE_GET_CLASS(m); + + ms->handled = true; + mc->mce_monitor_handler(m, ms->qdict, &ms->err); + if (ms->err) { + return -1; + } + } + mce_children(o, ms); + + return 0; +} + +static void mce_children(Object *o, struct do_mce_s *ms) +{ + object_child_foreach(o, do_mce, ms); +} + +void mce_monitor_handle(const QDict *qdict, Error **errp) +{ + struct do_mce_s ms = { + .qdict = qdict, + .err = NULL, + .handled = false + }; + + mce_children(object_get_root(), &ms); + if (ms.handled) { + error_propagate(errp, ms.err); + } else { + error_setg(errp, "machine does not provide MCEs"); + } +} + +static const TypeInfo mce_info = { + .name = TYPE_MCE, + .parent = TYPE_INTERFACE, + .class_size = sizeof(MCEClass), +}; + +static void mce_register_types(void) +{ + type_register_static(&mce_info); +} + +type_init(mce_register_types) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 871898ac46..0e46c107b6 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -28,6 +28,7 @@ #include "hw/intc/intc.h" #include "qemu/log.h" #include "sysemu/sysemu.h" +#include "hw/nmi.h" bool hmp_handle_error(Monitor *mon, Error *err) { diff --git a/target/ppc/ppc-qmp-cmds.c b/target/ppc/ppc-qmp-cmds.c index ee0b99fce7..43fa5980d2 100644 --- a/target/ppc/ppc-qmp-cmds.c +++ b/target/ppc/ppc-qmp-cmds.c @@ -31,6 +31,7 @@ #include "qapi/qapi-commands-machine-target.h" #include "cpu-models.h" #include "cpu-qom.h" +#include "hw/nmi.h" static target_long monitor_get_ccr(Monitor *mon, const struct MonitorDef *md, int val) @@ -91,6 +92,15 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) dump_mmu(env1); } +void hmp_mce(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + + mce_monitor_handle(qdict, &err); + + hmp_handle_error(mon, err); +} + const MonitorDef monitor_defs[] = { { "fpscr", offsetof(CPUPPCState, fpscr) }, /* Next instruction pointer */ diff --git a/hmp-commands.hx b/hmp-commands.hx index 765349ed14..384cf5d0c4 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1509,12 +1509,30 @@ ERST .cmd = hmp_mce, }, -#endif SRST ``mce`` *cpu* *bank* *status* *mcgstatus* *addr* *misc* Inject an MCE on the given CPU (x86 only). ERST +#endif + +#if defined(TARGET_PPC) + + { + .name = "mce", + .args_type = "cpu_index:i,srr1_mask:l,dsisr:i,dar:l,recovered:i", + .params = "cpu srr1_mask dsisr dar recovered", + .help = "inject a MCE on the given CPU", + .cmd = hmp_mce, + }, + +SRST +``mce`` *cpu* *srr1_mask* *dsisr* *dar* *recovered* + Inject a low-level MCE on the given CPU (PPC only). +ERST + +#endif + #ifdef CONFIG_POSIX { .name = "getfd", -- 2.42.0