On Thu, Nov 20, 2025 at 11:57:53 +0000, Daniel P. Berrangé via Devel wrote:
> From: Daniel P. Berrangé <[email protected]>
>
> 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é <[email protected]>
> ---
> 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
>