@@ -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_hv_crash(CPUState *cpu);
+
int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run);
int kvm_arch_process_async_events(CPUState *cpu);
@@ -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);
@@ -1844,6 +1844,13 @@ int kvm_cpu_exec(CPUState *cpu)
qemu_system_reset_request();
ret = EXCP_INTERRUPT;
break;
+ case KVM_SYSTEM_EVENT_CRASH:
+ if (run->system_event.flags & KVM_SYSTEM_EVENT_FL_HV_CRASH) {
+ kvm_arch_handle_hv_crash(cpu);
+ }
+ qemu_system_guest_panicked();
+ ret = 0;
+ break;
default:
DPRINTF("kvm_arch_handle_exit\n");
ret = kvm_arch_handle_exit(cpu, run);
@@ -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 \
@@ -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;
@@ -512,6 +512,11 @@ MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
return MEMTXATTRS_UNSPECIFIED;
}
+int kvm_arch_handle_hv_crash(CPUState *cs)
+{
+ return 0;
+}
+
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
return 0;
@@ -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;
@@ -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),
@@ -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,8 @@ 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;
/* exception/interrupt handling */
int error_code;
@@ -80,6 +80,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;
@@ -516,6 +517,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) {
@@ -762,6 +768,9 @@ 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_CONTENTS;
+ }
}
void kvm_arch_do_init_vcpu(X86CPU *cpu)
@@ -1322,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++],
@@ -1674,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;
@@ -1818,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;
@@ -2540,6 +2573,53 @@ static bool host_supports_vmx(void)
return ecx & CPUID_EXT_VMX;
}
+int kvm_arch_handle_hv_crash(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+ struct {
+ struct kvm_msrs info;
+ struct kvm_msr_entry entries[HV_X64_MSR_CRASH_PARAMS + 1];
+ } msr_data;
+ struct kvm_msr_entry *msrs = msr_data.entries;
+ int ret, n, i;
+
+ if (!has_msr_hv_crash) {
+ return -EINVAL;
+ }
+
+ for (n = 0; n < HV_X64_MSR_CRASH_PARAMS; n++) {
+ msrs[n].index = HV_X64_MSR_CRASH_P0 + n;
+ }
+
+ msrs[n++].index = HV_X64_MSR_CRASH_CTL;
+ msr_data.info = (struct kvm_msrs) {
+ .nmsrs = n,
+ };
+
+ ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
+ if (ret < 0) {
+ return ret;
+ }
+
+ for (i = 0; i < ret; i++) {
+ uint32_t index = msrs[i].index;
+
+ switch (index) {
+ 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 HV_X64_MSR_CRASH_CTL:
+ env->msr_hv_crash_ctl = msrs[i].data;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
#define VMX_INVALID_GUEST_STATE 0x80000021
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
@@ -661,6 +661,28 @@ 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_END_OF_LIST()
+ }
+};
+
static bool avx512_needed(void *opaque)
{
X86CPU *cpu = opaque;
@@ -842,6 +864,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
@@ -122,6 +122,11 @@ int kvm_arch_process_async_events(CPUState *cs)
return cs->halted;
}
+int kvm_arch_handle_hv_crash(CPUState *cs)
+{
+ return 0;
+}
+
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
int ret;
@@ -1564,6 +1564,11 @@ static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
return handle;
}
+int kvm_arch_handle_hv_crash(CPUState *cs)
+{
+ return 0;
+}
+
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -2002,6 +2002,11 @@ static int kvm_arch_handle_debug_exit(S390CPU *cpu)
return ret;
}
+int kvm_arch_handle_hv_crash(CPUState *cs)
+{
+ return 0;
+}
+
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
S390CPU *cpu = S390_CPU(cs);
@@ -1725,6 +1725,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) {