qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 9/9] qemu/kvm: kvm hyper-v based guest crash event h


From: Denis V. Lunev
Subject: [Qemu-devel] [PATCH 9/9] qemu/kvm: kvm hyper-v based guest crash event handling
Date: Tue, 30 Jun 2015 14:33:27 +0300

From: Andrey Smetanin <address@hidden>

KVM Hyper-V based guests can notify hypervisor about
occurred guest crash. This patch does handling of KVM crash event
by sending to libvirt guest panic event that allows to gather
guest crash dump by QEMU/LIBVIRT. Add support of HV_X64_MSR_CRASH_P0-P4,
HV_X64_MSR_CRASH_CTL msrs.

The idea is to provide functionality equal to pvpanic device without
QEMU guest agent for Windows.

The idea is borrowed from Linux HyperV bus driver and validated against
Windows 2k12.

Note that it's usually impossible to understand from Hyper-V
crash msr's that crash happened because ctl msr
always contains the same value HV_X64_MSR_CRASH_CTL_NOTIFY.
To solve it add a particular value - hv_crash_occurred
inside CPU state and migrate this value with crash msr's.

Signed-off-by: Andrey Smetanin <address@hidden>
Signed-off-by: Denis V. Lunev <address@hidden>
CC: Paolo Bonzini <address@hidden>
CC: Andreas Färber <address@hidden>
---
 hw/misc/pvpanic.c              |  3 +--
 include/sysemu/kvm.h           |  2 ++
 include/sysemu/sysemu.h        |  1 +
 kvm-all.c                      |  5 ++++
 linux-headers/asm-x86/hyperv.h | 16 +++++++++++++
 linux-headers/linux/kvm.h      |  2 ++
 target-arm/kvm.c               |  5 ++++
 target-i386/cpu-qom.h          |  1 +
 target-i386/cpu.c              |  1 +
 target-i386/cpu.h              |  4 ++++
 target-i386/kvm.c              | 53 ++++++++++++++++++++++++++++++++++++++++++
 target-i386/machine.c          | 24 +++++++++++++++++++
 target-mips/kvm.c              |  5 ++++
 target-ppc/kvm.c               |  5 ++++
 target-s390x/kvm.c             | 16 ++++++-------
 vl.c                           |  6 +++++
 16 files changed, 138 insertions(+), 11 deletions(-)

diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c
index 994f8af..3709488 100644
--- a/hw/misc/pvpanic.c
+++ b/hw/misc/pvpanic.c
@@ -41,8 +41,7 @@ static void handle_event(int event)
     }
 
     if (event & PVPANIC_PANICKED) {
-        qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort);
-        vm_stop(RUN_STATE_GUEST_PANICKED);
+        qemu_system_guest_panicked();
         return;
     }
 }
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index f459fbd..c62fd0c 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -257,6 +257,8 @@ extern const KVMCapabilityInfo 
kvm_arch_required_capabilities[];
 void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run);
 MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run);
 
+int kvm_arch_handle_crash(CPUState *cpu, struct kvm_run *run);
+
 int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run);
 
 int kvm_arch_process_async_events(CPUState *cpu);
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index df80951..70164c9 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -68,6 +68,7 @@ int qemu_reset_requested_get(void);
 void qemu_system_killed(int signal, pid_t pid);
 void qemu_devices_reset(void);
 void qemu_system_reset(bool report);
+void qemu_system_guest_panicked(void);
 
 void qemu_add_exit_notifier(Notifier *notify);
 void qemu_remove_exit_notifier(Notifier *notify);
diff --git a/kvm-all.c b/kvm-all.c
index 53e01d4..d35dc1e 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1844,6 +1844,11 @@ int kvm_cpu_exec(CPUState *cpu)
                 qemu_system_reset_request();
                 ret = EXCP_INTERRUPT;
                 break;
