diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 3b4f7cdb43..7905343a55 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1358,11 +1358,12 @@ qemuMonitorEmitResume(qemuMonitorPtr mon) int -qemuMonitorEmitGuestPanic(qemuMonitorPtr mon) +qemuMonitorEmitGuestPanic(qemuMonitorPtr mon, + qemuMonitorEventPanicInfoPtr info) { int ret = -1; VIR_DEBUG("mon=%p", mon); - QEMU_MONITOR_CALLBACK(mon, ret, domainGuestPanic, mon->vm); + QEMU_MONITOR_CALLBACK(mon, ret, domainGuestPanic, mon->vm, info); return ret; } @@ -4240,3 +4241,13 @@ qemuMonitorQueryNamedBlockNodes(qemuMonitorPtr mon) return qemuMonitorJSONQueryNamedBlockNodes(mon); } + + +void +qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfoPtr info) +{ + if (!info) + return; + + VIR_FREE(info); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index ee8bf42d14..ad1e962768 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -70,6 +70,34 @@ struct _qemuMonitorMessage { void *passwordOpaque; }; +typedef enum { + QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_NONE = 0, + QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_HYPERV, + + QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_LAST +} qemuMonitorEventPanicInfoType; + +typedef struct _qemuMonitorEventPanicInfoHyperv qemuMonitorEventPanicInfoHyperv; +typedef qemuMonitorEventPanicInfoHyperv *qemuMonitorEventPanicInfoHypervPtr; +struct _qemuMonitorEventPanicInfoHyperv { + /* Hyper-V specific guest panic information (HV crash MSRs) */ + unsigned long long arg1; + unsigned long long arg2; + unsigned long long arg3; + unsigned long long arg4; + unsigned long long arg5; +}; + +typedef struct _qemuMonitorEventPanicInfo qemuMonitorEventPanicInfo; +typedef qemuMonitorEventPanicInfo *qemuMonitorEventPanicInfoPtr; +struct _qemuMonitorEventPanicInfo { + qemuMonitorEventPanicInfoType type; + union { + qemuMonitorEventPanicInfoHyperv hyperv; + } data; +}; + +void qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfoPtr info); typedef void (*qemuMonitorDestroyCallback)(qemuMonitorPtr mon, virDomainObjPtr vm, @@ -167,6 +195,7 @@ typedef int (*qemuMonitorDomainPMSuspendDiskCallback)(qemuMonitorPtr mon, void *opaque); typedef int (*qemuMonitorDomainGuestPanicCallback)(qemuMonitorPtr mon, virDomainObjPtr vm, + qemuMonitorEventPanicInfoPtr info, void *opaque); typedef int (*qemuMonitorDomainDeviceDeletedCallback)(qemuMonitorPtr mon, virDomainObjPtr vm, @@ -346,7 +375,8 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon, int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon, unsigned long long actual); int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon); -int qemuMonitorEmitGuestPanic(qemuMonitorPtr mon); +int qemuMonitorEmitGuestPanic(qemuMonitorPtr mon, + qemuMonitorEventPanicInfoPtr info); int qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon, const char *devAlias); int qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index e68c31ef45..b86d4d8e35 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -548,11 +548,63 @@ static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data qemuMonitorEmitResume(mon); } -static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED) + +static qemuMonitorEventPanicInfoPtr +qemuMonitorJSONGuestPanicExtractInfoHyperv(virJSONValuePtr data) { - qemuMonitorEmitGuestPanic(mon); + qemuMonitorEventPanicInfoPtr ret; + + if (VIR_ALLOC(ret) < 0) + return NULL; + + ret->type = QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_HYPERV; + + if (virJSONValueObjectGetNumberUlong(data, "arg1", &ret->data.hyperv.arg1) < 0 || + virJSONValueObjectGetNumberUlong(data, "arg2", &ret->data.hyperv.arg2) < 0 || + virJSONValueObjectGetNumberUlong(data, "arg3", &ret->data.hyperv.arg3) < 0 || + virJSONValueObjectGetNumberUlong(data, "arg4", &ret->data.hyperv.arg4) < 0 || + virJSONValueObjectGetNumberUlong(data, "arg5", &ret->data.hyperv.arg5) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed hyperv panic data")); + goto error; + } + + return ret; + + error: + qemuMonitorEventPanicInfoFree(ret); + return NULL; } + +static qemuMonitorEventPanicInfoPtr +qemuMonitorJSONGuestPanicExtractInfo(virJSONValuePtr data) +{ + const char *type = virJSONValueObjectGetString(data, "type"); + + if (STREQ_NULLABLE(type, "hyper-v")) + return qemuMonitorJSONGuestPanicExtractInfoHyperv(data); + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown panic info type '%s'"), NULLSTR(type)); + return NULL; +} + + +static void +qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, + virJSONValuePtr data) +{ + virJSONValuePtr infojson = virJSONValueObjectGetObject(data, "info"); + qemuMonitorEventPanicInfoPtr info = NULL; + + if (infojson) + info = qemuMonitorJSONGuestPanicExtractInfo(infojson); + + qemuMonitorEmitGuestPanic(mon, info); +} + + static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data) { long long offset = 0; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index b0e3e90964..a20beb13c1 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1298,6 +1298,7 @@ qemuProcessHandlePMSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED, static int qemuProcessHandleGuestPanic(qemuMonitorPtr mon ATTRIBUTE_UNUSED, virDomainObjPtr vm, + qemuMonitorEventPanicInfoPtr info, void *opaque) { virQEMUDriverPtr driver = opaque; @@ -1310,6 +1311,7 @@ qemuProcessHandleGuestPanic(qemuMonitorPtr mon ATTRIBUTE_UNUSED, processEvent->eventType = QEMU_PROCESS_EVENT_GUESTPANIC; processEvent->action = vm->def->onCrash; processEvent->vm = vm; + processEvent->data = info; /* Hold an extra reference because we can't allow 'vm' to be * deleted before handling guest panic event is finished. */