From nobody Mon Feb 2 07:32:14 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail header.i=@fujitsu.com; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=reject dis=none) header.from=aa.jp.fujitsu.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1769076339209481.89455699918244; Thu, 22 Jan 2026 02:05:39 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 052E641BA2; Thu, 22 Jan 2026 05:05:38 -0500 (EST) Received: from [172.19.199.3] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 4842343EFC; Thu, 22 Jan 2026 05:02:26 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 76F724199B; Thu, 22 Jan 2026 05:02:08 -0500 (EST) Received: from esa12.hc1455-7.c3s2.iphmx.com (esa12.hc1455-7.c3s2.iphmx.com [139.138.37.100]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 0BD5743DC2 for ; Thu, 22 Jan 2026 05:01:34 -0500 (EST) Received: from unknown (HELO az2nlsmgr1.o.css.fujitsu.com) ([51.138.80.169]) by esa12.hc1455-7.c3s2.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jan 2026 19:00:29 +0900 Received: from az2nlsmgm2.o.css.fujitsu.com (unknown [10.150.26.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by az2nlsmgr1.o.css.fujitsu.com (Postfix) with ESMTPS id ECD361C00182 for ; Thu, 22 Jan 2026 10:00:30 +0000 (UTC) Received: from az2uksmom4.o.css.fujitsu.com (az2uksmom4.o.css.fujitsu.com [10.151.22.204]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by az2nlsmgm2.o.css.fujitsu.com (Postfix) with ESMTPS id 8C6011C00977 for ; Thu, 22 Jan 2026 10:00:30 +0000 (UTC) Received: from sm-arm-grace07.ssoft.mng.com (sm-x86-stp01.soft.fujitsu.com [10.124.178.20]) by az2uksmom4.o.css.fujitsu.com (Postfix) with ESMTP id 14BAC406874; Thu, 22 Jan 2026 10:00:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 X-Greylist: delayed 62 seconds by postgrey-1.37 at lists.libvirt.org; Thu, 22 Jan 2026 05:01:35 EST DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=fujitsu.com; i=@fujitsu.com; q=dns/txt; s=fj2; t=1769076093; x=1800612093; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=T1kQc40/rBbingVzdALvWBKbIvl73jSxPPdDov8f/CY=; b=Anz3CtGltGso8dIE2Fa0FChcIJk2jn7tLDF4vghh3cLpNfh72e0dtZra 6XHDcxPI0edUAdn1Gc/5zKidZG4S0K2QtqUeNe6rHmTLv4XkiRso/WqXb gaGgfOw+6F7mEXVfkCHSAhR8A2WrO9e/EvEyYCMds/GZ1JZRQ3i8PQa0g iqfgKExZWwdXze1pp+KPfOwP6dt1GSSye9+r4kMFNc0MI84iiEuFJ0+FB L/8gV0bDGpXmZt7sCypaiWyHOImu69pvahFEslKZqPeCFwMu3xFbXjb9U 4YIMxDkcKXy5H/UTGILlAqm4QSmNm0cEg1s8YrTDzBhxwC8Nu+EmFHkAr A==; X-CSE-ConnectionGUID: c5NlnB3eTbOWzZQ1eUCO1A== X-CSE-MsgGUID: 3qw5szQhStqw6wQHk90sTA== X-IronPort-AV: E=McAfee;i="6800,10657,11678"; a="205679455" X-IronPort-AV: E=Sophos;i="6.21,246,1763391600"; d="scan'208";a="205679455" From: Kazuhiro Abe To: devel@lists.libvirt.org Subject: [RFC PATCH v5 2/5] src: Add ARM CCA support in domain capabilities command Date: Thu, 22 Jan 2026 18:58:35 +0900 Message-ID: <20260122095930.3544797-3-fj1078ii@aa.jp.fujitsu.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260122095930.3544797-1-fj1078ii@aa.jp.fujitsu.com> References: <20260122095930.3544797-1-fj1078ii@aa.jp.fujitsu.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-ID-Hash: CX3T2235GVNLMXSKS4OK6DNB3N3KNDRT X-Message-ID-Hash: CX3T2235GVNLMXSKS4OK6DNB3N3KNDRT X-MailFrom: fj1078ii@aa.jp.fujitsu.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: taketani.ryo@fujitsu.com X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1769076340229158500 Content-Type: text/plain; charset="utf-8" From: Akio Kakuno - Add ARM CCA support in domain capabilies XML schema. [Capability example] - Execution results of 'virsh domcapability" on qemu ... ... sha256 sha512 ... Signed-off-by: Kazuhiro Abe --- docs/formatdomaincaps.rst | 27 +++++++- src/conf/domain_capabilities.c | 48 ++++++++++++++ src/conf/domain_capabilities.h | 6 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 29 +++++++++ src/qemu/qemu_monitor.c | 10 +++ src/qemu/qemu_monitor.h | 3 + src/qemu/qemu_monitor_json.c | 111 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++ 9 files changed, 238 insertions(+), 1 deletion(-) diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index 8b4f0ecff3..6d4f3a0092 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -735,6 +735,12 @@ capabilities. All features occur as children of the ma= in ``features`` element.
+ + + sha256 + sha512 + + relaxed @@ -862,6 +868,24 @@ 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). =20 +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 de= veloper's +document store. In order to use CCA with libvirt have a look at `CCA in do= main +XML `__ + +``measurement-algo`` + Options for the ``measurement-algo`` used to describe blob hashes. + =20 Hyper-V Enlightenments ^^^^^^^^^^^^^^^^^^^^^^ @@ -882,4 +906,5 @@ The ``sectype`` enum corresponds to ``type`` attribute = of ```` element as documented in `Launch Security `__. :since:`(Since 10.5.0)` For addit= ional 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 capabili= ties`_ +for Arm CCA. diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index f843124695..9af3bf544c 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -118,6 +118,25 @@ virDomainCapsFeatureHypervCopy(virDomainCapsFeatureHyp= erv *cap) } =20 =20 +void +virCCACapabilitiesFree(virCCACapability *cap) +{ + size_t i; + + if (!cap) + return; + + if (cap->nCcaMeasurementAlgo) + for (i =3D 0; i < cap->nCcaMeasurementAlgo; i++) + g_free(cap->ccaMeasurementAlgo[i]); + + if (cap->ccaMeasurementAlgo) + g_free(cap->ccaMeasurementAlgo); + + g_free(cap); +} + + static void virDomainCapsDispose(void *obj) { @@ -131,6 +150,7 @@ virDomainCapsDispose(void *obj) virCPUDefFree(caps->cpu.hostModel); virSEVCapabilitiesFree(caps->sev); virSGXCapabilitiesFree(caps->sgx); + virCCACapabilitiesFree(caps->cca); virDomainCapsFeatureHypervFree(caps->hyperv); =20 values =3D &caps->os.loader.values; @@ -823,6 +843,33 @@ virDomainCapsFeatureSGXFormat(virBuffer *buf, virBufferAddLit(buf, "\n"); } =20 +static void +virDomainCapsFeatureCCAFormat(virBuffer *buf, + const virCCACapability *cca) +{ + size_t i; + + if (!cca) { + virBufferAddLit(buf, "\n"); + return; + } + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + for (i =3D 0; i < cca->nCcaMeasurementAlgo; i++) { + virBufferAsprintf(buf, "%s\n", + cca->ccaMeasurementAlgo[i]); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); +} + static void virDomainCapsFeatureHypervFormat(virBuffer *buf, const virDomainCapsFeatureHyperv *hyperv) @@ -900,6 +947,7 @@ virDomainCapsFormatFeatures(const virDomainCaps *caps, =20 virDomainCapsFeatureSEVFormat(&childBuf, caps->sev); virDomainCapsFeatureSGXFormat(&childBuf, caps->sgx); + virDomainCapsFeatureCCAFormat(&childBuf, caps->cca); virDomainCapsFeatureHypervFormat(&childBuf, caps->hyperv); virDomainCapsLaunchSecurityFormat(&childBuf, &caps->launchSecurity); =20 diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 0ce68b44ef..ed73164f82 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -329,6 +329,7 @@ struct _virDomainCaps { virDomainCapsFeatureGIC gic; virSEVCapability *sev; virSGXCapability *sgx; + virCCACapability *cca; virDomainCapsFeatureHyperv *hyperv; virDomainCapsLaunchSecurity launchSecurity; /* add new domain features here */ @@ -395,3 +396,8 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainCapsFeatureHyper= v, virDomainCapsFeatureHy =20 virDomainCapsFeatureHyperv * virDomainCapsFeatureHypervCopy(virDomainCapsFeatureHyperv *cap); + +void +virCCACapabilitiesFree(virCCACapability *capabilities); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCCACapability, virCCACapabilitiesFree); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4e57e4a8f6..e9250dfbbb 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -208,6 +208,7 @@ virDomainAuditVcpu; =20 =20 # conf/domain_capabilities.h +virCCACapabilitiesFree; virDomainCapsCPUModelsAdd; virDomainCapsCPUModelsCopy; virDomainCapsCPUModelsGet; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 9a2eadb673..e152523850 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -3765,6 +3765,32 @@ virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemu= Caps, } =20 =20 +static int +virQEMUCapsProbeQMPCCACapabilities(virQEMUCaps *qemuCaps, + qemuMonitor *mon) +{ + int rc =3D -1; + virCCACapability *caps =3D NULL; + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CCA_GUEST)) + return 0; + + if ((rc =3D qemuMonitorGetCCACapabilities(mon, &caps)) < 0) + return -1; + + /* CCA isn't actually supported */ + if (rc =3D=3D 0) { + virQEMUCapsClear(qemuCaps, QEMU_CAPS_CCA_GUEST); + return 0; + } + + virCCACapabilitiesFree(qemuCaps->ccaCapabilities); + qemuCaps->ccaCapabilities =3D 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 anythi= ng @@ -5964,6 +5990,9 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, return -1; if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeQMPCCACapabilities(qemuCaps, mon) < 0) + return -1; + virQEMUCapsProbeTDXCapabilities(qemuCaps); =20 virQEMUCapsInitProcessCaps(qemuCaps); diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 504500c864..2da0b38b17 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3571,6 +3571,16 @@ qemuMonitorGetSGXCapabilities(qemuMonitor *mon, } =20 =20 +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 d096f474c1..5fb25b776f 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -969,6 +969,9 @@ int qemuMonitorSetMigrationParams(qemuMonitor *mon, virJSONValue **params); =20 +int qemuMonitorGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities); + typedef enum { QEMU_MONITOR_MIGRATION_STATUS_INACTIVE, QEMU_MONITOR_MIGRATION_STATUS_SETUP, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index a602b1e65b..96fb83e738 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6541,6 +6541,117 @@ qemuMonitorJSONGetSGXCapabilities(qemuMonitor *mon, } =20 =20 +static int +qemuMonitorJSONGetCCAMeasurementAlgo(qemuMonitor *mon, + size_t *numalgo, + char ***malgo) +{ + g_autoptr(virJSONValue) cmd =3D NULL; + g_autoptr(virJSONValue) reply =3D NULL; + virJSONValue *caps; + virJSONValue *section =3D NULL; + virJSONValue *malgolist =3D NULL; + g_auto(GStrv) list =3D NULL; + size_t i; + size_t n =3D 0; + + if (!(cmd =3D qemuMonitorJSONMakeCommand("query-rme-guest-capabilities= ", + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return -1; + + /* If the 'query-rme-guest-capabilities' QMP command was not available + * we simply successfully return zero capabilities. + * This the case for QEMU < (CCA support version) and all non-ARM arch= itectures. + * TODO: Replace (CCA support version) with the actual CCA support ver= sion upon merge. */ + if (qemuMonitorJSONHasError(reply, "CommandNotFound")) + return 0; + + if (qemuMonitorJSONHasError(reply, "GenericError")) + return 0; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + return -1; + + if (!(caps =3D qemuMonitorJSONGetReply(cmd, reply, VIR_JSON_TYPE_OBJEC= T))) + return -1; + + if (!(section =3D virJSONValueObjectGetObject(caps, "section"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-rme-guest-capabilities reply was missing '= section' object")); + return -1; + } + + if (!(malgolist =3D virJSONValueObjectGetArray(section, "measurement-a= lgorithms"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-rme-guest-capabilities reply was missing '= measurement-algorithms' array")); + return -1; + } + + n =3D virJSONValueArraySize(malgolist); + + /* If the received 'measurement-algorithms' array is empty, an error i= s returned. */ + if (n =3D=3D 0) + return -1; + + list =3D g_new0(char *, n + 1); + + for (i =3D 0; i < n; i++) { + virJSONValue *algo =3D virJSONValueArrayGet(malgolist, i); + const char *measurement_algo =3D NULL; + + if (!algo || virJSONValueGetType(algo) !=3D VIR_JSON_TYPE_STRING) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("measurement-algorithms entry was not in expe= cted format")); + return -1; + } + + if (!(measurement_algo =3D virJSONValueGetString(algo))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to get measurement-algorithms string"= )); + return -1; + } + + list[i] =3D g_strdup(measurement_algo); + } + + *numalgo =3D n; + *malgo =3D g_steal_pointer(&list); + return 1; +} + + +/** + * qemuMonitorJSONGetCCACapabilities: + * @mon: qemu monitor object + * @capabilities: pointer to pointer to a CCA capability structure to be f= illed + * + * Returns -1 on error, 0 if CCA is not supported, and 1 if CCA is support= ed on + * the platform. + */ +int +qemuMonitorJSONGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities) +{ + g_autoptr(virCCACapability) capability =3D NULL; + int ret =3D 0; + + *capabilities =3D NULL; + capability =3D g_new0(virCCACapability, 1); + + ret =3D qemuMonitorJSONGetCCAMeasurementAlgo(mon, + &capability->nCcaMeasuremen= tAlgo, + &capability->ccaMeasurement= Algo); + + if (ret > 0) + *capabilities =3D 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 db9160eb68..6cf3778368 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -162,6 +162,10 @@ int qemuMonitorJSONGetSEVCapabilities(qemuMonitor *mon, virSEVCapability **capabilities); =20 +int +qemuMonitorJSONGetCCACapabilities(qemuMonitor *mon, + virCCACapability **capabilities); + int qemuMonitorJSONMigrate(qemuMonitor *mon, unsigned int flags, --=20 2.43.0