Since QEMU 10.1.0 commit id '
6e250463b08b' guest crash information for
TDX is available in the QEMU monitor, e.g.:
{
"timestamp": {
"seconds":
1752118704,
"microseconds": 27480
},
"event": "GUEST_PANICKED",
"data": {
"action": "pause",
"info": {
"error-code": 0,
"message": "TD misconfiguration: SEPT #VE has to be disabled",
"type": "tdx"
}
}
}
Let's log this information into the domain log file, e.g.:
2025-07-10 03:39:18.243+0000: panic tdx: error_code='0x0' message='TD misconfiguration: SEPT #VE has to be disabled'
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
info->data.s390.psw_addr,
info->data.s390.reason);
break;
+ case QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_TDX:
+ if (info->data.tdx.has_gpa)
+ ret = g_strdup_printf("tdx: error_code='0x%x' message='%s' "
+ "additional error information can be found "
+ "at gpa page: '0x%016llx'",
+ info->data.tdx.error_code,
+ info->data.tdx.message,
+ info->data.tdx.gpa);
+ else
+ ret = g_strdup_printf("tdx: error_code='0x%x' message='%s'",
+ info->data.tdx.error_code,
+ info->data.tdx.message);
+ break;
case QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_NONE:
case QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_LAST:
break;
case QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_S390:
g_free(info->data.s390.reason);
break;
+ case QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_TDX:
+ g_free(info->data.tdx.message);
+ break;
case QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_NONE:
case QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_HYPERV:
case QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_LAST:
QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_NONE = 0,
QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_HYPERV,
QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_S390,
+ QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_TDX,
QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_LAST
} qemuMonitorEventPanicInfoType;
char *reason;
};
+typedef struct _qemuMonitorEventPanicInfoTDX qemuMonitorEventPanicInfoTDX;
+struct _qemuMonitorEventPanicInfoTDX {
+ /* TDX specific guest panic information */
+ int error_code;
+ char *message;
+ bool has_gpa;
+ unsigned long long gpa;
+};
+
typedef struct _qemuMonitorEventPanicInfo qemuMonitorEventPanicInfo;
struct _qemuMonitorEventPanicInfo {
qemuMonitorEventPanicInfoType type;
union {
qemuMonitorEventPanicInfoHyperv hyperv;
qemuMonitorEventPanicInfoS390 s390;
+ qemuMonitorEventPanicInfoTDX tdx;
} data;
};
return g_steal_pointer(&ret);
}
+static qemuMonitorEventPanicInfo *
+qemuMonitorJSONGuestPanicExtractInfoTDX(virJSONValue *data)
+{
+ g_autoptr(qemuMonitorEventPanicInfo) ret = NULL;
+ int error_code;
+ unsigned long long gpa = 0;
+ const char *message = NULL;
+ bool has_gpa;
+
+ ret = g_new0(qemuMonitorEventPanicInfo, 1);
+
+ ret->type = QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_TDX;
+ has_gpa = virJSONValueObjectHasKey(data, "gpa");
+
+ if (virJSONValueObjectGetNumberInt(data, "error-code", &error_code) < 0 ||
+ !(message = virJSONValueObjectGetString(data, "message")) ||
+ (has_gpa && virJSONValueObjectGetNumberUlong(data, "gpa", &gpa) < 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed TDX panic data"));
+ return NULL;
+ }
+
+ ret->data.tdx.error_code = error_code;
+ ret->data.tdx.gpa = gpa;
+ ret->data.tdx.has_gpa = has_gpa;
+
+ ret->data.tdx.message = g_strdup(message);
+
+ return g_steal_pointer(&ret);
+}
+
static qemuMonitorEventPanicInfo *
qemuMonitorJSONGuestPanicExtractInfo(virJSONValue *data)
{
return qemuMonitorJSONGuestPanicExtractInfoHyperv(data);
else if (STREQ_NULLABLE(type, "s390"))
return qemuMonitorJSONGuestPanicExtractInfoS390(data);
+ else if (STREQ_NULLABLE(type, "tdx"))
+ return qemuMonitorJSONGuestPanicExtractInfoTDX(data);
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown panic info type '%1$s'"), NULLSTR(type));