+            case KVM_SYSTEM_EVENT_CRASH:
+                kvm_arch_handle_crash(cpu, run);
+                qemu_system_guest_panicked();
+                ret = 0;
+                break;
             default:
                 DPRINTF("kvm_arch_handle_exit\n");
                 ret = kvm_arch_handle_exit(cpu, run);
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
index ce6068d..aec7d27 100644
--- a/linux-headers/asm-x86/hyperv.h
+++ b/linux-headers/asm-x86/hyperv.h
@@ -108,6 +108,8 @@
 #define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE          (1 << 4)
 /* Support for a virtual guest idle state is available */
 #define HV_X64_GUEST_IDLE_STATE_AVAILABLE              (1 << 5)
+/* Guest crash data handler available */
+#define HV_X64_GUEST_CRASH_MSR_AVAILABLE               (1 << 10)
 
 /*
  * Implementation recommendations. Indicates which behaviors the hypervisor
@@ -199,6 +201,20 @@
 #define HV_X64_MSR_STIMER3_CONFIG              0x400000B6
 #define HV_X64_MSR_STIMER3_COUNT               0x400000B7
 
+/* Hypev-V guest crash notification MSR's */
+#define HV_X64_MSR_CRASH_P0                    0x40000100
+#define HV_X64_MSR_CRASH_P1                    0x40000101
+#define HV_X64_MSR_CRASH_P2                    0x40000102
+#define HV_X64_MSR_CRASH_P3                    0x40000103
+#define HV_X64_MSR_CRASH_P4                    0x40000104
+#define HV_X64_MSR_CRASH_CTL                   0x40000105
+#define HV_X64_MSR_CRASH_CTL_NOTIFY            (1ULL << 63)
+#define HV_X64_MSR_CRASH_CTL_CONTENTS  \
+               (HV_X64_MSR_CRASH_CTL_NOTIFY)
+
+#define HV_X64_MSR_CRASH_PARAMS        \
+               (1 + (HV_X64_MSR_CRASH_P4 - HV_X64_MSR_CRASH_P0))
+
 #define HV_X64_MSR_HYPERCALL_ENABLE            0x00000001
 #define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT        12
 #define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_MASK \
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index fad9e5c..46cb7e0 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -317,6 +317,8 @@ struct kvm_run {
                struct {
 #define KVM_SYSTEM_EVENT_SHUTDOWN       1
 #define KVM_SYSTEM_EVENT_RESET          2
+#define KVM_SYSTEM_EVENT_CRASH          3
+#define KVM_SYSTEM_EVENT_FL_HV_CRASH    (1ULL << 0)
                        __u32 type;
                        __u64 flags;
                } system_event;
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 548bfd7..8cc5571 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -512,6 +512,11 @@ MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run 
*run)
     return MEMTXATTRS_UNSPECIFIED;
 }
 
+int kvm_arch_handle_crash(CPUState *cs, struct kvm_run *run)
+{
+    return 0;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     return 0;
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 7a4fddd..c35b624 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -89,6 +89,7 @@ typedef struct X86CPU {
     bool hyperv_relaxed_timing;
     int hyperv_spinlock_attempts;
     bool hyperv_time;
+    bool hyperv_crash;
     bool check_cpuid;
     bool enforce_cpuid;
     bool expose_kvm;
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 36b07f9..04a8408 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -3117,6 +3117,7 @@ static Property x86_cpu_properties[] = {
     DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
     DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false),
     DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
+    DEFINE_PROP_BOOL("hv-crash", X86CPU, hyperv_crash, false),
     DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false),
     DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
     DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 603aaf0..2958cdc 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -21,6 +21,7 @@
 
 #include "config.h"
 #include "qemu-common.h"
+#include <asm/hyperv.h>
 
 #ifdef TARGET_X86_64
 #define TARGET_LONG_BITS 64
@@ -904,6 +905,9 @@ typedef struct CPUX86State {
     uint64_t msr_hv_guest_os_id;
     uint64_t msr_hv_vapic;
     uint64_t msr_hv_tsc;
+    uint64_t msr_hv_crash_prm[HV_X64_MSR_CRASH_PARAMS];
+    uint64_t msr_hv_crash_ctl;
+    uint8_t hv_crash_occurred;
 
     /* exception/interrupt handling */
     int error_code;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index daced5c..1f887cb 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -79,6 +79,7 @@ static int lm_capable_kernel;
 static bool has_msr_hv_hypercall;
 static bool has_msr_hv_vapic;
 static bool has_msr_hv_tsc;
+static bool has_msr_hv_crash;
 static bool has_msr_mtrr;
 static bool has_msr_xss;
 
@@ -515,6 +516,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
             c->eax |= 0x200;
             has_msr_hv_tsc = true;
         }
+        if (cpu->hyperv_crash) {
+            c->edx |= HV_X64_GUEST_CRASH_MSR_AVAILABLE;
+            has_msr_hv_crash = true;
+        }
+
         c = &cpuid_data.entries[cpuid_i++];
         c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
         if (cpu->hyperv_relaxed_timing) {
@@ -761,6 +767,10 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
     } else {
         env->mp_state = KVM_MP_STATE_RUNNABLE;
     }
+    if (has_msr_hv_crash) {
+            env->msr_hv_crash_ctl = HV_X64_MSR_CRASH_CTL_NOTIFY;
+            env->hv_crash_occurred = 0;
+    }
 }
 
 void kvm_arch_do_init_vcpu(X86CPU *cpu)
