This patch adds a 'kvm nmi' command which can be used to trigger NMIs in
guests.

Mostly useful for debugging purposes.

Signed-off-by: Sasha Levin <[email protected]>
---
 tools/kvm/Documentation/kvm-nmi.txt |   16 +++++++
 tools/kvm/Makefile                  |    3 +-
 tools/kvm/builtin-nmi.c             |   80 +++++++++++++++++++++++++++++++++++
 tools/kvm/builtin-run.c             |    9 ++++
 tools/kvm/command-list.txt          |    1 +
 tools/kvm/include/kvm/builtin-nmi.h |   15 +++++++
 tools/kvm/include/kvm/kvm-ipc.h     |    1 +
 tools/kvm/kvm-cmd.c                 |    2 +
 8 files changed, 126 insertions(+), 1 deletions(-)
 create mode 100644 tools/kvm/Documentation/kvm-nmi.txt
 create mode 100644 tools/kvm/builtin-nmi.c
 create mode 100644 tools/kvm/include/kvm/builtin-nmi.h

diff --git a/tools/kvm/Documentation/kvm-nmi.txt 
b/tools/kvm/Documentation/kvm-nmi.txt
new file mode 100644
index 0000000..d562abc
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-nmi.txt
@@ -0,0 +1,16 @@
+kvm-nmi(1)
+================
+
+NAME
+----
+kvm-nmi - Trigger an NMI on a specific cpu in the guest
+
+SYNOPSIS
+--------
+[verse]
+'kvm nmi [instance] -c [cpu]'
+
+DESCRIPTION
+-----------
+The command triggers a NMI on cpu 'cpu' in the guest.
+For a list of running instances see 'kvm list'.
diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index 243886e..b5a76e2 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -80,6 +80,7 @@ OBJS  += hw/vesa.o
 OBJS   += hw/i8042.o
 OBJS   += hw/pci-shmem.o
 OBJS   += kvm-ipc.o
+OBJS   += builtin-nmi.o
 
 FLAGS_BFD := $(CFLAGS) -lbfd
 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
@@ -176,7 +177,7 @@ DEFINES     += -DKVMTOOLS_VERSION='"$(KVMTOOLS_VERSION)"'
 DEFINES        += -DBUILD_ARCH='"$(ARCH)"'
 
 KVM_INCLUDE := include
-CFLAGS += $(CPPFLAGS) $(DEFINES) -I$(KVM_INCLUDE) -I$(ARCH_INCLUDE) 
-I../../include -I../../arch/$(ARCH)/include/ -Os -g
+CFLAGS += $(CPPFLAGS) $(DEFINES) -I$(KVM_INCLUDE) -I$(ARCH_INCLUDE) 
-I../../include -I../../arch/$(ARCH)/include/ -O0 -g
 
 ifneq ($(WERROR),0)
        WARNINGS += -Werror
diff --git a/tools/kvm/builtin-nmi.c b/tools/kvm/builtin-nmi.c
new file mode 100644
index 0000000..ad60ac2
--- /dev/null
+++ b/tools/kvm/builtin-nmi.c
@@ -0,0 +1,80 @@
+#include <kvm/builtin-nmi.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+#include <kvm/read-write.h>
+#include <kvm/util.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static bool all;
+static int instance;
+static int cpu = -1;
+static const char *instance_name;
+
+static const char * const nmi_usage[] = {
+       "kvm nmi [--all] [-n name] -c cpu",
+       NULL
+};
+
+static const struct option nmi_options[] = {
+       OPT_GROUP("General options:"),
+       OPT_BOOLEAN('a', "all", &all, "Send NMI to all instances"),
+       OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+       OPT_INTEGER('c', "cpu", &cpu, "CPU which will receive NMI"),
+       OPT_END()
+};
+
+static void parse_nmi_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, nmi_options, nmi_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0)
+                       kvm_nmi_help();
+       }
+}
+
+void kvm_nmi_help(void)
+{
+       usage_with_options(nmi_usage, nmi_options);
+}
+
+static int do_nmi(const char *name, int sock)
+{
+       struct nmi_cmd cmd = {KVM_IPC_NMI, sizeof(u32)};
+       int r;
+
+       r = xwrite(sock, &cmd, sizeof(cmd));
+       if (r < 0)
+               return r;
+
+       pr_info("NMI sent to %s!\n", name);
+
+       return 0;
+}
+
+int kvm_cmd_nmi(int argc, const char **argv, const char *prefix)
+{
+       parse_nmi_options(argc, argv);
+
+       if (all)
+               return kvm__enumerate_instances(do_nmi);
+
+       if (instance_name == NULL &&
+           instance == 0)
+               kvm_nmi_help();
+
+       if (cpu == -1)
+               kvm_nmi_help();
+
+       if (instance_name)
+               instance = kvm__get_sock_by_instance(instance_name);
+
+       if (instance <= 0)
+               die("Failed locating instance");
+
+       return do_nmi(instance_name, instance);
+}
diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c
index 9148d83..b8743cd 100644
--- a/tools/kvm/builtin-run.c
+++ b/tools/kvm/builtin-run.c
@@ -31,6 +31,7 @@
 #include "kvm/guest_compat.h"
 #include "kvm/pci-shmem.h"
 #include "kvm/kvm-ipc.h"
