From 5ea63e7421dc9e4c711a9d206d6a6bcd9ad7561a Mon Sep 17 00:00:00 2001
From: panhengchang <panhengchang@huawei.com>
Date: Wed, 4 Jun 2025 09:38:52 +0800
Subject: [PATCH 1/2] add qemu VIRTCCA capability detection

This patch is used to detect virtcca capability
on Hisi Kunpeng platform through qmp command
"query-virtcca-capabilities". The result will
be formated to xml, such as
"<virtcca supoported='no'>" or
"<virtcca supoported='yes'>"

This function can be called by
"virsh domcapabilities" command or libvirt api
"qemuConnectGetDomainCapabilities".

Signed-off-by: panghengchang <panhengchang@huawei.com>
---
 src/conf/domain_capabilities.c |  35 +++++++++++
 src/conf/domain_capabilities.h |  11 ++++
 src/libvirt_private.syms       |   1 +
 src/qemu/qemu_capabilities.c   | 108 +++++++++++++++++++++++++++++++++
 src/qemu/qemu_capabilities.h   |   1 +
 src/qemu/qemu_monitor.c        |  10 +++
 src/qemu/qemu_monitor.h        |   3 +
 src/qemu/qemu_monitor_json.c   |  45 ++++++++++++++
 src/qemu/qemu_monitor_json.h   |   4 ++
 9 files changed, 218 insertions(+)

diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index f6e09dc584..4a83777e9c 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -88,6 +88,16 @@ virSGXCapabilitiesFree(virSGXCapability *cap)
 }
 
 
+void
+virVIRTCCACapabilitiesFree(virVIRTCCACapability *cap)
+{
+    if (!cap)
+        return;
+
+    g_free(cap);
+}
+
+
 static void
 virDomainCapsDispose(void *obj)
 {
@@ -101,6 +111,7 @@ virDomainCapsDispose(void *obj)
     virCPUDefFree(caps->cpu.hostModel);
     virSEVCapabilitiesFree(caps->sev);
     virSGXCapabilitiesFree(caps->sgx);
+    virVIRTCCACapabilitiesFree(caps->virtcca);
     g_free(caps->hyperv);
 
     values = &caps->os.loader.values;
@@ -707,6 +718,29 @@ virDomainCapsFeatureHypervFormat(virBuffer *buf,
     FORMAT_EPILOGUE(hyperv);
 }
 
+/**
+ * virDomainCapsFeatureVIRTCCAFormat:
+ * @buf: target buffer
+ * @virtcca: VIRTCCA features
+ *
+ * Format VIRTCCA features for inclusion in the domcapabilities XML.
+ *
+ * The resulting XML will look like
+ *
+ *   <virtcca supported='yes'/>
+ */
+static void
+virDomainCapsFeatureVIRTCCAFormat(virBuffer *buf,
+                              const virVIRTCCACapability *virtcca)
+{
+    if (!virtcca) {
+        virBufferAddLit(buf, "<virtcca supported='no'/>\n");
+        return;
+    }
+
+    virBufferAddLit(buf, "<virtcca supported='yes'/>\n");
+}
+
 static void
 virDomainCapsFormatFeatures(const virDomainCaps *caps,
                             virBuffer *buf)
@@ -728,6 +762,7 @@ virDomainCapsFormatFeatures(const virDomainCaps *caps,
     virDomainCapsFeatureSEVFormat(&childBuf, caps->sev);
     virDomainCapsFeatureSGXFormat(&childBuf, caps->sgx);
     virDomainCapsFeatureHypervFormat(&childBuf, caps->hyperv);
+    virDomainCapsFeatureVIRTCCAFormat(&childBuf, caps->virtcca);
 
     virXMLFormatElement(buf, "features", NULL, &childBuf);
 }
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
index 01bcfa2e39..718fb75467 100644
--- a/src/conf/domain_capabilities.h
+++ b/src/conf/domain_capabilities.h
@@ -231,6 +231,11 @@ struct _virSGXCapability {
     virSGXSection *sgxSections;
 };
 
+typedef struct _virVIRTCCACapability virVIRTCCACapability;
+struct _virVIRTCCACapability {
+    bool enabled;
+};
+
 STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_MODEL_LAST);
 STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_TYPE_LAST);
 STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_BACKEND_LAST);
