[PATCH 0/2] qemu: fix capabilities reporting for TDX
The capabilities reporting merged for TDX was flawed because it would always report TDX as supported simply if QEMU was new enough to have 'tdx-guest'. IOW, all x86 hosts currently report 'tdx' as fully supported which is a regression for AMD hosts, as we're now reporting incorrect data there which can confuse mgmt apps. Unfortunately the 'query-tdx-capabilities' QMP command that was in early postings: https://mail.gnu.org/archive/html/qemu-devel/2021-07/msg01689.html went missing and I'm not seeing an alternative way to query QEMU to see if TDX is actually launchable. So in these patches I open /dev/kvm and directly ask of the 'TDX' VM type is supported by KVM, which IIUC is equivalent to waht the original 'query-tdx-capabilities' patch was doing. Daniel P. Berrangé (2): qemu: correctly detect working TDX support qemu: always report TDX feature caps on x86 src/qemu/qemu_capabilities.c | 71 +++++++++++++++++-- src/qemu/qemu_capabilities.h | 3 + .../qemu_10.0.0-q35.x86_64+amdsev.xml | 1 + .../domaincapsdata/qemu_10.0.0-q35.x86_64.xml | 1 + .../qemu_10.0.0-tcg.x86_64+amdsev.xml | 1 + .../domaincapsdata/qemu_10.0.0-tcg.x86_64.xml | 1 + .../qemu_10.0.0.x86_64+amdsev.xml | 1 + tests/domaincapsdata/qemu_10.0.0.x86_64.xml | 1 + .../qemu_10.1.0-tcg.x86_64+inteltdx.xml | 1 + .../domaincapsdata/qemu_10.1.0-tcg.x86_64.xml | 1 + .../domaincapsdata/qemu_10.2.0-tcg.x86_64.xml | 1 + .../domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 1 + .../domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 1 + .../domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 1 + .../qemu_7.2.0-hvf.x86_64+hvf.xml | 1 + .../domaincapsdata/qemu_7.2.0-q35.x86_64.xml | 1 + .../qemu_7.2.0-tcg.x86_64+hvf.xml | 1 + .../domaincapsdata/qemu_7.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.2.0.x86_64.xml | 1 + .../domaincapsdata/qemu_8.0.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_8.0.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.0.0.x86_64.xml | 1 + .../domaincapsdata/qemu_8.1.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_8.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.1.0.x86_64.xml | 1 + .../domaincapsdata/qemu_8.2.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_8.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.2.0.x86_64.xml | 1 + .../domaincapsdata/qemu_9.0.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_9.0.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.0.0.x86_64.xml | 1 + .../domaincapsdata/qemu_9.1.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_9.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.1.0.x86_64.xml | 1 + .../qemu_9.2.0-q35.x86_64+amdsev.xml | 1 + .../domaincapsdata/qemu_9.2.0-q35.x86_64.xml | 1 + .../qemu_9.2.0-tcg.x86_64+amdsev.xml | 1 + .../domaincapsdata/qemu_9.2.0-tcg.x86_64.xml | 1 + .../qemu_9.2.0.x86_64+amdsev.xml | 1 + tests/domaincapsdata/qemu_9.2.0.x86_64.xml | 1 + tests/domaincapsmock.c | 6 ++ 47 files changed, 120 insertions(+), 4 deletions(-) -- 2.51.1
From: Daniel P. Berrangé <berrange@redhat.com> Querying existence of the 'tdx-guest' type merely tells us whether QEMU has been compiled with TDX support, not whether it is usable on the host. Thus QEMU was incorrectly reporting <tdx supported='yes'/> ... <launchSecurity supported='yes'> <enum name='sectype'> <value>tdx</value> </enum> </launchSecurity> on every platform with new enough QEMU. Unfortunately an earlier patch for a 'query-tdx-capabilities' QMP command in QEMU was dropped, so there is no way to ask QEMU whether it can launch a TDX guest. Libvirt must directly query the KVM device and ask for supported VM types. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 60 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 3 ++ tests/domaincapsmock.c | 6 ++++ 3 files changed, 69 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 205bf3d0b8..67fe5d7acf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -54,11 +54,16 @@ # include <sys/types.h> # include <sys/sysctl.h> #endif +#ifdef __linux__ +# include <linux/kvm.h> +#endif #define VIR_FROM_THIS VIR_FROM_QEMU VIR_LOG_INIT("qemu.qemu_capabilities"); +#define KVM_DEVICE "/dev/kvm" + /* While not public, these strings must not change. They * are used in domain status files which are read on * daemon restarts @@ -3655,6 +3660,59 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps, } +int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ +#if defined(KVM_CAP_VM_TYPES) && defined(KVM_X86_TDX_VM) + int kvmfd = -1; + int types; + + if (!virFileExists(KVM_DEVICE)) + return 0; + + if ((kvmfd = open(KVM_DEVICE, O_RDONLY)) < 0) { + VIR_DEBUG("Unable to open %s, cannot check TDX", KVM_DEVICE); + return 0; + } + + types = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_TYPES); + + VIR_FORCE_CLOSE(kvmfd); + VIR_DEBUG("KVM VM types: 0x%x", types); + + return !!(types & (1 << KVM_X86_TDX_VM)); +#else + VIR_DEBUG("KVM not compiled"); + return 0; +#endif +} + + +/* This ought to be virQEMUCapsProbeQMPTDXCapabilities, + * but there is no 'query-tdx-capabilities' command + * available in QEMU currently. If one arrives, rename + * this method & switch to using that on new enough QEMU + */ +static int +virQEMUCapsProbeTDXCapabilities(virQEMUCaps *qemuCaps) +{ + int rc; + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) + return 0; + + if ((rc = virQEMUCapsKVMSupportsVMTypeTDX()) < 0) + return -1; + + if (rc == 0) { + virQEMUCapsClear(qemuCaps, QEMU_CAPS_TDX_GUEST); + return 0; + } + + return 0; +} + + static int virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps, qemuMonitor *mon) @@ -5837,6 +5895,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, return -1; if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeTDXCapabilities(qemuCaps) < 0) + return -1; virQEMUCapsInitProcessCaps(qemuCaps); diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index efbef2acef..64e5c4ff55 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -979,3 +979,6 @@ int virQEMUCapsProbeQMPMachineTypes(virQEMUCaps *qemuCaps, virDomainVirtType virtType, qemuMonitor *mon); + +int +virQEMUCapsKVMSupportsVMTypeTDX(void) ATTRIBUTE_MOCKABLE; diff --git a/tests/domaincapsmock.c b/tests/domaincapsmock.c index cb6e98dbb8..e882c01260 100644 --- a/tests/domaincapsmock.c +++ b/tests/domaincapsmock.c @@ -48,6 +48,12 @@ virHostCPUGetPhysAddrSize(const virArch hostArch, } #if WITH_QEMU +int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ + return 1; +} + static bool (*real_virQEMUCapsGetKVMSupportsSecureGuest)(virQEMUCaps *qemuCaps); bool -- 2.51.1
On Thu, Nov 20, 2025 at 11:57:53 +0000, Daniel P. Berrangé via Devel wrote:
From: Daniel P. Berrangé <berrange@redhat.com>
Querying existence of the 'tdx-guest' type merely tells us whether QEMU has been compiled with TDX support, not whether it is usable on the host. Thus QEMU was incorrectly reporting
<tdx supported='yes'/> ... <launchSecurity supported='yes'> <enum name='sectype'> <value>tdx</value> </enum> </launchSecurity>
on every platform with new enough QEMU.
Unfortunately an earlier patch for a 'query-tdx-capabilities' QMP command in QEMU was dropped, so there is no way to ask QEMU whether it can launch a TDX guest. Libvirt must directly query the KVM device and ask for supported VM types.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 60 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 3 ++ tests/domaincapsmock.c | 6 ++++ 3 files changed, 69 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 205bf3d0b8..67fe5d7acf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -54,11 +54,16 @@ # include <sys/types.h> # include <sys/sysctl.h> #endif +#ifdef __linux__ +# include <linux/kvm.h> +#endif
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_capabilities");
+#define KVM_DEVICE "/dev/kvm" + /* While not public, these strings must not change. They * are used in domain status files which are read on * daemon restarts @@ -3655,6 +3660,59 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps, }
+int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ +#if defined(KVM_CAP_VM_TYPES) && defined(KVM_X86_TDX_VM) + int kvmfd = -1;
Preferrably use VIR_AUTOCLOSE here if anyone ever extends this function.
+ int types; + + if (!virFileExists(KVM_DEVICE)) + return 0; + + if ((kvmfd = open(KVM_DEVICE, O_RDONLY)) < 0) { + VIR_DEBUG("Unable to open %s, cannot check TDX", KVM_DEVICE); + return 0; + } + + types = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_TYPES); + + VIR_FORCE_CLOSE(kvmfd); + VIR_DEBUG("KVM VM types: 0x%x", types); + + return !!(types & (1 << KVM_X86_TDX_VM));
I didn't bother looking at what the IOCTL returns but I'd expect a < 0 check here as bit-checking a negative value could be 'fun'. So looking at all branches this only returns 0 or 1 ...
+#else + VIR_DEBUG("KVM not compiled"); + return 0; +#endif +} + + +/* This ought to be virQEMUCapsProbeQMPTDXCapabilities, + * but there is no 'query-tdx-capabilities' command + * available in QEMU currently. If one arrives, rename + * this method & switch to using that on new enough QEMU + */ +static int +virQEMUCapsProbeTDXCapabilities(virQEMUCaps *qemuCaps) +{ + int rc; + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) + return 0; + + if ((rc = virQEMUCapsKVMSupportsVMTypeTDX()) < 0) + return -1;
So this branch is dead code. All other branches return 0 so this function can be turned into a void function.
+ + if (rc == 0) { + virQEMUCapsClear(qemuCaps, QEMU_CAPS_TDX_GUEST); + return 0; + } + + return 0; +} + + static int virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps, qemuMonitor *mon) @@ -5837,6 +5895,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, return -1; if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeTDXCapabilities(qemuCaps) < 0) + return -1;
virQEMUCapsInitProcessCaps(qemuCaps);
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index efbef2acef..64e5c4ff55 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -979,3 +979,6 @@ int virQEMUCapsProbeQMPMachineTypes(virQEMUCaps *qemuCaps, virDomainVirtType virtType, qemuMonitor *mon); + +int +virQEMUCapsKVMSupportsVMTypeTDX(void) ATTRIBUTE_MOCKABLE; diff --git a/tests/domaincapsmock.c b/tests/domaincapsmock.c index cb6e98dbb8..e882c01260 100644 --- a/tests/domaincapsmock.c +++ b/tests/domaincapsmock.c @@ -48,6 +48,12 @@ virHostCPUGetPhysAddrSize(const virArch hostArch, }
#if WITH_QEMU +int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ + return 1; +} + static bool (*real_virQEMUCapsGetKVMSupportsSecureGuest)(virQEMUCaps *qemuCaps);
bool -- 2.51.1
On Thu, Nov 20, 2025 at 02:17:47PM +0100, Peter Krempa wrote:
On Thu, Nov 20, 2025 at 11:57:53 +0000, Daniel P. Berrangé via Devel wrote:
From: Daniel P. Berrangé <berrange@redhat.com>
Querying existence of the 'tdx-guest' type merely tells us whether QEMU has been compiled with TDX support, not whether it is usable on the host. Thus QEMU was incorrectly reporting
<tdx supported='yes'/> ... <launchSecurity supported='yes'> <enum name='sectype'> <value>tdx</value> </enum> </launchSecurity>
on every platform with new enough QEMU.
Unfortunately an earlier patch for a 'query-tdx-capabilities' QMP command in QEMU was dropped, so there is no way to ask QEMU whether it can launch a TDX guest. Libvirt must directly query the KVM device and ask for supported VM types.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 60 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 3 ++ tests/domaincapsmock.c | 6 ++++ 3 files changed, 69 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 205bf3d0b8..67fe5d7acf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -54,11 +54,16 @@ # include <sys/types.h> # include <sys/sysctl.h> #endif +#ifdef __linux__ +# include <linux/kvm.h> +#endif
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_capabilities");
+#define KVM_DEVICE "/dev/kvm" + /* While not public, these strings must not change. They * are used in domain status files which are read on * daemon restarts @@ -3655,6 +3660,59 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps, }
+int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ +#if defined(KVM_CAP_VM_TYPES) && defined(KVM_X86_TDX_VM) + int kvmfd = -1;
Preferrably use VIR_AUTOCLOSE here if anyone ever extends this function.
ok
+ int types; + + if (!virFileExists(KVM_DEVICE)) + return 0; + + if ((kvmfd = open(KVM_DEVICE, O_RDONLY)) < 0) { + VIR_DEBUG("Unable to open %s, cannot check TDX", KVM_DEVICE); + return 0; + } + + types = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_TYPES); + + VIR_FORCE_CLOSE(kvmfd); + VIR_DEBUG("KVM VM types: 0x%x", types); + + return !!(types & (1 << KVM_X86_TDX_VM));
I didn't bother looking at what the IOCTL returns but I'd expect a < 0 check here as bit-checking a negative value could be 'fun'.
KVM_CHECK_EXTENSION will return 0 if any capability does not exist, so this should be safe in old KVM, but for safety, lets squash -1 to be 0 explicitly.
So looking at all branches this only returns 0 or 1 ...
Oh yes, I removed the -1 branch from failure to open /dev/kvm as I decided that shouldn't be allowed to break caps probing.
+#else + VIR_DEBUG("KVM not compiled"); + return 0; +#endif +} + + +/* This ought to be virQEMUCapsProbeQMPTDXCapabilities, + * but there is no 'query-tdx-capabilities' command + * available in QEMU currently. If one arrives, rename + * this method & switch to using that on new enough QEMU + */ +static int +virQEMUCapsProbeTDXCapabilities(virQEMUCaps *qemuCaps) +{ + int rc; + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST)) + return 0; + + if ((rc = virQEMUCapsKVMSupportsVMTypeTDX()) < 0) + return -1;
So this branch is dead code. All other branches return 0 so this function can be turned into a void function.
Yep.
+ + if (rc == 0) { + virQEMUCapsClear(qemuCaps, QEMU_CAPS_TDX_GUEST); + return 0; + } + + return 0; +} + + static int virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps, qemuMonitor *mon) @@ -5837,6 +5895,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, return -1; if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeTDXCapabilities(qemuCaps) < 0) + return -1;
virQEMUCapsInitProcessCaps(qemuCaps);
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index efbef2acef..64e5c4ff55 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -979,3 +979,6 @@ int virQEMUCapsProbeQMPMachineTypes(virQEMUCaps *qemuCaps, virDomainVirtType virtType, qemuMonitor *mon); + +int +virQEMUCapsKVMSupportsVMTypeTDX(void) ATTRIBUTE_MOCKABLE; diff --git a/tests/domaincapsmock.c b/tests/domaincapsmock.c index cb6e98dbb8..e882c01260 100644 --- a/tests/domaincapsmock.c +++ b/tests/domaincapsmock.c @@ -48,6 +48,12 @@ virHostCPUGetPhysAddrSize(const virArch hostArch, }
#if WITH_QEMU +int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ + return 1; +} + static bool (*real_virQEMUCapsGetKVMSupportsSecureGuest)(virQEMUCaps *qemuCaps);
bool -- 2.51.1
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
On Thu, Nov 20, 2025 at 13:37:34 +0000, Daniel P. Berrangé wrote:
On Thu, Nov 20, 2025 at 02:17:47PM +0100, Peter Krempa wrote:
On Thu, Nov 20, 2025 at 11:57:53 +0000, Daniel P. Berrangé via Devel wrote:
From: Daniel P. Berrangé <berrange@redhat.com>
Querying existence of the 'tdx-guest' type merely tells us whether QEMU has been compiled with TDX support, not whether it is usable on the host. Thus QEMU was incorrectly reporting
<tdx supported='yes'/> ... <launchSecurity supported='yes'> <enum name='sectype'> <value>tdx</value> </enum> </launchSecurity>
on every platform with new enough QEMU.
Unfortunately an earlier patch for a 'query-tdx-capabilities' QMP command in QEMU was dropped, so there is no way to ask QEMU whether it can launch a TDX guest. Libvirt must directly query the KVM device and ask for supported VM types.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 60 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 3 ++ tests/domaincapsmock.c | 6 ++++ 3 files changed, 69 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 205bf3d0b8..67fe5d7acf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -54,11 +54,16 @@ # include <sys/types.h> # include <sys/sysctl.h> #endif +#ifdef __linux__ +# include <linux/kvm.h> +#endif
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_capabilities");
+#define KVM_DEVICE "/dev/kvm" + /* While not public, these strings must not change. They * are used in domain status files which are read on * daemon restarts @@ -3655,6 +3660,59 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps, }
+int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ +#if defined(KVM_CAP_VM_TYPES) && defined(KVM_X86_TDX_VM) + int kvmfd = -1;
Preferrably use VIR_AUTOCLOSE here if anyone ever extends this function.
ok
+ int types; + + if (!virFileExists(KVM_DEVICE)) + return 0; + + if ((kvmfd = open(KVM_DEVICE, O_RDONLY)) < 0) { + VIR_DEBUG("Unable to open %s, cannot check TDX", KVM_DEVICE); + return 0; + } + + types = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_TYPES); + + VIR_FORCE_CLOSE(kvmfd); + VIR_DEBUG("KVM VM types: 0x%x", types); + + return !!(types & (1 << KVM_X86_TDX_VM));
I didn't bother looking at what the IOCTL returns but I'd expect a < 0 check here as bit-checking a negative value could be 'fun'.
KVM_CHECK_EXTENSION will return 0 if any capability does not exist, so this should be safe in old KVM, but for safety, lets squash -1 to be 0 explicitly.
So looking at all branches this only returns 0 or 1 ...
Oh yes, I removed the -1 branch from failure to open /dev/kvm as I decided that shouldn't be allowed to break caps probing.
With the suggested changes (especially for the -1) case: Reviewed-by: Peter Krempa <pkrempa@redhat.com>
On a Thursday in 2025, Daniel P. Berrangé via Devel wrote:
From: Daniel P. Berrangé <berrange@redhat.com>
Querying existence of the 'tdx-guest' type merely tells us whether QEMU has been compiled with TDX support, not whether it is usable on the host. Thus QEMU was incorrectly reporting
s/QEMU/libvirt/ in the one case above
<tdx supported='yes'/> ... <launchSecurity supported='yes'> <enum name='sectype'> <value>tdx</value> </enum> </launchSecurity>
on every platform with new enough QEMU.
Unfortunately an earlier patch for a 'query-tdx-capabilities' QMP command in QEMU was dropped, so there is no way to ask QEMU whether it can launch a TDX guest. Libvirt must directly query the KVM device and ask for supported VM types.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 60 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 3 ++ tests/domaincapsmock.c | 6 ++++ 3 files changed, 69 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 205bf3d0b8..67fe5d7acf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -54,11 +54,16 @@ # include <sys/types.h> # include <sys/sysctl.h> #endif +#ifdef __linux__ +# include <linux/kvm.h> +#endif
I think the part touching /dev/kvm should live somewhere in src/util
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_capabilities");
+#define KVM_DEVICE "/dev/kvm" + /* While not public, these strings must not change. They * are used in domain status files which are read on * daemon restarts @@ -3655,6 +3660,59 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps, }
+int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ +#if defined(KVM_CAP_VM_TYPES) && defined(KVM_X86_TDX_VM) + int kvmfd = -1; + int types; + + if (!virFileExists(KVM_DEVICE)) + return 0; + + if ((kvmfd = open(KVM_DEVICE, O_RDONLY)) < 0) { + VIR_DEBUG("Unable to open %s, cannot check TDX", KVM_DEVICE); + return 0; + } + + types = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_TYPES);
Interesting that you did not have to include sys/ioctl.h It seems it gets included via virsocket.h
+ + VIR_FORCE_CLOSE(kvmfd); + VIR_DEBUG("KVM VM types: 0x%x", types); + + return !!(types & (1 << KVM_X86_TDX_VM));
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
On Thu, Nov 20, 2025 at 02:30:18PM +0100, Ján Tomko wrote:
On a Thursday in 2025, Daniel P. Berrangé via Devel wrote:
From: Daniel P. Berrangé <berrange@redhat.com>
Querying existence of the 'tdx-guest' type merely tells us whether QEMU has been compiled with TDX support, not whether it is usable on the host. Thus QEMU was incorrectly reporting
s/QEMU/libvirt/ in the one case above
<tdx supported='yes'/> ... <launchSecurity supported='yes'> <enum name='sectype'> <value>tdx</value> </enum> </launchSecurity>
on every platform with new enough QEMU.
Unfortunately an earlier patch for a 'query-tdx-capabilities' QMP command in QEMU was dropped, so there is no way to ask QEMU whether it can launch a TDX guest. Libvirt must directly query the KVM device and ask for supported VM types.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 60 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 3 ++ tests/domaincapsmock.c | 6 ++++ 3 files changed, 69 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 205bf3d0b8..67fe5d7acf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -54,11 +54,16 @@ # include <sys/types.h> # include <sys/sysctl.h> #endif +#ifdef __linux__ +# include <linux/kvm.h> +#endif
I think the part touching /dev/kvm should live somewhere in src/util
We've got bits touching /dev/kvm in many other source files too. Feels like we should introduce a virkvm.{ch} module in util and merge everything. I'll do that as a followup though, since this commit wants to be easy to backport to previous releases.
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_capabilities");
+#define KVM_DEVICE "/dev/kvm" + /* While not public, these strings must not change. They * are used in domain status files which are read on * daemon restarts @@ -3655,6 +3660,59 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps, }
+int +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ +#if defined(KVM_CAP_VM_TYPES) && defined(KVM_X86_TDX_VM) + int kvmfd = -1; + int types; + + if (!virFileExists(KVM_DEVICE)) + return 0; + + if ((kvmfd = open(KVM_DEVICE, O_RDONLY)) < 0) { + VIR_DEBUG("Unable to open %s, cannot check TDX", KVM_DEVICE); + return 0; + } + + types = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_TYPES);
Interesting that you did not have to include sys/ioctl.h It seems it gets included via virsocket.h
I'll make that an explicit include to be sure.
+ + VIR_FORCE_CLOSE(kvmfd); + VIR_DEBUG("KVM VM types: 0x%x", types); + + return !!(types & (1 << KVM_X86_TDX_VM));
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Jano
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
From: Daniel P. Berrangé <berrange@redhat.com> Currently domain capabilities will only ever report <tdx supported='yes'/> so it is not possible to determine whether libvirt itself is new enough to have TDX support or not, vs the host OS lacking it. For SEV and s390 prot-virt, the capability is always reported whether supported or not, so do likewise for TDX, so other x86 hosts get: <tdx supported='no'/> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 11 +++++++---- .../domaincapsdata/qemu_10.0.0-q35.x86_64+amdsev.xml | 1 + tests/domaincapsdata/qemu_10.0.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_10.0.0-tcg.x86_64+amdsev.xml | 1 + tests/domaincapsdata/qemu_10.0.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_10.0.0.x86_64+amdsev.xml | 1 + tests/domaincapsdata/qemu_10.0.0.x86_64.xml | 1 + .../qemu_10.1.0-tcg.x86_64+inteltdx.xml | 1 + tests/domaincapsdata/qemu_10.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_10.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.2.0-hvf.x86_64+hvf.xml | 1 + tests/domaincapsdata/qemu_7.2.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.2.0-tcg.x86_64+hvf.xml | 1 + tests/domaincapsdata/qemu_7.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.2.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.0.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.0.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.0.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.1.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.1.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.2.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_8.2.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.0.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.0.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.0.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.1.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.1.0.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.2.0-q35.x86_64+amdsev.xml | 1 + tests/domaincapsdata/qemu_9.2.0-q35.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.2.0-tcg.x86_64+amdsev.xml | 1 + tests/domaincapsdata/qemu_9.2.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_9.2.0.x86_64+amdsev.xml | 1 + tests/domaincapsdata/qemu_9.2.0.x86_64.xml | 1 + 45 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 67fe5d7acf..2eae52f8c4 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -7120,11 +7120,14 @@ static void virQEMUCapsFillDomainFeatureTDXCaps(virQEMUCaps *qemuCaps, virDomainCaps *domCaps) { - if (domCaps->arch == VIR_ARCH_X86_64 && - domCaps->virttype == VIR_DOMAIN_VIRT_KVM && - virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && - virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) + if (domCaps->arch == VIR_ARCH_X86_64) { + if (domCaps->virttype == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && + virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_YES; + else + domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_NO; + } } diff --git a/tests/domaincapsdata/qemu_10.0.0-q35.x86_64+amdsev.xml b/tests/domaincapsdata/qemu_10.0.0-q35.x86_64+amdsev.xml index b7debc22a5..c6ccb1cf9d 100644 --- a/tests/domaincapsdata/qemu_10.0.0-q35.x86_64+amdsev.xml +++ b/tests/domaincapsdata/qemu_10.0.0-q35.x86_64+amdsev.xml @@ -954,6 +954,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='yes'> <cbitpos>51</cbitpos> <reducedPhysBits>1</reducedPhysBits> diff --git a/tests/domaincapsdata/qemu_10.0.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_10.0.0-q35.x86_64.xml index e543997db2..97f57d9517 100644 --- a/tests/domaincapsdata/qemu_10.0.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_10.0.0-q35.x86_64.xml @@ -1853,6 +1853,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_10.0.0-tcg.x86_64+amdsev.xml b/tests/domaincapsdata/qemu_10.0.0-tcg.x86_64+amdsev.xml index 134f2c5847..063dfff42e 100644 --- a/tests/domaincapsdata/qemu_10.0.0-tcg.x86_64+amdsev.xml +++ b/tests/domaincapsdata/qemu_10.0.0-tcg.x86_64+amdsev.xml @@ -1938,6 +1938,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='yes'> <cbitpos>51</cbitpos> <reducedPhysBits>1</reducedPhysBits> diff --git a/tests/domaincapsdata/qemu_10.0.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_10.0.0-tcg.x86_64.xml index 494152ea41..847869fd76 100644 --- a/tests/domaincapsdata/qemu_10.0.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_10.0.0-tcg.x86_64.xml @@ -1938,6 +1938,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_10.0.0.x86_64+amdsev.xml b/tests/domaincapsdata/qemu_10.0.0.x86_64+amdsev.xml index 093ce552e8..e078b61b16 100644 --- a/tests/domaincapsdata/qemu_10.0.0.x86_64+amdsev.xml +++ b/tests/domaincapsdata/qemu_10.0.0.x86_64+amdsev.xml @@ -954,6 +954,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='yes'> <cbitpos>51</cbitpos> <reducedPhysBits>1</reducedPhysBits> diff --git a/tests/domaincapsdata/qemu_10.0.0.x86_64.xml b/tests/domaincapsdata/qemu_10.0.0.x86_64.xml index bcb0bc56e0..c979f72c7f 100644 --- a/tests/domaincapsdata/qemu_10.0.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_10.0.0.x86_64.xml @@ -1853,6 +1853,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_10.1.0-tcg.x86_64+inteltdx.xml b/tests/domaincapsdata/qemu_10.1.0-tcg.x86_64+inteltdx.xml index c5a4542f98..7b0fb06a06 100644 --- a/tests/domaincapsdata/qemu_10.1.0-tcg.x86_64+inteltdx.xml +++ b/tests/domaincapsdata/qemu_10.1.0-tcg.x86_64+inteltdx.xml @@ -2177,6 +2177,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='yes'> <flc>yes</flc> diff --git a/tests/domaincapsdata/qemu_10.1.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_10.1.0-tcg.x86_64.xml index cbbe141e3d..0709035d73 100644 --- a/tests/domaincapsdata/qemu_10.1.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_10.1.0-tcg.x86_64.xml @@ -2324,6 +2324,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_10.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_10.2.0-tcg.x86_64.xml index 2f2835e080..adc3171a88 100644 --- a/tests/domaincapsdata/qemu_10.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_10.2.0-tcg.x86_64.xml @@ -2324,6 +2324,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml index 3637f37a0f..e012c147b1 100644 --- a/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml @@ -1157,6 +1157,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='no'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml index f575585760..d8efb8a905 100644 --- a/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml @@ -1959,6 +1959,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='no'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_6.2.0.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0.x86_64.xml index fc849d0d30..f138cc9a01 100644 --- a/tests/domaincapsdata/qemu_6.2.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0.x86_64.xml @@ -1157,6 +1157,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='no'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml index 7a524ee5f8..9c4736071d 100644 --- a/tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml @@ -1185,6 +1185,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='yes'> <flc>no</flc> diff --git a/tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml index ce77e930c0..4a5179551e 100644 --- a/tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml @@ -1984,6 +1984,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='yes'> <flc>no</flc> diff --git a/tests/domaincapsdata/qemu_7.0.0.x86_64.xml b/tests/domaincapsdata/qemu_7.0.0.x86_64.xml index 9621a12a3a..269a3ad6c2 100644 --- a/tests/domaincapsdata/qemu_7.0.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.0.0.x86_64.xml @@ -1185,6 +1185,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='yes'> <flc>no</flc> diff --git a/tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml index d7c39ea11e..4620b8146b 100644 --- a/tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml @@ -1152,6 +1152,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml index e255480051..5fd8dbe775 100644 --- a/tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml @@ -1932,6 +1932,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_7.1.0.x86_64.xml b/tests/domaincapsdata/qemu_7.1.0.x86_64.xml index 098c0f42c1..884f403622 100644 --- a/tests/domaincapsdata/qemu_7.1.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.1.0.x86_64.xml @@ -1152,6 +1152,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_7.2.0-hvf.x86_64+hvf.xml b/tests/domaincapsdata/qemu_7.2.0-hvf.x86_64+hvf.xml index ba8ecd6a95..a162c239d2 100644 --- a/tests/domaincapsdata/qemu_7.2.0-hvf.x86_64+hvf.xml +++ b/tests/domaincapsdata/qemu_7.2.0-hvf.x86_64+hvf.xml @@ -1159,6 +1159,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_7.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_7.2.0-q35.x86_64.xml index 4b8849cd99..961ff998ff 100644 --- a/tests/domaincapsdata/qemu_7.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.2.0-q35.x86_64.xml @@ -1159,6 +1159,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_7.2.0-tcg.x86_64+hvf.xml b/tests/domaincapsdata/qemu_7.2.0-tcg.x86_64+hvf.xml index 2aa72f1b10..1ba28743a5 100644 --- a/tests/domaincapsdata/qemu_7.2.0-tcg.x86_64+hvf.xml +++ b/tests/domaincapsdata/qemu_7.2.0-tcg.x86_64+hvf.xml @@ -1639,6 +1639,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_7.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_7.2.0-tcg.x86_64.xml index 2aa72f1b10..1ba28743a5 100644 --- a/tests/domaincapsdata/qemu_7.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.2.0-tcg.x86_64.xml @@ -1639,6 +1639,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_7.2.0.x86_64.xml b/tests/domaincapsdata/qemu_7.2.0.x86_64.xml index c02c5e6555..95ab14e86d 100644 --- a/tests/domaincapsdata/qemu_7.2.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.2.0.x86_64.xml @@ -1159,6 +1159,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <launchSecurity supported='no'/> diff --git a/tests/domaincapsdata/qemu_8.0.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_8.0.0-q35.x86_64.xml index 8a5277934d..978181a189 100644 --- a/tests/domaincapsdata/qemu_8.0.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.0.0-q35.x86_64.xml @@ -1241,6 +1241,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_8.0.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_8.0.0-tcg.x86_64.xml index 9348304998..9dbcf2d903 100644 --- a/tests/domaincapsdata/qemu_8.0.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.0.0-tcg.x86_64.xml @@ -1734,6 +1734,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_8.0.0.x86_64.xml b/tests/domaincapsdata/qemu_8.0.0.x86_64.xml index f68a87f2e0..72ec08a143 100644 --- a/tests/domaincapsdata/qemu_8.0.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.0.0.x86_64.xml @@ -1241,6 +1241,7 @@ <backup supported='yes'/> <async-teardown supported='no'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_8.1.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_8.1.0-q35.x86_64.xml index a9a113326a..deb305fddc 100644 --- a/tests/domaincapsdata/qemu_8.1.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.1.0-q35.x86_64.xml @@ -1499,6 +1499,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_8.1.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_8.1.0-tcg.x86_64.xml index f1f41fbe96..9fb3da8876 100644 --- a/tests/domaincapsdata/qemu_8.1.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.1.0-tcg.x86_64.xml @@ -1755,6 +1755,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_8.1.0.x86_64.xml b/tests/domaincapsdata/qemu_8.1.0.x86_64.xml index 13541e8421..d7a78be468 100644 --- a/tests/domaincapsdata/qemu_8.1.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.1.0.x86_64.xml @@ -1499,6 +1499,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_8.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_8.2.0-q35.x86_64.xml index dabdf47c6b..55a064b979 100644 --- a/tests/domaincapsdata/qemu_8.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.2.0-q35.x86_64.xml @@ -1501,6 +1501,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_8.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_8.2.0-tcg.x86_64.xml index 7538570678..c7b3b5e594 100644 --- a/tests/domaincapsdata/qemu_8.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.2.0-tcg.x86_64.xml @@ -1722,6 +1722,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_8.2.0.x86_64.xml b/tests/domaincapsdata/qemu_8.2.0.x86_64.xml index ffcfc42b08..98c6be67ba 100644 --- a/tests/domaincapsdata/qemu_8.2.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_8.2.0.x86_64.xml @@ -1501,6 +1501,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.0.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_9.0.0-q35.x86_64.xml index 7289d5fbdc..862b647f5a 100644 --- a/tests/domaincapsdata/qemu_9.0.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.0.0-q35.x86_64.xml @@ -1501,6 +1501,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.0.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_9.0.0-tcg.x86_64.xml index 141edc67f3..f29be31e20 100644 --- a/tests/domaincapsdata/qemu_9.0.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.0.0-tcg.x86_64.xml @@ -1651,6 +1651,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.0.0.x86_64.xml b/tests/domaincapsdata/qemu_9.0.0.x86_64.xml index 5a636f06a8..962ed89b0a 100644 --- a/tests/domaincapsdata/qemu_9.0.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.0.0.x86_64.xml @@ -1501,6 +1501,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.1.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_9.1.0-q35.x86_64.xml index 4003af73de..896643346b 100644 --- a/tests/domaincapsdata/qemu_9.1.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.1.0-q35.x86_64.xml @@ -1637,6 +1637,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.1.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_9.1.0-tcg.x86_64.xml index 2fdeeb143a..a19cc09abc 100644 --- a/tests/domaincapsdata/qemu_9.1.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.1.0-tcg.x86_64.xml @@ -1756,6 +1756,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.1.0.x86_64.xml b/tests/domaincapsdata/qemu_9.1.0.x86_64.xml index ba78d5d24d..408006f2ad 100644 --- a/tests/domaincapsdata/qemu_9.1.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.1.0.x86_64.xml @@ -1637,6 +1637,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.2.0-q35.x86_64+amdsev.xml b/tests/domaincapsdata/qemu_9.2.0-q35.x86_64+amdsev.xml index 099c503551..09b753dcd1 100644 --- a/tests/domaincapsdata/qemu_9.2.0-q35.x86_64+amdsev.xml +++ b/tests/domaincapsdata/qemu_9.2.0-q35.x86_64+amdsev.xml @@ -834,6 +834,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='yes'> <cbitpos>51</cbitpos> <reducedPhysBits>1</reducedPhysBits> diff --git a/tests/domaincapsdata/qemu_9.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_9.2.0-q35.x86_64.xml index f83af00819..848918ee63 100644 --- a/tests/domaincapsdata/qemu_9.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.2.0-q35.x86_64.xml @@ -1695,6 +1695,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.2.0-tcg.x86_64+amdsev.xml b/tests/domaincapsdata/qemu_9.2.0-tcg.x86_64+amdsev.xml index 28b9647f14..677c677e98 100644 --- a/tests/domaincapsdata/qemu_9.2.0-tcg.x86_64+amdsev.xml +++ b/tests/domaincapsdata/qemu_9.2.0-tcg.x86_64+amdsev.xml @@ -1803,6 +1803,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='yes'> <cbitpos>51</cbitpos> <reducedPhysBits>1</reducedPhysBits> diff --git a/tests/domaincapsdata/qemu_9.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_9.2.0-tcg.x86_64.xml index f3469cdade..2590f41d4f 100644 --- a/tests/domaincapsdata/qemu_9.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.2.0-tcg.x86_64.xml @@ -1803,6 +1803,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> diff --git a/tests/domaincapsdata/qemu_9.2.0.x86_64+amdsev.xml b/tests/domaincapsdata/qemu_9.2.0.x86_64+amdsev.xml index 462365ee12..a65c587e5d 100644 --- a/tests/domaincapsdata/qemu_9.2.0.x86_64+amdsev.xml +++ b/tests/domaincapsdata/qemu_9.2.0.x86_64+amdsev.xml @@ -834,6 +834,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='yes'> <cbitpos>51</cbitpos> <reducedPhysBits>1</reducedPhysBits> diff --git a/tests/domaincapsdata/qemu_9.2.0.x86_64.xml b/tests/domaincapsdata/qemu_9.2.0.x86_64.xml index 756e2cf90a..f183fe119f 100644 --- a/tests/domaincapsdata/qemu_9.2.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_9.2.0.x86_64.xml @@ -1695,6 +1695,7 @@ <backup supported='yes'/> <async-teardown supported='yes'/> <ps2 supported='yes'/> + <tdx supported='no'/> <sev supported='no'/> <sgx supported='no'/> <hyperv supported='yes'> -- 2.51.1
On Thu, Nov 20, 2025 at 11:57:54 +0000, Daniel P. Berrangé via Devel wrote:
From: Daniel P. Berrangé <berrange@redhat.com>
Currently domain capabilities will only ever report
<tdx supported='yes'/>
so it is not possible to determine whether libvirt itself is new enough to have TDX support or not, vs the host OS lacking it.
For SEV and s390 prot-virt, the capability is always reported whether supported or not, so do likewise for TDX, so other x86 hosts get:
<tdx supported='no'/>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
[...]
--- diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 67fe5d7acf..2eae52f8c4 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -7120,11 +7120,14 @@ static void virQEMUCapsFillDomainFeatureTDXCaps(virQEMUCaps *qemuCaps, virDomainCaps *domCaps) { - if (domCaps->arch == VIR_ARCH_X86_64 && - domCaps->virttype == VIR_DOMAIN_VIRT_KVM && - virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && - virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) + if (domCaps->arch == VIR_ARCH_X86_64) { + if (domCaps->virttype == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && + virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_YES; + else + domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_NO;
IMO we should say that it's not supported even on non-x86 arches rather than make it seem like the feature doesn't exist.
+ }
On Thu, Nov 20, 2025 at 02:25:05PM +0100, Peter Krempa wrote:
On Thu, Nov 20, 2025 at 11:57:54 +0000, Daniel P. Berrangé via Devel wrote:
From: Daniel P. Berrangé <berrange@redhat.com>
Currently domain capabilities will only ever report
<tdx supported='yes'/>
so it is not possible to determine whether libvirt itself is new enough to have TDX support or not, vs the host OS lacking it.
For SEV and s390 prot-virt, the capability is always reported whether supported or not, so do likewise for TDX, so other x86 hosts get:
<tdx supported='no'/>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
[...]
--- diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 67fe5d7acf..2eae52f8c4 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -7120,11 +7120,14 @@ static void virQEMUCapsFillDomainFeatureTDXCaps(virQEMUCaps *qemuCaps, virDomainCaps *domCaps) { - if (domCaps->arch == VIR_ARCH_X86_64 && - domCaps->virttype == VIR_DOMAIN_VIRT_KVM && - virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && - virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) + if (domCaps->arch == VIR_ARCH_X86_64) { + if (domCaps->virttype == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && + virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_YES; + else + domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_NO;
IMO we should say that it's not supported even on non-x86 arches rather than make it seem like the feature doesn't exist.
I did that to be consistent with virQEMUCapsFillDomainFeatureS390PVCaps. Do you think we should report s390 prot-virt as not-avail on x86 too ? With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
On Thu, Nov 20, 2025 at 13:34:13 +0000, Daniel P. Berrangé wrote:
On Thu, Nov 20, 2025 at 02:25:05PM +0100, Peter Krempa wrote:
On Thu, Nov 20, 2025 at 11:57:54 +0000, Daniel P. Berrangé via Devel wrote:
From: Daniel P. Berrangé <berrange@redhat.com>
Currently domain capabilities will only ever report
<tdx supported='yes'/>
so it is not possible to determine whether libvirt itself is new enough to have TDX support or not, vs the host OS lacking it.
For SEV and s390 prot-virt, the capability is always reported whether supported or not, so do likewise for TDX, so other x86 hosts get:
<tdx supported='no'/>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
[...]
--- diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 67fe5d7acf..2eae52f8c4 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -7120,11 +7120,14 @@ static void virQEMUCapsFillDomainFeatureTDXCaps(virQEMUCaps *qemuCaps, virDomainCaps *domCaps) { - if (domCaps->arch == VIR_ARCH_X86_64 && - domCaps->virttype == VIR_DOMAIN_VIRT_KVM && - virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && - virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) + if (domCaps->arch == VIR_ARCH_X86_64) { + if (domCaps->virttype == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST) && + virQEMUCapsGetKVMSupportsSecureGuest(qemuCaps)) domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_YES; + else + domCaps->features[VIR_DOMAIN_CAPS_FEATURE_TDX] = VIR_TRISTATE_BOOL_NO;
IMO we should say that it's not supported even on non-x86 arches rather than make it seem like the feature doesn't exist.
I did that to be consistent with virQEMUCapsFillDomainFeatureS390PVCaps.
Do you think we should report s390 prot-virt as not-avail on x86 too
Well yes. Libvirt does already have that feature and that feature doesn't work on that host. IMO there's no difference if you have a box where the feature doesn't work or have a kernel that doesn't support it. If, as you mentioned in 1/2, you want to keep this patch minimal for backports, I'm okay to do it in a follow-up. Reviewed-by: Peter Krempa <pkrempa@redhat.com>
participants (3)
-
Daniel P. Berrangé -
Ján Tomko -
Peter Krempa