+#include "kvm/builtin-nmi.h"
 
 #include <linux/types.h>
 
@@ -529,6 +530,13 @@ static void handle_stop(int fd, u32 type, u32 len, u8 *msg)
        kvm_cpu__reboot();
 }
 
+static void handle_nmi(int fd, u32 type, u32 len, u8 *msg)
+{
+       u32 vcpu = *(u32 *)msg;
+
+       ioctl(kvm_cpus[vcpu]->vcpu_fd, KVM_NMI);
+}
+
 static void *kvm_cpu_thread(void *arg)
 {
        current_kvm_cpu         = arg;
@@ -718,6 +726,7 @@ int kvm_cmd_run(int argc, const char **argv, const char 
*prefix)
        kvm_ipc__register_handler(KVM_IPC_PAUSE, handle_pause);
        kvm_ipc__register_handler(KVM_IPC_RESUME, handle_pause);
        kvm_ipc__register_handler(KVM_IPC_STOP, handle_stop);
+       kvm_ipc__register_handler(KVM_IPC_NMI, handle_nmi);
 
        nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
 
diff --git a/tools/kvm/command-list.txt b/tools/kvm/command-list.txt
index 0d16c62..e9ab8e4 100644
--- a/tools/kvm/command-list.txt
+++ b/tools/kvm/command-list.txt
@@ -12,3 +12,4 @@ kvm-debug                     common
 kvm-balloon                    common
 kvm-stop                       common
 kvm-stat                       common
+kvm-nmi                                common
diff --git a/tools/kvm/include/kvm/builtin-nmi.h 
b/tools/kvm/include/kvm/builtin-nmi.h
new file mode 100644
index 0000000..ffdc288
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-nmi.h
@@ -0,0 +1,15 @@
+#ifndef KVM__NMI_H
+#define KVM__NMI_H
+
+#include <linux/types.h>
+
+struct nmi_cmd {
+       u32 type;
+       u32 len;
+       u32 cpu;
+};
+
+int kvm_cmd_nmi(int argc, const char **argv, const char *prefix);
+void kvm_nmi_help(void);
+
+#endif
diff --git a/tools/kvm/include/kvm/kvm-ipc.h b/tools/kvm/include/kvm/kvm-ipc.h
index 731767f..366f54e 100644
--- a/tools/kvm/include/kvm/kvm-ipc.h
+++ b/tools/kvm/include/kvm/kvm-ipc.h
@@ -17,6 +17,7 @@ enum {
        KVM_IPC_RESUME  = 5,
        KVM_IPC_STOP    = 6,
        KVM_IPC_PID     = 7,
+       KVM_IPC_NMI     = 8,
 };
 
 int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, 
u8 *msg));
diff --git a/tools/kvm/kvm-cmd.c b/tools/kvm/kvm-cmd.c
index 96108a8..6ab9897 100644
--- a/tools/kvm/kvm-cmd.c
+++ b/tools/kvm/kvm-cmd.c
@@ -15,6 +15,7 @@
 #include "kvm/builtin-stop.h"
 #include "kvm/builtin-stat.h"
 #include "kvm/builtin-help.h"
+#include "kvm/builtin-nmi.h"
 #include "kvm/kvm-cmd.h"
 #include "kvm/builtin-run.h"
 #include "kvm/util.h"
@@ -31,6 +32,7 @@ struct cmd_struct kvm_commands[] = {
        { "stat",       kvm_cmd_stat,           kvm_stat_help,          0 },
        { "help",       kvm_cmd_help,           NULL,                   0 },
        { "setup",      kvm_cmd_setup,          kvm_setup_help,         0 },
+       { "nmi",        kvm_cmd_nmi,            kvm_nmi_help,           0 },
        { "run",        kvm_cmd_run,            kvm_run_help,           0 },
        { NULL,         NULL,                   NULL,                   0 },
 };
-- 
1.7.8

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to