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