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