[PATCH 1/2] qemu: correctly detect working TDX support

Daniel P. Berrangé via Devel posted 2 patches 22 hours ago
[PATCH 1/2] qemu: correctly detect working TDX support
Posted by Daniel P. Berrangé via Devel 22 hours ago
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

Re: [PATCH 1/2] qemu: correctly detect working TDX support
Posted by Ján Tomko via Devel 20 hours ago
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
Re: [PATCH 1/2] qemu: correctly detect working TDX support
Posted by Daniel P. Berrangé via Devel 20 hours ago
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 :|

Re: [PATCH 1/2] qemu: correctly detect working TDX support
Posted by Peter Krempa via Devel 20 hours ago
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
> 
Re: [PATCH 1/2] qemu: correctly detect working TDX support
Posted by Daniel P. Berrangé via Devel 20 hours ago
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 :|

Re: [PATCH 1/2] qemu: correctly detect working TDX support
Posted by Peter Krempa via Devel 17 hours ago
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>