This allows triggering NMI on guests using 'kvm debug -m [cpu]'.

Please note that the default behaviour of 'kvm debug' dumping guest's cpu
state has been modified to require a '-d'/--dump.

Signed-off-by: Sasha Levin <levinsasha...@gmail.com>
---
 tools/kvm/builtin-debug.c                |   22 +++++++++++----
 tools/kvm/builtin-run.c                  |   16 +++++++++++-
 tools/kvm/include/kvm/builtin-debug.h    |   11 ++++++++
 tools/kvm/include/kvm/kvm-cpu.h          |    1 +
 tools/kvm/kvm-cpu.c                      |    5 +++
 tools/kvm/x86/include/kvm/kvm-cpu-arch.h |    1 +
 tools/kvm/x86/kvm-cpu.c                  |   41 ++++++++++++++++++++++++++++++
 7 files changed, 90 insertions(+), 7 deletions(-)

diff --git a/tools/kvm/builtin-debug.c b/tools/kvm/builtin-debug.c
index 045dc2c..eee26c3 100644
--- a/tools/kvm/builtin-debug.c
+++ b/tools/kvm/builtin-debug.c
@@ -14,13 +14,10 @@
 
 static bool all;
 static int instance;
+static int nmi = -1;
+static bool dump;
 static const char *instance_name;
 
