]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: correctly detect working TDX support
authorDaniel P. Berrangé <berrange@redhat.com>
Thu, 20 Nov 2025 11:24:31 +0000 (06:24 -0500)
committerDaniel P. Berrangé <berrange@redhat.com>
Mon, 24 Nov 2025 15:05:09 +0000 (15:05 +0000)
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.

Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
src/qemu/qemu_capabilities.c
src/qemu/qemu_capabilities.h
tests/domaincapsmock.c

index 4050d5ccc692b204e6ff716e6b544a3149bc244c..02ab663f3b8de6748ff58db7aa95963b401ff9b0 100644 (file)
 # include <sys/types.h>
 # include <sys/sysctl.h>
 #endif
+#ifdef WITH_LINUX_KVM_H
+# include <linux/kvm.h>
+# include <sys/ioctl.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
@@ -3686,6 +3692,50 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps,
 }
 
 
+bool
+virQEMUCapsKVMSupportsVMTypeTDX(void)
+{
+#if defined(KVM_CAP_VM_TYPES) && defined(KVM_X86_TDX_VM)
+    VIR_AUTOCLOSE kvmfd = -1;
+    int types;
+
+    if (!virFileExists(KVM_DEVICE))
+        return false;
+
+    if ((kvmfd = open(KVM_DEVICE, O_RDONLY)) < 0) {
+        VIR_DEBUG("Unable to open %s, cannot check TDX", KVM_DEVICE);
+        return false;
+    }
+
+    if ((types = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_VM_TYPES)) < 0)
+        types = 0;
+
+    VIR_DEBUG("KVM VM types: 0x%x", types);
+
+    return !!(types & (1 << KVM_X86_TDX_VM));
+#else
+    VIR_DEBUG("KVM not compiled");
+    return false;
+#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 void
+virQEMUCapsProbeTDXCapabilities(virQEMUCaps *qemuCaps)
+{
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_TDX_GUEST))
+        return;
+
+    if (!virQEMUCapsKVMSupportsVMTypeTDX())
+        virQEMUCapsClear(qemuCaps, QEMU_CAPS_TDX_GUEST);
+}
+
+
 static int
 virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps,
                                    qemuMonitor *mon)
@@ -5910,6 +5960,7 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps,
         return -1;
     if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0)
         return -1;
+    virQEMUCapsProbeTDXCapabilities(qemuCaps);
 
     virQEMUCapsInitProcessCaps(qemuCaps);
 
index 2b519be3a87a5add5172a774ca42b711bc122dc9..f180844e667862ae4ff961f513993d1fde61fbd6 100644 (file)
@@ -980,3 +980,6 @@ int
 virQEMUCapsProbeQMPMachineTypes(virQEMUCaps *qemuCaps,
                                 virDomainVirtType virtType,
                                 qemuMonitor *mon);
+
+bool
+virQEMUCapsKVMSupportsVMTypeTDX(void) ATTRIBUTE_MOCKABLE;
index cb6e98dbb892994f7775b970c01c8811609a3777..7bece6c8c1ac6b0f423ed06d5b3258729793dce4 100644 (file)
@@ -48,6 +48,12 @@ virHostCPUGetPhysAddrSize(const virArch hostArch,
 }
 
 #if WITH_QEMU
+bool
+virQEMUCapsKVMSupportsVMTypeTDX(void)
+{
+    return true;
+}
+
 static bool (*real_virQEMUCapsGetKVMSupportsSecureGuest)(virQEMUCaps *qemuCaps);
 
 bool