@@ -284,6 +289,7 @@ struct _virDomainCaps {
     virSEVCapability *sev;
     virSGXCapability *sgx;
     virDomainCapsFeatureHyperv *hyperv;
+    virVIRTCCACapability *virtcca;
     /* add new domain features here */
 
     virTristateBool features[VIR_DOMAIN_CAPS_FEATURE_LAST];
@@ -339,3 +345,8 @@ void
 virSGXCapabilitiesFree(virSGXCapability *capabilities);
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSGXCapability, virSGXCapabilitiesFree);
+
+void
+virVIRTCCACapabilitiesFree(virVIRTCCACapability *capabilities);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virVIRTCCACapability, virVIRTCCACapabilitiesFree);
\ No newline at end of file
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4d712f0d79..cd99cc302a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -218,6 +218,7 @@ virDomainCapsFormat;
 virDomainCapsNew;
 virSEVCapabilitiesFree;
 virSGXCapabilitiesFree;
+virVIRTCCACapabilitiesFree;
 
 
 # conf/domain_conf.h
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 86f1491bc5..72c6eed5ef 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -699,6 +699,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
               "run-with.async-teardown", /* QEMU_CAPS_RUN_WITH_ASYNC_TEARDOWN */
               "virtio-blk-vhost-vdpa", /* QEMU_CAPS_DEVICE_VIRTIO_BLK_VHOST_VDPA */
               "smp-clusters", /* QEMU_CAPS_SMP_CLUSTERS */
+              "tmm-guest", /* QEMU_CAPS_VIRTCCA */
     );
 
 
@@ -784,6 +785,8 @@ struct _virQEMUCaps {
 
     virSGXCapability *sgxCapabilities;
 
+    virVIRTCCACapability *virtccaCapabilities;
+
     virDomainCapsFeatureHyperv *hypervCapabilities;
 
     /* Capabilities which may differ depending on the accelerator. */
@@ -1387,6 +1390,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
     { "virtio-crypto-device", QEMU_CAPS_DEVICE_VIRTIO_CRYPTO },
     { "cryptodev-backend-lkcf", QEMU_CAPS_OBJECT_CRYPTO_LKCF },
     { "pvpanic-pci", QEMU_CAPS_DEVICE_PANIC_PCI },
+    { "tmm-guest", QEMU_CAPS_VIRTCCA },
 };
 
 
@@ -1910,6 +1914,25 @@ virQEMUCapsSGXInfoCopy(virSGXCapability **dst,
 }
 
 
+static void
+virQEMUCapsVIRTCCAInfoCopy(virVIRTCCACapability **dst,
+                       virVIRTCCACapability *src)
+{
+    g_autoptr(virVIRTCCACapability) tmp = NULL;
+
+    if (!src) {
+        *dst = NULL;
+        return;
+    }
+
+    tmp = g_new0(virVIRTCCACapability, 1);
+
+    tmp->enabled = src->enabled;
+
+    *dst = g_steal_pointer(&tmp);
+}
+
+
 static void
 virQEMUCapsAccelCopyMachineTypes(virQEMUCapsAccel *dst,
                                  virQEMUCapsAccel *src)
@@ -1985,6 +2008,9 @@ virQEMUCaps *virQEMUCapsNewCopy(virQEMUCaps *qemuCaps)
     if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGX_EPC))
         virQEMUCapsSGXInfoCopy(&ret->sgxCapabilities, qemuCaps->sgxCapabilities);
 
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTCCA))
+        virQEMUCapsVIRTCCAInfoCopy(&ret->virtccaCapabilities, qemuCaps->virtccaCapabilities);
+
     ret->hypervCapabilities = g_memdup(qemuCaps->hypervCapabilities,
                                        sizeof(virDomainCapsFeatureHyperv));
 
@@ -2027,6 +2053,7 @@ void virQEMUCapsDispose(void *obj)
 
     virSEVCapabilitiesFree(qemuCaps->sevCapabilities);
     virSGXCapabilitiesFree(qemuCaps->sgxCapabilities);
+    virVIRTCCACapabilitiesFree(qemuCaps->virtccaCapabilities);
 
     g_free(qemuCaps->hypervCapabilities);
 
@@ -3485,6 +3512,31 @@ virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps,
 }
 
 
