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(a)redhat.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan(a)intel.com>
---
src/qemu/qemu_monitor.c | 16 ++++++++++++++++
src/qemu/qemu_monitor.h | 11 +++++++++++
src/qemu/qemu_monitor_json.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 59 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 95c88fd5e8..b06949ab66 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3912,6 +3912,19 @@ qemuMonitorGuestPanicEventInfoFormatMsg(qemuMonitorEventPanicInfo
*info)
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;
@@ -3931,6 +3944,9 @@ qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfo *info)
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:
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 6030c31598..98eabbb89f 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -38,6 +38,7 @@ typedef enum {
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;
@@ -61,12 +62,22 @@ struct _qemuMonitorEventPanicInfoS390 {
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;
};
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 5297ffb027..6c2051ebfb 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -621,6 +621,36 @@ qemuMonitorJSONGuestPanicExtractInfoS390(virJSONValue *data)
return g_steal_pointer(&ret);
}
+static qemuMonitorEventPanicInfo *
+qemuMonitorJSONGuestPanicExtractInfoTDX(virJSONValue *data)
+{
+ g_autoptr(qemuMonitorEventPanicInfo) ret = NULL;
+ int error_code;
+ unsigned long long gpa;
+ 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)
{
@@ -630,6 +660,8 @@ 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));
--
2.47.1