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 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 :|
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>
© 2016 - 2025 Red Hat, Inc.