+static int
+virQEMUCapsProbeQMPVIRTCCACapabilities(virQEMUCaps *qemuCaps,
+                                   qemuMonitor *mon)
+{
+    int rc = -1;
+    virVIRTCCACapability *caps = NULL;
+
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTCCA))
+        return 0;
+
+    if ((rc = qemuMonitorGetVIRTCCACapabilities(mon, &caps)) < 0)
+        return -1;
+
+    /* VIRTCCA isn't actually supported */
+    if (rc == 0) {
+        virQEMUCapsClear(qemuCaps, QEMU_CAPS_VIRTCCA);
+        return 0;
+    }
+
+    virVIRTCCACapabilitiesFree(qemuCaps->virtccaCapabilities);
+    qemuCaps->virtccaCapabilities = caps;
+    return 0;
+}
+
+
 /*
  * Filter for features which should never be passed to QEMU. Either because
  * QEMU never supported them or they were dropped as they never did anything
@@ -4356,6 +4408,28 @@ virQEMUCapsParseSGXInfo(virQEMUCaps *qemuCaps,
 }
 
 
+static int
+virQEMUCapsParseVIRTCCAInfo(virQEMUCaps *qemuCaps,
+                        xmlXPathContextPtr ctxt)
+{
+    g_autoptr(virVIRTCCACapability) virtcca = NULL;
+
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTCCA))
+        return 0;
+
+    if (virXPathBoolean("boolean(./virtcca)", ctxt) == 0) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("missing virtcca platform data in QEMU capabilities cache"));
+        return -1;
+    }
+
+    virtcca = g_new0(virVIRTCCACapability, 1);
+
+    qemuCaps->virtccaCapabilities = g_steal_pointer(&virtcca);
+    return 0;
+}
+
+
 static int
 virQEMUCapsParseHypervCapabilities(virQEMUCaps *qemuCaps,
                                    xmlXPathContextPtr ctxt)
@@ -4682,6 +4756,9 @@ virQEMUCapsLoadCache(virArch hostArch,
     if (virQEMUCapsParseSGXInfo(qemuCaps, ctxt) < 0)
         return -1;
 
+    if (virQEMUCapsParseVIRTCCAInfo(qemuCaps, ctxt) < 0)
+        return -1;
+
     if (virQEMUCapsParseHypervCapabilities(qemuCaps, ctxt) < 0)
         return -1;
 
@@ -4910,6 +4987,14 @@ virQEMUCapsFormatSGXInfo(virQEMUCaps *qemuCaps,
 }
 
 
+static void
+virQEMUCapsFormatVIRTCCAInfo(virBuffer *buf)
+{
+    virBufferAddLit(buf, "<virtcca>\n");
+    virBufferAddLit(buf, "</virtcca>\n");
+}
+
+
 static void
 virQEMUCapsFormatHypervCapabilities(virQEMUCaps *qemuCaps,
                                     virBuffer *buf)
@@ -5018,6 +5103,9 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps)
     if (qemuCaps->sgxCapabilities)
         virQEMUCapsFormatSGXInfo(qemuCaps, &buf);
 
+    if (qemuCaps->virtccaCapabilities)
+        virQEMUCapsFormatVIRTCCAInfo(&buf);
+
     if (qemuCaps->hypervCapabilities)
         virQEMUCapsFormatHypervCapabilities(qemuCaps, &buf);
 
@@ -5572,6 +5660,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps,
         return -1;
     if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0)
         return -1;
+    if (virQEMUCapsProbeQMPVIRTCCACapabilities(qemuCaps, mon) < 0)
+        return -1;
 
     virQEMUCapsInitProcessCaps(qemuCaps);
 
@@ -6607,6 +6697,23 @@ virQEMUCapsFillDomainFeatureSEVCaps(virQEMUCaps *qemuCaps,
 }
 
 
+/**
+ * virQEMUCapsFillDomainFeatureVIRTCCACaps:
+ * @qemuCaps: QEMU capabilities
+ * @domCaps: domain capabilities
+ *
+ * Take the information about VIRTCCA capabilities that has been obtained
+ * using the 'query-virtcca-capabilities' QMP command and stored in @qemuCaps
+ * and convert it to a form suitable for @domCaps.
+ */
+static void
+virQEMUCapsFillDomainFeatureVIRTCCACaps(virQEMUCaps *qemuCaps,
+                                    virDomainCaps *domCaps)
+{
+    virQEMUCapsVIRTCCAInfoCopy(&domCaps->virtcca, qemuCaps->virtccaCapabilities);
+}
+
+
 static void
 virQEMUCapsFillDomainFeatureS390PVCaps(virQEMUCaps *qemuCaps,
                                        virDomainCaps *domCaps)
