diff mbox

[1/2] spapr: Add NMI interface

Message ID 1395886880-11021-2-git-send-email-aik@ozlabs.ru
State New
Headers show

Commit Message

Alexey Kardashevskiy March 27, 2014, 2:21 a.m. UTC
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 <aik@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 mbox

Patch

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 */