This introduces an NMI (non maskable interrupt) interface which QMP's "nmi" command may use to issue NMI on a CPU. A machine class is expected to implement it.
This adds a helper to obtain the interface pointer and call the deliver_nmi handler. Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru> --- cpus.c | 7 ++++++- hmp-commands.hx | 4 +--- hw/core/Makefile.objs | 1 + hw/core/nmi.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/nmi.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 hw/core/nmi.c create mode 100644 include/hw/nmi.h diff --git a/cpus.c b/cpus.c index 1104d61..c5cab31 100644 --- a/cpus.c +++ b/cpus.c @@ -38,6 +38,7 @@ #include "qemu/main-loop.h" #include "qemu/bitmap.h" #include "qemu/seqlock.h" +#include "hw/nmi.h" #ifndef _WIN32 #include "qemu/compatfd.h" @@ -1496,6 +1497,10 @@ void qmp_inject_nmi(Error **errp) } } #else - error_set(errp, QERR_UNSUPPORTED); + CPUState *cs = qemu_get_cpu(monitor_get_cpu_index()); + + if (cs && nmi_try_deliver(cs)) { + error_set(errp, QERR_UNSUPPORTED); + } #endif } diff --git a/hmp-commands.hx b/hmp-commands.hx index f3fc514..c25a0f4 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -827,7 +827,6 @@ The values that can be specified here depend on the machine type, but are the same that can be specified in the @code{-boot} command line option. ETEXI -#if defined(TARGET_I386) || defined(TARGET_S390X) { .name = "nmi", .args_type = "", @@ -835,11 +834,10 @@ ETEXI .help = "inject an NMI on all guest's CPUs", .mhandler.cmd = hmp_inject_nmi, }, -#endif STEXI @item nmi @var{cpu} @findex nmi -Inject an NMI (x86) or RESTART (s390x) on the given CPU. +Inject an NMI (x86), RESTART (s390x) or platform-defined NMI on the given CPU. ETEXI diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 5377d05..d2a7be1 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -1,6 +1,7 @@ # core qdev-related obj files, also used by *-user: common-obj-y += qdev.o qdev-properties.o common-obj-y += fw-path-provider.o +common-obj-y += nmi.o # irq.o needed for qdev GPIO handling: common-obj-y += irq.o common-obj-y += hotplug.o diff --git a/hw/core/nmi.c b/hw/core/nmi.c new file mode 100644 index 0000000..01009d3 --- /dev/null +++ b/hw/core/nmi.c @@ -0,0 +1,50 @@ +/* + * NMI (non-maskable interrupt) interface and helper. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License + * or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw/nmi.h" + +int nmi_try_deliver(CPUState *cs) +{ + Object *obj = OBJECT(first_cpu); + NMIObj *nmi; + NMIClass *nmic; + + while (obj->parent) { + nmi = (NMIObj *) object_dynamic_cast(obj, TYPE_NMI); + if (nmi) { + nmic = NMI_GET_CLASS(nmi); + nmic->deliver_nmi(nmi, cs); + return 0; + } + obj = obj->parent; + } + + return -1; +} + +static const TypeInfo nmi_info = { + .name = TYPE_NMI, + .parent = TYPE_INTERFACE, + .class_size = sizeof(NMIClass), +}; + +static void nmi_register_types(void) +{ + type_register_static(&nmi_info); +} + +type_init(nmi_register_types) diff --git a/include/hw/nmi.h b/include/hw/nmi.h new file mode 100644 index 0000000..53075e3 --- /dev/null +++ b/include/hw/nmi.h @@ -0,0 +1,48 @@ +/* + * NMI (non-maskable interrupt) interface and helper definitions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License + * or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NMI_H +#define NMI_H 1 + +#include "qom/object.h" +#include "qom/cpu.h" + +#define TYPE_NMI "nmi" + +#define NMI_CLASS(klass) \ + OBJECT_CLASS_CHECK(NMIClass, (klass), TYPE_NMI) +#define NMI_GET_CLASS(obj) \ + OBJECT_GET_CLASS(NMIClass, (obj), TYPE_NMI) +#define NMI(obj) \ + INTERFACE_CHECK(NMIObj, (obj), TYPE_NMI) + +typedef struct NMIiObj { + /* private */ + Object parent_obj; +} NMIObj; + +typedef struct NMIClass { + /* private */ + InterfaceClass parent_class; + + /* public */ + void (*deliver_nmi)(NMIObj *p, CPUState *cs); +} NMIClass; + +extern int nmi_try_deliver(CPUState *cs); + +#endif /* NMI_H */ -- 1.8.4.rc4