@@ -6706,6 +6813,7 @@ virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps,
     virQEMUCapsFillDomainFeatureSGXCaps(qemuCaps, domCaps);
     virQEMUCapsFillDomainFeatureHypervCaps(qemuCaps, domCaps);
     virQEMUCapsFillDomainDeviceCryptoCaps(qemuCaps, crypto);
+    virQEMUCapsFillDomainFeatureVIRTCCACaps(qemuCaps, domCaps);
 
     return 0;
 }
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index a928f5947d..f32109573c 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -678,6 +678,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
     QEMU_CAPS_RUN_WITH_ASYNC_TEARDOWN, /* asynchronous teardown -run-with async-teardown=on|off */
     QEMU_CAPS_DEVICE_VIRTIO_BLK_VHOST_VDPA, /* virtio-blk-vhost-vdpa block driver */
     QEMU_CAPS_SMP_CLUSTERS, /* -smp clusters= */
+    QEMU_CAPS_VIRTCCA, /* tmm-guest */
 
     QEMU_CAPS_LAST /* this must always be the last item */
 } virQEMUCapsFlags;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index e270bee2cd..3fd26a0433 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3469,6 +3469,16 @@ qemuMonitorGetSGXCapabilities(qemuMonitor *mon,
 }
 
 
+int
+qemuMonitorGetVIRTCCACapabilities(qemuMonitor *mon,
+                              virVIRTCCACapability **capabilities)
+{
+    QEMU_CHECK_MONITOR(mon);
+
+    return qemuMonitorJSONGetVIRTCCACapabilities(mon, capabilities);
+}
+
+
 int
 qemuMonitorNBDServerStart(qemuMonitor *mon,
                           const virStorageNetHostDef *server,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 4cbd225e8f..6c6e18da50 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -849,6 +849,9 @@ int qemuMonitorGetSEVCapabilities(qemuMonitor *mon,
 int qemuMonitorGetSGXCapabilities(qemuMonitor *mon,
                                   virSGXCapability **capabilities);
 
+int qemuMonitorGetVIRTCCACapabilities(qemuMonitor *mon,
+                              virVIRTCCACapability **capabilities);
+
 typedef enum {
   QEMU_MONITOR_MIGRATE_RESUME           = 1 << 0, /* resume failed post-copy migration */
   QEMU_MONITOR_MIGRATION_FLAGS_LAST
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 3748034bb9..7f23d034b8 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -6139,6 +6139,51 @@ qemuMonitorJSONGetSGXCapabilities(qemuMonitor *mon,
 }
 
 
+/**
+ * qemuMonitorJSONGetVIRTCCACapabilities:
+ * @mon: qemu monitor object
+ * @capabilities: pointer to pointer to a VIRTCCA capability structure to be filled
+ *
+ * Returns: -1 on error,
+ *          0 if VIRTCCA is not supported, and
+ *          1 if VIRTCCA is supported on the platform.
+ */
+int
+qemuMonitorJSONGetVIRTCCACapabilities(qemuMonitor *mon,
+                                  virVIRTCCACapability **capabilities)
+{
+    g_autoptr(virJSONValue) cmd = NULL;
+    g_autoptr(virJSONValue) reply = NULL;
+    g_autoptr(virVIRTCCACapability) capability = NULL;
+    virJSONValue *caps;
+
+    *capabilities = NULL;
+    capability = g_new0(virVIRTCCACapability, 1);
+
+    if (!(cmd = qemuMonitorJSONMakeCommand("query-virtcca-capabilities", NULL)))
+        return -1;
+
+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+        return -1;
+
+    /* QEMU not support VIRTCCA */
+    if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+        return 0;
+
+    caps = virJSONValueObjectGetObject(reply, "return");
+
+    if (virJSONValueObjectGetBoolean(caps, "enabled", &capability->enabled) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("query-virtcca-capabilities reply was missing 'enabled' field"));
+        return -1;
+    }
+
+    *capabilities = g_steal_pointer(&capability);
+
+    return 1;
+}
+
+
 static virJSONValue *
 qemuMonitorJSONBuildInetSocketAddress(const char *host,
                                       const char *port)
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index ed0027c118..2e0f2e2594 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -168,6 +168,10 @@ int
 qemuMonitorJSONGetSEVCapabilities(qemuMonitor *mon,
                                   virSEVCapability **capabilities);
 
+int
+qemuMonitorJSONGetVIRTCCACapabilities(qemuMonitor *mon,
+                                  virVIRTCCACapability **capabilities);
+
 int
 qemuMonitorJSONMigrate(qemuMonitor *mon,
                        unsigned int flags,
-- 
2.33.0