@@ -1321,6 +1331,16 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
             kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
                               env->msr_hv_tsc);
         }
+        if (has_msr_hv_crash) {
+            int j;
+
+            for (j = 0; j < HV_X64_MSR_CRASH_PARAMS; j++)
+                kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_CRASH_P0 + j,
+                                  env->msr_hv_crash_prm[j]);
+
+            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_CRASH_CTL,
+                              env->msr_hv_crash_ctl);
+        }
         if (has_msr_mtrr) {
             kvm_msr_entry_set(&msrs[n++], MSR_MTRRdefType, env->mtrr_deftype);
             kvm_msr_entry_set(&msrs[n++],
@@ -1673,6 +1693,14 @@ static int kvm_get_msrs(X86CPU *cpu)
     if (has_msr_hv_tsc) {
         msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
     }
+    if (has_msr_hv_crash) {
+        int j;
+
+        for (j = 0; j < HV_X64_MSR_CRASH_PARAMS; j++) {
+            msrs[n++].index = HV_X64_MSR_CRASH_P0 + j;
+        }
+        msrs[n++].index = HV_X64_MSR_CRASH_CTL;
+    }
     if (has_msr_mtrr) {
         msrs[n++].index = MSR_MTRRdefType;
         msrs[n++].index = MSR_MTRRfix64K_00000;
@@ -1817,6 +1845,12 @@ static int kvm_get_msrs(X86CPU *cpu)
         case HV_X64_MSR_REFERENCE_TSC:
             env->msr_hv_tsc = msrs[i].data;
             break;
+        case HV_X64_MSR_CRASH_CTL:
+            env->msr_hv_crash_ctl = msrs[i].data;
+            break;
+        case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
+            env->msr_hv_crash_prm[index - HV_X64_MSR_CRASH_P0] = msrs[i].data;
+            break;
         case MSR_MTRRdefType:
             env->mtrr_deftype = msrs[i].data;
             break;
@@ -2539,6 +2573,25 @@ static bool host_supports_vmx(void)
     return ecx & CPUID_EXT_VMX;
 }
 
+static int kvm_arch_handle_hv_crash(CPUState *cs)
+{
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+
+    /* Mark that Hyper-v guest crash occurred */
+    env->hv_crash_occurred = 1;
+
+    return 0;
+}
+
+int kvm_arch_handle_crash(CPUState *cs, struct kvm_run *run)
+{
+    if (run->system_event.flags & KVM_SYSTEM_EVENT_FL_HV_CRASH) {
+        return kvm_arch_handle_hv_crash(cs);
+    }
+    return 0;
+}
+
 #define VMX_INVALID_GUEST_STATE 0x80000021
 
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
diff --git a/target-i386/machine.c b/target-i386/machine.c
index a0df64b..4f72ba8 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -661,6 +661,29 @@ static const VMStateDescription vmstate_msr_hyperv_time = {
     }
 };
 
+static bool hyperv_crash_enable_needed(void *opaque)
+{
+    X86CPU *cpu = opaque;
+    CPUX86State *env = &cpu->env;
+
+    return (env->msr_hv_crash_ctl & HV_X64_MSR_CRASH_CTL_CONTENTS) ?
+            true : false;
+}
+
+static const VMStateDescription vmstate_msr_hyperv_crash = {
+    .name = "cpu/msr_hyperv_crash",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = hyperv_crash_enable_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(env.msr_hv_crash_ctl, X86CPU),
+        VMSTATE_UINT64_ARRAY(env.msr_hv_crash_prm,
+                             X86CPU, HV_X64_MSR_CRASH_PARAMS),
+        VMSTATE_UINT8(env.hv_crash_occurred, X86CPU),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static bool avx512_needed(void *opaque)
 {
     X86CPU *cpu = opaque;
@@ -842,6 +865,7 @@ VMStateDescription vmstate_x86_cpu = {
         &vmstate_msr_hypercall_hypercall,
         &vmstate_msr_hyperv_vapic,
         &vmstate_msr_hyperv_time,
+        &vmstate_msr_hyperv_crash,
         &vmstate_avx512,
         &vmstate_xss,
         NULL
diff --git a/target-mips/kvm.c b/target-mips/kvm.c
index 948619f..01a6350 100644
--- a/target-mips/kvm.c
+++ b/target-mips/kvm.c
@@ -122,6 +122,11 @@ int kvm_arch_process_async_events(CPUState *cs)
     return cs->halted;
 }
 
+int kvm_arch_handle_crash(CPUState *cs, struct kvm_run *run)
+{
+    return 0;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     int ret;
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index afb4696..6b53a85 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -1564,6 +1564,11 @@ static int kvm_handle_debug(PowerPCCPU *cpu, struct 
kvm_run *run)
     return handle;
 }
 
+int kvm_arch_handle_crash(CPUState *cs, struct kvm_run *run)
+{
+    return 0;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 135111a..79317c8 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -1796,13 +1796,6 @@ static bool is_special_wait_psw(CPUState *cs)
     return cs->kvm_run->psw_addr == 0xfffUL;
 }
 
-static void guest_panicked(void)
-{
-    qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE,
-                                   &error_abort);
-    vm_stop(RUN_STATE_GUEST_PANICKED);
-}
-
 static void unmanageable_intercept(S390CPU *cpu, const char *str, int 
pswoffset)
 {
     CPUState *cs = CPU(cpu);
@@ -1811,7 +1804,7 @@ static void unmanageable_intercept(S390CPU *cpu, const 
char *str, int pswoffset)
                  str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + 
pswoffset),
                  ldq_phys(cs->as, cpu->env.psa + pswoffset + 8));
     s390_cpu_halt(cpu);
-    guest_panicked();
+    qemu_system_guest_panicked();
 }
 
 static int handle_intercept(S390CPU *cpu)
@@ -1844,7 +1837,7 @@ static int handle_intercept(S390CPU *cpu)
                 if (is_special_wait_psw(cs)) {
                     qemu_system_shutdown_request();
                 } else {
-                    guest_panicked();
+                    qemu_system_guest_panicked();
                 }
             }
             r = EXCP_HALTED;
@@ -2002,6 +1995,11 @@ static int kvm_arch_handle_debug_exit(S390CPU *cpu)
     return ret;
 }
 
+int kvm_arch_handle_crash(CPUState *cs, struct kvm_run *run)
+{
+    return 0;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     S390CPU *cpu = S390_CPU(cs);
diff --git a/vl.c b/vl.c
index 69ad90c..38eee1f 100644
--- a/vl.c
+++ b/vl.c
@@ -1721,6 +1721,12 @@ void qemu_system_reset(bool report)
     cpu_synchronize_all_post_reset();
 }
 
+void qemu_system_guest_panicked(void)
+{
+    qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort);
+    vm_stop(RUN_STATE_GUEST_PANICKED);
+}
+
 void qemu_system_reset_request(void)
 {
     if (no_reboot) {
-- 
2.1.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]