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(+)
@@ -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);
}
@@ -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
@@ -218,6 +218,7 @@ virDomainCapsFormat;
virDomainCapsNew;
virSEVCapabilitiesFree;
virSGXCapabilitiesFree;
+virVIRTCCACapabilitiesFree;
# conf/domain_conf.h
@@ -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;
}
@@ -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;
@@ -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,
@@ -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
@@ -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)
@@ -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