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 <levinsasha928@xxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html