@@ -527,4 +527,6 @@ int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source);
*/
int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target);
int kvm_get_max_memslots(void);
+
+void kvm_arch_save_crash_info(CPUState *cpu);
#endif
@@ -2000,6 +2000,7 @@ int kvm_cpu_exec(CPUState *cpu)
ret = EXCP_INTERRUPT;
break;
case KVM_SYSTEM_EVENT_CRASH:
+ kvm_arch_save_crash_info(cpu);
qemu_mutex_lock_iothread();
qemu_system_guest_panicked();
qemu_mutex_unlock_iothread();
@@ -5846,6 +5846,30 @@
'data': [ 'pause', 'poweroff' ] }
##
+# @GuestPanicInformation:
+#
+# Information about a guest panic
+#
+# Since: 2.9
+##
+{'union': 'GuestPanicInformation',
+ 'data': { 'hyper-v': 'GuestPanicInformationHyperV' } }
+
+##
+# @GuestPanicInformationHyperV:
+#
+# Hyper-V specific guest panic information (HV crash MSRs)
+#
+# Since: 2.9
+##
+{'struct': 'GuestPanicInformationHyperV',
+ 'data': { 'arg1': 'uint64',
+ 'arg2': 'uint64',
+ 'arg3': 'uint64',
+ 'arg4': 'uint64',
+ 'arg5': 'uint64' } }
+
+##
# @rtc-reset-reinjection:
#
# This command will reset the RTC interrupt reinjection backlog.
@@ -35,3 +35,4 @@ stub-obj-y += qmp_pc_dimm_device_list.o
stub-obj-y += target-monitor-defs.o
stub-obj-y += target-get-monitor-def.o
stub-obj-y += pc_madt_cpu_entry.o
+stub-obj-y += kvm-crash.o
new file mode 100644
@@ -0,0 +1,8 @@
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "sysemu/kvm.h"
+
+void kvm_arch_save_crash_info(CPUState *cs)
+{
+ return;
+}
@@ -3495,6 +3495,57 @@ static void x86_cpu_register_feature_bit_props(X86CPU *cpu,
x86_cpu_register_bit_prop(cpu, name, &cpu->env.features[w], bitnr);
}
+static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+ GuestPanicInformation *panic_info = NULL;
+
+ if (env->features[FEAT_HYPERV_EDX] & HV_X64_GUEST_CRASH_MSR_AVAILABLE) {
+ GuestPanicInformationHyperV *panic_info_hv =
+ g_malloc0(sizeof(GuestPanicInformationHyperV));
+ panic_info = g_malloc0(sizeof(GuestPanicInformation));
+
+ panic_info->type = GUEST_PANIC_INFORMATION_KIND_HYPER_V;
+ panic_info->u.hyper_v.data = panic_info_hv;
+
+ assert(HV_X64_MSR_CRASH_PARAMS >= 5);
+ panic_info_hv->arg1 = cpu->hv_msr_crash_params[0];
+ panic_info_hv->arg2 = cpu->hv_msr_crash_params[1];
+ panic_info_hv->arg3 = cpu->hv_msr_crash_params[2];
+ panic_info_hv->arg4 = cpu->hv_msr_crash_params[3];
+ panic_info_hv->arg5 = cpu->hv_msr_crash_params[4];
+ }
+
+ return panic_info;
+}
+static void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CPUState *cs = CPU(obj);
+ GuestPanicInformation *panic_info;
+
+ if (!cs->crash_occurred) {
+ error_setg(errp, "No crash occured");
+ return;
+ }
+
+ panic_info = x86_cpu_get_crash_info(cs);
+ if (panic_info == NULL) {
+ error_setg(errp, "No crash information");
+ return;
+ }
+
+ visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
+ errp);
+
+ if (panic_info->type == GUEST_PANIC_INFORMATION_KIND_HYPER_V) {
+ g_free(panic_info->u.hyper_v.data);
+ }
+ g_free(panic_info);
+}
+
static void x86_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@@ -3530,6 +3581,9 @@ static void x86_cpu_initfn(Object *obj)
x86_cpu_get_feature_words,
NULL, NULL, (void *)cpu->filtered_features, NULL);
+ object_property_add(obj, "crash-information", "GuestPanicInformation",
+ x86_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL);
+
cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
for (w = 0; w < FEATURE_WORDS; w++) {
@@ -1258,6 +1258,9 @@ struct X86CPU {
/* Number of physical address bits supported */
uint32_t phys_bits;
+ /* Hyper-V crash MSRs */
+ uint64_t hv_msr_crash_params[HV_X64_MSR_CRASH_PARAMS];
+
/* in order to simplify APIC support, we leave this pointer to the
user */
struct DeviceState *apic_state;
@@ -2054,6 +2054,36 @@ static int kvm_get_sregs(X86CPU *cpu)
return 0;
}
+static int kvm_read_msr_hv_crash(X86CPU *cpu, uint64_t *buf)
+{
+ int i, ret;
+ struct {
+ struct kvm_msrs info;
+ struct kvm_msr_entry entries[HV_X64_MSR_CRASH_PARAMS];
+ } msr_data;
+
+ if (!has_msr_hv_crash) {
+ return -ENOSYS;
+ }
+
+ for (i = 0; i < HV_X64_MSR_CRASH_PARAMS; i++) {
+ msr_data.entries[i].index = HV_X64_MSR_CRASH_P0 + i;
+ }
+ msr_data.info.nmsrs = HV_X64_MSR_CRASH_PARAMS;
+
+ ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
+ if (ret < 0) {
+ return ret;
+ }
+
+ for (i = 0; i < ret; i++) {
+ const struct kvm_msr_entry *msr = msr_data.entries + i;
+ buf[msr->index - HV_X64_MSR_CRASH_P0] = msr->data;
+ }
+
+ return 0;
+}
+
static int kvm_get_msrs(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
@@ -2801,6 +2831,17 @@ int kvm_arch_get_registers(CPUState *cs)
return ret;
}
+void kvm_arch_save_crash_info(CPUState *cs)
+{
+ if (has_msr_hv_crash) {
+ X86CPU *cpu = X86_CPU(cs);
+ int ret = kvm_read_msr_hv_crash(cpu, cpu->hv_msr_crash_params);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to get HV crash parameters\n");
+ }
+ }
+}
+
void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
{
X86CPU *x86_cpu = X86_CPU(cpu);