@@ -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;
}
}
@@ -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);
@@ -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,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);
@@ -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_crash(CPUState *cs, struct kvm_run *run)
+{
+ 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,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;
@@ -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)
@@ -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
@@ -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;
@@ -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);
@@ -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);
@@ -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) {