- This patch adds Arm CCA support to qemu driver for aarch64 system.
CCA is an abbreviation for Arm Confidential Compute Architecture feature,
it enhances the virtualization capabilities of the platform by separating
the management of resources from access to those resources.
[summary]
- At this stage, all you can do is getting the CCA capability with the virsh
domcapabilities command and start the CCA VM with the virsh create command.
[Capability example]
- Execution results of 'virsh domcapability" on qemu
<domaincapabilities>
...
<features>
...
</sgx>
<cca supported='yes'>
<enum name='measurement-algo'>
<value>sha256</value>
<value>sha512</value>
</enum>
</cca>
<hyperv supported='yes'>
...
</features>
</domaincapabilities>
[XML example]
<domain>
...
<launchsecurity type='cca'>
<measurement-algo>sha256</measurement-algo>
</launchsecurity>
...
</domain>
Signed-off-by: Akio Kakuno <fj3333bs(a)fujitsu.com>
---
docs/formatdomain.rst | 28 ++++++
docs/formatdomaincaps.rst | 26 ++++-
src/conf/domain_capabilities.c | 41 ++++++++
src/conf/domain_capabilities.h | 12 +++
src/conf/domain_conf.c | 13 +++
src/conf/domain_conf.h | 7 ++
src/conf/schemas/domaincaps.rng | 14 +++
src/conf/schemas/domaincommon.rng | 14 +++
src/conf/virconftypes.h | 2 +
src/libvirt_private.syms | 1 +
src/qemu/qemu_capabilities.c | 156 ++++++++++++++++++++++++++++++
src/qemu/qemu_capabilities.h | 4 +
src/qemu/qemu_cgroup.c | 2 +
src/qemu/qemu_command.c | 32 ++++++
src/qemu/qemu_driver.c | 2 +
src/qemu/qemu_monitor.c | 10 ++
src/qemu/qemu_monitor.h | 3 +
src/qemu/qemu_monitor_json.c | 104 ++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 4 +
src/qemu/qemu_namespace.c | 2 +
src/qemu/qemu_process.c | 4 +
src/qemu/qemu_validate.c | 7 ++
22 files changed, 487 insertions(+), 1 deletion(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 3253a28e5a..08e0abf0f3 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -9040,6 +9040,34 @@ The ``<launchSecurity/>`` element then accepts the following
child elements:
the SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI.
+The contents of the ``<launchSecurity type='cca'>`` element is used to
create
+RealmVM using the Arm CCA feature (Confidential Compute Architecture).
+CCA :since:`Since 10.9.0` enhances the virtualization capabilities of the
+platform by separating the management of resources from access to those resources.
+This is achieved by extending the TrustZone of Cortex-A's Normal and Secure
+world concepts and adding the Realm world and the underlying Root world.
+The Secure Monitor runs in the root world and manages the transition between
+these security states. For more information see the Learn the architecture -
+Arm Confidential Compute Architecture software stack:
+`<https://developer.arm.com/documentation/den0127/latest>`__
+
+::
+
+ <domain>
+ ...
+ <launchSecurity type='cca'>
+ <measurement-algo>sha256</measurement-algo>
+ </launchSecurity>
+ ...
+ </domain>
+
+The ``<launchSecurity/>`` element accepts the following attributes:
+
+``measurement-algo``
+ The optional ``measurement-algo`` element determines algorithm used to
+ describe blob hashes.
+
+
Example configs
===============
diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst
index 5309c6c251..7457c3ac98 100644
--- a/docs/formatdomaincaps.rst
+++ b/docs/formatdomaincaps.rst
@@ -708,6 +708,12 @@ capabilities. All features occur as children of the main ``features``
element.
<section node='1' size='262144' unit='KiB'/>
</sections>
</sgx>
+ <cca supported='yes'>
+ <enum name='measurement-algo'>
+ <value>sha256</value>
+ <value>sha512</value>
+ </enum>
+ </cca>
<hyperv supported='yes'>
<enum name='features'>
<value>relaxed</value>
@@ -835,6 +841,23 @@ document store. In order to use SGX with libvirt have a look at `SGX
in domain X
``sections``
The sections of the SGX enclave page cache (called EPC).
+CCA capabilities
+^^^^^^^^^^^^^^^^
+
+Arm Confidential Compute Architecture (CCA) capabilities are exposed under the
+``cca`` element.
+
+Arm CCA is a system solution comprised of hardware and software components that
+maximizes the security of data on devices and in the cloud.
+CCA enhances the virtualization capabilities of the platform by separating the
+management of resources from access to those resources.
+
+For more details on the CCA feature, please follow resources in the CCA developer's
+document store. In order to use CCA with libvirt have a look at `CCA in domain
+XML <formatdomain.html#launch-security>`__
+
+``measurement-algo``
+ Options for the ``measurement-algo`` used to describe blob hashes.
Hyper-V Enlightenments
^^^^^^^^^^^^^^^^^^^^^^
@@ -856,4 +879,5 @@ The ``sectype`` enum corresponds to ``type`` attribute of
``<launchSecurity/>``
element as documented in `Launch Security
<formatdomain.html#launch-security>`__. :since:`(Since 10.5.0)` For additional
information on individual types, see sections above: `s390-pv capability`_ for
-S390 PV, `SEV capabilities`_ for AMD SEV and/or AMD SEV-SNP.
+S390 PV, `SEV capabilities`_ for AMD SEV and/or AMD SEV-SNP, `CCA capabilities`_
+for Arm CCA.
diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index cf40d798e5..0a79fc0279 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -90,6 +90,19 @@ virSGXCapabilitiesFree(virSGXCapability *cap)
}
+void
+virCCACapabilitiesFree(virCCACapability *cap)
+{
+ if (!cap)
+ return;
+
+ if (cap->ccaMeasurementAlgo)
+ g_free(cap->ccaMeasurementAlgo);
+
+ g_free(cap);
+}
+
+
static void
virDomainCapsDispose(void *obj)
{
@@ -755,6 +768,33 @@ virDomainCapsFeatureSGXFormat(virBuffer *buf,
virBufferAddLit(buf, "</sgx>\n");
}
+static void
+virDomainCapsFeatureCCAFormat(virBuffer *buf,
+ const virCCACapability *cca)
+{
+ size_t i;
+
+ if (!cca) {
+ virBufferAddLit(buf, "<cca supported='no'/>\n");
+ return;
+ }
+
+ virBufferAddLit(buf, "<cca supported='yes'>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferAddLit(buf, "<enum name='measurement-algo'>\n");
+ virBufferAdjustIndent(buf, 2);
+ for (i = 0; i < cca->nCcaMeasurementAlgo; i++) {
+ virBufferAsprintf(buf, "<value>%s</value>\n",
+ cca->ccaMeasurementAlgo[i]);
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</enum>\n");
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</cca>\n\n");
+}
+
static void
virDomainCapsFeatureHypervFormat(virBuffer *buf,
const virDomainCapsFeatureHyperv *hyperv)
@@ -802,6 +842,7 @@ virDomainCapsFormatFeatures(const virDomainCaps *caps,
virDomainCapsFeatureSEVFormat(&childBuf, caps->sev);
virDomainCapsFeatureSGXFormat(&childBuf, caps->sgx);
+ virDomainCapsFeatureCCAFormat(&childBuf, caps->cca);
virDomainCapsFeatureHypervFormat(&childBuf, caps->hyperv);
virDomainCapsLaunchSecurityFormat(&childBuf, &caps->launchSecurity);
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
index a706ab337e..ef925fda0a 100644
--- a/src/conf/domain_capabilities.h
+++ b/src/conf/domain_capabilities.h
@@ -239,6 +239,12 @@ struct _virSGXCapability {
virSGXSection *sgxSections;
};
+typedef struct _virCCACapability virCCACapability;
+struct _virCCACapability {
+ size_t nCcaMeasurementAlgo;
+ char **ccaMeasurementAlgo;
+};
+
STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_MODEL_LAST);
STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_TYPE_LAST);
STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_BACKEND_LAST);
@@ -300,6 +306,7 @@ struct _virDomainCaps {
virDomainCapsFeatureGIC gic;
virSEVCapability *sev;
virSGXCapability *sgx;
+ virCCACapability *cca;
virDomainCapsFeatureHyperv *hyperv;
virDomainCapsLaunchSecurity launchSecurity;
/* add new domain features here */
@@ -359,3 +366,8 @@ void
virSGXCapabilitiesFree(virSGXCapability *capabilities);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSGXCapability, virSGXCapabilitiesFree);
+
+void
+virCCACapabilitiesFree(virCCACapability *capabilities);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCCACapability, virCCACapabilitiesFree);
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 6d7dee7956..62debe9eaa 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1515,6 +1515,7 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity,
"sev",
"sev-snp",
"s390-pv",
+ "cca",
);
VIR_ENUM_IMPL(virDomainPstoreBackend,
@@ -13775,6 +13776,15 @@ virDomainSEVSNPDefParseXML(virDomainSEVSNPDef *def,
}
+static int
+virDomainCCADefParseXML(virDomainCCADef *def,
+ xmlXPathContextPtr ctxt)
+{
+ def->measurement_algo = virXPathString("string(./measurement-algo)",
ctxt);
+ return 0;
+}
+
+
static virDomainSecDef *
virDomainSecDefParseXML(xmlNodePtr lsecNode,
xmlXPathContextPtr ctxt)
@@ -13800,6 +13810,9 @@ virDomainSecDefParseXML(xmlNodePtr lsecNode,
break;
case VIR_DOMAIN_LAUNCH_SECURITY_PV:
break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ virDomainCCADefParseXML(&sec->data.cca, ctxt);
+ break;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
default:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a15af4fae3..c13b7995d3 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2870,6 +2870,7 @@ typedef enum {
VIR_DOMAIN_LAUNCH_SECURITY_SEV,
VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP,
VIR_DOMAIN_LAUNCH_SECURITY_PV,
+ VIR_DOMAIN_LAUNCH_SECURITY_CCA,
VIR_DOMAIN_LAUNCH_SECURITY_LAST,
} virDomainLaunchSecurity;
@@ -2904,11 +2905,17 @@ struct _virDomainSEVSNPDef {
};
+struct _virDomainCCADef {
+ char *measurement_algo;
+};
+
+
struct _virDomainSecDef {
virDomainLaunchSecurity sectype;
union {
virDomainSEVDef sev;
virDomainSEVSNPDef sev_snp;
+ virDomainCCADef cca;
} data;
};
diff --git a/src/conf/schemas/domaincaps.rng b/src/conf/schemas/domaincaps.rng
index f9b87c8a59..5379bfb45c 100644
--- a/src/conf/schemas/domaincaps.rng
+++ b/src/conf/schemas/domaincaps.rng
@@ -334,6 +334,9 @@
<optional>
<ref name="sgx"/>
</optional>
+ <optional>
+ <ref name="cca"/>
+ </optional>
<optional>
<ref name="hyperv"/>
</optional>
@@ -452,6 +455,17 @@
</element>
</define>
+ <define name="cca">
+ <element name="cca">
+ <ref name="supported"/>
+ <optional>
+ <element name="measurement-algo">
+ <text/>
+ </element>
+ </optional>
+ </element>
+ </define>
+
<define name="hyperv">
<element name="hyperv">
<ref name="supported"/>
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index efb5f00d77..7cea83cc01 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -523,6 +523,9 @@
<value>s390-pv</value>
</attribute>
</group>
+ <group>
+ <ref name="launchSecurityCCA"/>
+ </group>
</choice>
</element>
</define>
@@ -618,6 +621,17 @@
</optional>
</interleave>
</define>
+
+ <define name="launchSecurityCCA">
+ <attribute name="type">
+ <value>cca</value>
+ </attribute>
+ <optional>
+ <element name="measurement-algo">
+ <data type="string"/>
+ </element>
+ </optional>
+ </define>
<!--
Enable or disable perf events for the domain. For each
of the events the following rules apply:
diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
index f18ebcca10..76218f51b4 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -216,6 +216,8 @@ typedef struct _virDomainSEVDef virDomainSEVDef;
typedef struct _virDomainSEVSNPDef virDomainSEVSNPDef;
+typedef struct _virDomainCCADef virDomainCCADef;
+
typedef struct _virDomainSecDef virDomainSecDef;
typedef struct _virDomainShmemDef virDomainShmemDef;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5fb4df3513..7f3886ecd7 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -221,6 +221,7 @@ virDomainCapsFormat;
virDomainCapsNew;
virSEVCapabilitiesFree;
virSGXCapabilitiesFree;
+virCCACapabilitiesFree;
# conf/domain_conf.h
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 9322ae9ae6..43e7a164ea 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -719,6 +719,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
/* 465 */
"snapshot-internal-qmp", /* QEMU_CAPS_SNAPSHOT_INTERNAL_QMP */
"chardev-reconnect-miliseconds", /*
QEMU_CAPS_CHARDEV_RECONNECT_MILISECONDS */
+ "rme-guest", /* QEMU_CAPS_CCA_GUEST */
);
@@ -804,6 +805,8 @@ struct _virQEMUCaps {
virSGXCapability *sgxCapabilities;
+ virCCACapability *ccaCapabilities;
+
virDomainCapsFeatureHyperv *hypervCapabilities;
/* Capabilities which may differ depending on the accelerator. */
@@ -1407,6 +1410,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
{ "virtio-sound-device", QEMU_CAPS_DEVICE_VIRTIO_SOUND },
{ "sev-snp-guest", QEMU_CAPS_SEV_SNP_GUEST },
{ "acpi-erst", QEMU_CAPS_DEVICE_ACPI_ERST },
+ { "rme-guest", QEMU_CAPS_CCA_GUEST },
};
@@ -1942,6 +1946,34 @@ virQEMUCapsSGXInfoCopy(virSGXCapability **dst,
}
+static void
+virQEMUCapsCCAInfoCopy(virCCACapability **dst,
+ virCCACapability *src)
+{
+ g_autoptr(virCCACapability) tmp = NULL;
+ size_t i;
+
+ if (!src) {
+ *dst = NULL;
+ return;
+ }
+
+ tmp = g_new0(virCCACapability, 1);
+
+ tmp->nCcaMeasurementAlgo = src->nCcaMeasurementAlgo;
+
+ if (tmp->nCcaMeasurementAlgo != 0) {
+ tmp->ccaMeasurementAlgo = g_new0(char *, tmp->nCcaMeasurementAlgo);
+
+ for (i=0; i<tmp->nCcaMeasurementAlgo; i++) {
+ tmp->ccaMeasurementAlgo[i] = src->ccaMeasurementAlgo[i];
+ }
+ }
+
+ *dst = g_steal_pointer(&tmp);
+}
+
+
static void
virQEMUCapsAccelCopyMachineTypes(virQEMUCapsAccel *dst,
virQEMUCapsAccel *src)
@@ -2017,6 +2049,9 @@ virQEMUCaps *virQEMUCapsNewCopy(virQEMUCaps *qemuCaps)
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGX_EPC))
virQEMUCapsSGXInfoCopy(&ret->sgxCapabilities,
qemuCaps->sgxCapabilities);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCA_GUEST))
+ virQEMUCapsCCAInfoCopy(&ret->ccaCapabilities,
qemuCaps->ccaCapabilities);
+
ret->hypervCapabilities = g_memdup(qemuCaps->hypervCapabilities,
sizeof(virDomainCapsFeatureHyperv));
@@ -2654,6 +2689,13 @@ virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps)
}
+virCCACapability *
+virQEMUCapsGetCCACapabilities(virQEMUCaps *qemuCaps)
+{
+ return qemuCaps->ccaCapabilities;
+}
+
+
static int
virQEMUCapsProbeQMPObjectTypes(virQEMUCaps *qemuCaps,
qemuMonitor *mon)
@@ -3571,6 +3613,32 @@ virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps,
}
+static int
+virQEMUCapsProbeQMPCCACapabilities(virQEMUCaps *qemuCaps,
+ qemuMonitor *mon)
+{
+ int rc = -1;
+ virCCACapability *caps = NULL;
+
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCA_GUEST))
+ return 0;
+
+ if ((rc = qemuMonitorGetCCACapabilities(mon, &caps)) < 0)
+ return -1;
+
+ /* CCA isn't actually supported */
+ if (rc == 0) {
+ virQEMUCapsClear(qemuCaps, QEMU_CAPS_CCA_GUEST);
+ return 0;
+ }
+
+ virCCACapabilitiesFree(qemuCaps->ccaCapabilities);
+ qemuCaps->ccaCapabilities = 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
@@ -4438,6 +4506,41 @@ virQEMUCapsParseSGXInfo(virQEMUCaps *qemuCaps,
}
+static int
+virQEMUCapsParseCCAInfo(virQEMUCaps *qemuCaps,
+ xmlXPathContextPtr ctxt)
+{
+ g_autofree xmlNodePtr *nodes = NULL;
+ g_autoptr(virCCACapability) tmp = NULL;
+ size_t i;
+ int n;
+
+ if ((n = virXPathNodeSet("./cca", ctxt, &nodes)) < 0)
+ return -1;
+
+ tmp = g_new0(virCCACapability, 1);
+ tmp->nCcaMeasurementAlgo = n;
+
+ if (tmp->nCcaMeasurementAlgo > 0) {
+ tmp->ccaMeasurementAlgo = g_new0(char *, tmp->nCcaMeasurementAlgo);
+
+ for (i = 0; i < n; i++) {
+ char *malgo = NULL;
+ if (!(malgo = virXMLPropString(nodes[i], "measurement-algo"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing CCA measurement-algo in QEMU capabilities
cache"));
+ return -1;
+ }
+
+ tmp->ccaMeasurementAlgo[i] = g_strdup(malgo);
+ }
+ }
+
+ qemuCaps->ccaCapabilities = g_steal_pointer(&tmp);
+ return 0;
+}
+
+
static int
virQEMUCapsParseHypervCapabilities(virQEMUCaps *qemuCaps,
xmlXPathContextPtr ctxt)
@@ -4758,6 +4861,9 @@ virQEMUCapsLoadCache(virArch hostArch,
if (virQEMUCapsParseSGXInfo(qemuCaps, ctxt) < 0)
return -1;
+ if (virQEMUCapsParseCCAInfo(qemuCaps, ctxt) < 0)
+ return -1;
+
if (virQEMUCapsParseHypervCapabilities(qemuCaps, ctxt) < 0)
return -1;
@@ -4986,6 +5092,31 @@ virQEMUCapsFormatSGXInfo(virQEMUCaps *qemuCaps,
}
+static void
+virQEMUCapsFormatCCAInfo(virQEMUCaps *qemuCaps, virBuffer *buf)
+{
+ virCCACapability *cca = virQEMUCapsGetCCACapabilities(qemuCaps);
+ size_t i;
+ size_t n;
+
+ virBufferAddLit(buf, "<cca>\n");
+
+ n = cca->nCcaMeasurementAlgo;
+
+ if (n != 0) {
+ virBufferAdjustIndent(buf, 2);
+
+ for (i = 0; i < n; i++) {
+ virBufferAsprintf(buf,
"<measurement-algo>%s</measurement-algo>\n",
cca->ccaMeasurementAlgo[i]);
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ }
+
+ virBufferAddLit(buf, "</cca>\n");
+}
+
+
static void
virQEMUCapsFormatHypervCapabilities(virQEMUCaps *qemuCaps,
virBuffer *buf)
@@ -5094,6 +5225,9 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps)
if (qemuCaps->sgxCapabilities)
virQEMUCapsFormatSGXInfo(qemuCaps, &buf);
+ if (qemuCaps->ccaCapabilities)
+ virQEMUCapsFormatCCAInfo(qemuCaps, &buf);
+
if (qemuCaps->hypervCapabilities)
virQEMUCapsFormatHypervCapabilities(qemuCaps, &buf);
@@ -5646,6 +5780,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps,
return -1;
if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0)
return -1;
+ if (virQEMUCapsProbeQMPCCACapabilities(qemuCaps, mon) < 0)
+ return -1;
virQEMUCapsInitProcessCaps(qemuCaps);
@@ -6618,6 +6754,8 @@ virQEMUCapsFillDomainLaunchSecurity(virQEMUCaps *qemuCaps,
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_S390_PV_GUEST) &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_MACHINE_CONFIDENTAL_GUEST_SUPPORT))
VIR_DOMAIN_CAPS_ENUM_SET(launchSecurity->sectype,
VIR_DOMAIN_LAUNCH_SECURITY_PV);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCA_GUEST))
+ VIR_DOMAIN_CAPS_ENUM_SET(launchSecurity->sectype,
VIR_DOMAIN_LAUNCH_SECURITY_CCA);
if (launchSecurity->sectype.values == 0) {
launchSecurity->supported = VIR_TRISTATE_BOOL_NO;
@@ -6786,6 +6924,23 @@ virQEMUCapsFillDomainFeatureSGXCaps(virQEMUCaps *qemuCaps,
}
+/**
+ * virQEMUCapsFillDomainFeatureCCACaps:
+ * @qemuCaps: QEMU capabilities
+ * @domCaps: domain capabilities
+ *
+ * Take the information about CCA capabilities that has been obtained
+ * using the 'query-cca-capabilities' QMP command and stored in @qemuCaps
+ * and convert it to a form suitable for @domCaps.
+ */
+static void
+virQEMUCapsFillDomainFeatureCCACaps(virQEMUCaps *qemuCaps,
+ virDomainCaps *domCaps)
+{
+ virQEMUCapsCCAInfoCopy(&domCaps->cca, qemuCaps->ccaCapabilities);
+}
+
+
static void
virQEMUCapsFillDomainFeatureHypervCaps(virQEMUCaps *qemuCaps,
virDomainCaps *domCaps)
@@ -6855,6 +7010,7 @@ virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps,
virQEMUCapsFillDomainFeatureS390PVCaps(qemuCaps, domCaps);
virQEMUCapsFillDomainFeaturePS2Caps(qemuCaps, domCaps);
virQEMUCapsFillDomainFeatureSGXCaps(qemuCaps, domCaps);
+ virQEMUCapsFillDomainFeatureCCACaps(qemuCaps, domCaps);
virQEMUCapsFillDomainFeatureHypervCaps(qemuCaps, domCaps);
virQEMUCapsFillDomainDeviceCryptoCaps(qemuCaps, crypto);
virQEMUCapsFillDomainLaunchSecurity(qemuCaps, launchSecurity);
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 54c7e30903..ea6e397037 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -698,6 +698,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check
*/
/* 465 */
QEMU_CAPS_SNAPSHOT_INTERNAL_QMP, /* internal snapshot support via QMP commands
'snapshot-save'/'snapshot-delete' */
QEMU_CAPS_CHARDEV_RECONNECT_MILISECONDS, /* 'reconnect-ms' option for
chardevs supported */
+ QEMU_CAPS_CCA_GUEST, /* -object rme-guest */
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
@@ -917,6 +918,9 @@ virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps);
virSGXCapability *
virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps);
+virCCACapability *
+virQEMUCapsGetCCACapabilities(virQEMUCaps *qemuCaps);
+
bool
virQEMUCapsGetKVMSupportsSecureGuest(virQEMUCaps *qemuCaps) G_NO_INLINE;
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 23b7e6b4e8..647ec8da86 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -852,6 +852,8 @@ qemuSetupDevicesCgroup(virDomainObj *vm)
if (qemuSetupSEVCgroup(vm) < 0)
return -1;
break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ break;
case VIR_DOMAIN_LAUNCH_SECURITY_PV:
break;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a5ff7695c3..60ae213729 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6894,6 +6894,9 @@ qemuBuildMachineCommandLine(virCommand *cmd,
case VIR_DOMAIN_LAUNCH_SECURITY_PV:
virBufferAddLit(&buf, ",confidential-guest-support=lsec0");
break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ virBufferAddLit(&buf, ",confidential-guest-support=rme0");
+ break;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
virReportEnumRangeError(virDomainLaunchSecurity, def->sec->sectype);
@@ -9644,6 +9647,32 @@ qemuBuildPVCommandLine(virDomainObj *vm, virCommand *cmd)
}
+static int
+qemuBuildCCACommandLine(virDomainObj *vm, virCommand *cmd,
+ virDomainCCADef *cca)
+{
+ g_autoptr(virJSONValue) props = NULL;
+ qemuDomainObjPrivate *priv = vm->privateData;
+
+ VIR_DEBUG("measurement_algorithm=%s", cca->measurement_algo);
+
+ if (cca->measurement_algo) {
+ if (qemuMonitorCreateObjectProps(&props, "rme-guest",
"rme0",
+ "S:measurement-algorithm",
cca->measurement_algo,
+ NULL) < 0)
+ return -1;
+ } else {
+ if (qemuMonitorCreateObjectProps(&props, "rme-guest",
"rme0", NULL) < 0)
+ return -1;
+ }
+
+ if (qemuBuildObjectCommandlineFromJSON(cmd, props, priv->qemuCaps) < 0)
+ return -1;
+
+ return 0;
+}
+
+
static int
qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd,
virDomainSecDef *sec)
@@ -9661,6 +9690,9 @@ qemuBuildSecCommandLine(virDomainObj *vm, virCommand *cmd,
case VIR_DOMAIN_LAUNCH_SECURITY_PV:
return qemuBuildPVCommandLine(vm, cmd);
break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ return qemuBuildCCACommandLine(vm, cmd, &sec->data.cca);
+ break;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
virReportEnumRangeError(virDomainLaunchSecurity, sec->sectype);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 72211da137..9745086c6a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -19145,6 +19145,8 @@ qemuDomainGetLaunchSecurityInfo(virDomainPtr domain,
if (qemuDomainGetSEVInfo(vm, params, nparams, flags) < 0)
goto cleanup;
break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ break;
case VIR_DOMAIN_LAUNCH_SECURITY_PV:
break;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index fd888e2468..56cee3e7a6 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3472,6 +3472,16 @@ qemuMonitorGetSGXCapabilities(qemuMonitor *mon,
}
+int
+qemuMonitorGetCCACapabilities(qemuMonitor *mon,
+ virCCACapability **capabilities)
+{
+ QEMU_CHECK_MONITOR(mon);
+
+ return qemuMonitorJSONGetCCACapabilities(mon, capabilities);
+}
+
+
int
qemuMonitorNBDServerStart(qemuMonitor *mon,
const virStorageNetHostDef *server,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 4341519cfe..451ad2ff47 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -839,6 +839,9 @@ int qemuMonitorGetSEVCapabilities(qemuMonitor *mon,
int qemuMonitorGetSGXCapabilities(qemuMonitor *mon,
virSGXCapability **capabilities);
+int qemuMonitorGetCCACapabilities(qemuMonitor *mon,
+ virCCACapability **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 c594b33106..2b0daa08db 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -6153,6 +6153,110 @@ qemuMonitorJSONGetSGXCapabilities(qemuMonitor *mon,
}
+static int
+qemuMonitorJSONGetCCAMeasurementAlgo(qemuMonitor *mon,
+ size_t *numalgo,
+ char ***malgo)
+{
+ g_autoptr(virJSONValue) cmd = NULL;
+ g_autoptr(virJSONValue) reply = NULL;
+ virJSONValue *caps;
+ virJSONValue *malgolist = NULL;
+ g_auto(GStrv) list = NULL;
+ size_t i;
+ size_t n = 0;
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("query-cca-capabilities",
+ NULL)))
+ return -1;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ return -1;
+
+ /* If the 'query-cca-capabilities' QMP command was not available
+ * we simply successfully return zero capabilities.
+ * This is the current QEMU (=9.1.91) and all non-ARM architectures */
+ if (qemuMonitorJSONHasError(reply, "CommandNotFound"))
+ return 0;
+
+ if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+ return -1;
+
+ caps = virJSONValueObjectGetObject(reply, "return");
+
+ if (!(caps = qemuMonitorJSONGetReply(cmd, reply, VIR_JSON_TYPE_ARRAY)))
+ return -1;
+
+ if ((malgolist = virJSONValueObjectGetArray(caps, "sections"))) {
+ n = virJSONValueArraySize(caps);
+
+ /* If the recieved array is empty, an error is returned. */
+ if (n == 0) {
+ *numalgo = n;
+ *malgo = NULL;
+
+ return -1;
+ }
+
+ list = g_new0(char *, n + 1);
+
+ for (i = 0; i < n; i++) {
+ virJSONValue *cap = virJSONValueArrayGet(malgolist, i);
+ const char *measurement_algo = NULL;
+
+ if (!cap || virJSONValueGetType(cap) != VIR_JSON_TYPE_OBJECT) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing entry in CCA capabilities list"));
+ return -1;
+ }
+
+ if (!(measurement_algo = virJSONValueObjectGetString(cap,
"measurement-algo"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-cca-capabilities reply was missing
'measurement-algo' field"));
+ return -1;
+ }
+
+ list[i] = g_strdup(measurement_algo);
+ }
+ }
+
+ *numalgo = n;
+ *malgo = g_steal_pointer(&list);
+ return 1;
+}
+
+
+/**
+ * qemuMonitorJSONGetCCACapabilities:
+ * @mon: qemu monitor object
+ * @capabilities: pointer to pointer to a CCA capability structure to be filled
+ *
+ * Returns -1 on error, 0 if CCA is not supported, and 1 if CCA is supported on
+ * the platform.
+ */
+int
+qemuMonitorJSONGetCCACapabilities(qemuMonitor *mon,
+ virCCACapability **capabilities)
+{
+ g_autoptr(virCCACapability) capability = NULL;
+ int ret = 0;
+
+ *capabilities = NULL;
+ capability = g_new0(virCCACapability, 1);
+
+ *capabilities = NULL;
+
+ ret = qemuMonitorJSONGetCCAMeasurementAlgo(mon,
+ &capability->nCcaMeasurementAlgo,
+ &capability->ccaMeasurementAlgo);
+
+ if (ret > 0)
+ *capabilities = g_steal_pointer(&capability);
+
+ return ret;
+}
+
+
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 10491b809b..46fb7bf108 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
+qemuMonitorJSONGetCCACapabilities(qemuMonitor *mon,
+ virCCACapability **capabilities);
+
int
qemuMonitorJSONMigrate(qemuMonitor *mon,
unsigned int flags,
diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c
index 5d9385afd6..c9c1de179c 100644
--- a/src/qemu/qemu_namespace.c
+++ b/src/qemu/qemu_namespace.c
@@ -660,6 +660,8 @@ qemuDomainSetupLaunchSecurity(virDomainObj *vm,
VIR_DEBUG("Set up launch security for SEV");
break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ break;
case VIR_DOMAIN_LAUNCH_SECURITY_PV:
break;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 0815bffe3c..695ee64373 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -6714,6 +6714,8 @@ qemuProcessPrepareDomain(virQEMUDriver *driver,
if (qemuProcessUpdateSEVInfo(vm) < 0)
return -1;
break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ break;
case VIR_DOMAIN_LAUNCH_SECURITY_PV:
break;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
@@ -6786,6 +6788,8 @@ qemuProcessPrepareLaunchSecurityGuestInput(virDomainObj *vm)
return qemuProcessPrepareSEVGuestInput(vm);
case VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP:
break;
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ return 0;
case VIR_DOMAIN_LAUNCH_SECURITY_PV:
return 0;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index fa23c5f973..c5e5de4d7e 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -1369,6 +1369,13 @@ qemuValidateDomainDef(const virDomainDef *def,
return -1;
}
break;
+
+ case VIR_DOMAIN_LAUNCH_SECURITY_CCA:
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCA_GUEST)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("CCA
launch security is not supported by this QEMU binary"));
+ }
+ break;
+
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
virReportEnumRangeError(virDomainLaunchSecurity, def->sec->sectype);
--
2.34.1