-struct debug_cmd {
-       u32 type;
-       u32 len;
-};
-
 static const char * const debug_usage[] = {
        "kvm debug [--all] [-n name]",
        NULL
@@ -30,6 +27,8 @@ static const struct option debug_options[] = {
        OPT_GROUP("General options:"),
        OPT_BOOLEAN('a', "all", &all, "Debug all instances"),
        OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+       OPT_BOOLEAN('d', "dump", &dump, "Generate a debug dump from guest"),
+       OPT_INTEGER('m', "nmi", &nmi, "Generate NMI on VCPU"),
        OPT_END()
 };
 
@@ -51,13 +50,24 @@ void kvm_debug_help(void)
 static int do_debug(const char *name, int sock)
 {
        char buff[BUFFER_SIZE];
-       struct debug_cmd cmd = {KVM_IPC_DEBUG, 0};
+       struct debug_cmd cmd = {KVM_IPC_DEBUG, 2 * sizeof(u32)};
        int r;
 
+       if (dump)
+               cmd.dbg_type |= KVM_DEBUG_CMD_TYPE_DUMP;
+
+       if (nmi != -1) {
+               cmd.dbg_type |= KVM_DEBUG_CMD_TYPE_NMI;
+               cmd.cpu = nmi;
+       }
+
        r = xwrite(sock, &cmd, sizeof(cmd));
        if (r < 0)
                return r;
 
+       if (!dump)
+               return 0;
+
        do {
                r = xread(sock, buff, BUFFER_SIZE);
                if (r < 0)
diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c
index 7969901..7709edb 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-debug.h"
 
 #include <linux/types.h>
 
@@ -464,7 +465,7 @@ static void handle_sigusr1(int sig)
        struct kvm_cpu *cpu = current_kvm_cpu;
        int fd = kvm_cpu__get_debug_fd();
 
-       if (!cpu)
+       if (!cpu || cpu->needs_nmi)
                return;
 
        dprintf(fd, "\n #\n # vCPU #%ld's dump:\n #\n", cpu->cpu_id);
@@ -495,6 +496,19 @@ static void handle_pause(int fd, u32 type, u32 len, u8 
*msg)
 static void handle_debug(int fd, u32 type, u32 len, u8 *msg)
 {
        int i;
+       u32 dbg_type = *(u32 *)msg;
+       int vcpu = *(((u32 *)msg) + 1);
+
+       if (dbg_type & KVM_DEBUG_CMD_TYPE_NMI) {
+               if (vcpu >= kvm->nrcpus)
+                       return;
+
+               kvm_cpus[vcpu]->needs_nmi = 1;
+               pthread_kill(kvm_cpus[vcpu]->thread, SIGUSR1);
+       }
+
+       if (!(dbg_type & KVM_DEBUG_CMD_TYPE_DUMP))
+               return;
 
        for (i = 0; i < nrcpus; i++) {
                struct kvm_cpu *cpu = kvm_cpus[i];
diff --git a/tools/kvm/include/kvm/builtin-debug.h 
b/tools/kvm/include/kvm/builtin-debug.h
index 3fc2469..b24b501 100644
--- a/tools/kvm/include/kvm/builtin-debug.h
+++ b/tools/kvm/include/kvm/builtin-debug.h
@@ -1,6 +1,17 @@
 #ifndef KVM__DEBUG_H
 #define KVM__DEBUG_H
 
+#include <linux/types.h>
+
+struct debug_cmd {
+       u32 type;
+       u32 len;
+       u32 dbg_type;
+#define KVM_DEBUG_CMD_TYPE_DUMP        (1 << 0)
+#define KVM_DEBUG_CMD_TYPE_NMI (1 << 1)
+       u32 cpu;
+};
+
 int kvm_cmd_debug(int argc, const char **argv, const char *prefix);
 void kvm_debug_help(void);
 
diff --git a/tools/kvm/include/kvm/kvm-cpu.h b/tools/kvm/include/kvm/kvm-cpu.h
index 15618f1..d4448f6 100644
--- a/tools/kvm/include/kvm/kvm-cpu.h
+++ b/tools/kvm/include/kvm/kvm-cpu.h
@@ -19,5 +19,6 @@ void kvm_cpu__set_debug_fd(int fd);
 void kvm_cpu__show_code(struct kvm_cpu *vcpu);
 void kvm_cpu__show_registers(struct kvm_cpu *vcpu);
 void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu);
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu);
 
 #endif /* KVM__KVM_CPU_H */
diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c
index 884a89f..8ec4efa 100644
--- a/tools/kvm/kvm-cpu.c
+++ b/tools/kvm/kvm-cpu.c
@@ -94,6 +94,11 @@ int kvm_cpu__start(struct kvm_cpu *cpu)
                        cpu->paused = 0;
                }
 
+               if (cpu->needs_nmi) {
+                       kvm_cpu__arch_nmi(cpu);
+                       cpu->needs_nmi = 0;
+               }
+
                kvm_cpu__run(cpu);
 
                switch (cpu->kvm_run->exit_reason) {
diff --git a/tools/kvm/x86/include/kvm/kvm-cpu-arch.h 
b/tools/kvm/x86/include/kvm/kvm-cpu-arch.h
index ed1c727..822d966 100644
--- a/tools/kvm/x86/include/kvm/kvm-cpu-arch.h
+++ b/tools/kvm/x86/include/kvm/kvm-cpu-arch.h
@@ -26,6 +26,7 @@ struct kvm_cpu {
 
        u8                      is_running;
        u8                      paused;
+       u8                      needs_nmi;
 
        struct kvm_coalesced_mmio_ring  *ring;
 };
diff --git a/tools/kvm/x86/kvm-cpu.c b/tools/kvm/x86/kvm-cpu.c
index a0d10cc..18b4906 100644
--- a/tools/kvm/x86/kvm-cpu.c
+++ b/tools/kvm/x86/kvm-cpu.c
@@ -5,6 +5,7 @@
 #include "kvm/kvm.h"
 
 #include <asm/msr-index.h>
+#include <asm/apicdef.h>
 
 #include <sys/ioctl.h>
 #include <sys/mman.h>
@@ -76,6 +77,26 @@ void kvm_cpu__delete(struct kvm_cpu *vcpu)
        free(vcpu);
 }
 
+static int kvm_cpu__set_lint(struct kvm_cpu *vcpu)
+{
+       struct kvm_lapic_state klapic;
+       struct local_apic *lapic = (void *)&klapic;
+       u32 lvt;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_LAPIC, &klapic))
+               return -1;
+
+       lvt = *(u32 *)&lapic->lvt_lint0;
+       lvt = SET_APIC_DELIVERY_MODE(lvt, APIC_MODE_EXTINT);
+       *(u32 *)&lapic->lvt_lint0 = lvt;
+
+       lvt = *(u32 *)&lapic->lvt_lint0;
+       lvt = SET_APIC_DELIVERY_MODE(lvt, APIC_MODE_NMI);
+       *(u32 *)&lapic->lvt_lint0 = lvt;
+
+       return ioctl(vcpu->vcpu_fd, KVM_SET_LAPIC, &klapic);
+}
+
 struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id)
 {
        struct kvm_cpu *vcpu;
@@ -104,6 +125,9 @@ struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned 
long cpu_id)
        if (coalesced_offset)
                vcpu->ring = (void *)vcpu->kvm_run + (coalesced_offset * 
PAGE_SIZE);
 
+       if (kvm_cpu__set_lint(vcpu))
+               die_perror("KVM_SET_LAPIC failed");
+
        vcpu->is_running = true;
 
        return vcpu;
@@ -386,3 +410,20 @@ void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
                        "llx   pte1: %016llx\n",
                        *pte4, *pte3, *pte2, *pte1);
 }
+
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
+{
+       struct kvm_lapic_state klapic;
+       struct local_apic *lapic = (void *)&klapic;
+
+       if (ioctl(cpu->vcpu_fd, KVM_GET_LAPIC, &klapic) != 0)
+               return;
+
+       if (lapic->lvt_lint1.mask)
+               return;
+
+       if (lapic->lvt_lint1.delivery_mode != APIC_MODE_NMI)
+               return;
+
+       ioctl(cpu->vcpu_fd, KVM_NMI);
+}
-- 
1.7.8

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

Reply via email to