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é <berra...@redhat.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.d...@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

Reply via email to