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 | 51 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 3 +++ tests/domaincapsmock.c | 6 +++++ 3 files changed, 60 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 4050d5ccc6..9196ea1bb6 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -54,11 +54,17 @@ # include <sys/types.h> # include <sys/sysctl.h> #endif +#ifdef __linux__ +# 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 = false; + + 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); diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 2b519be3a8..f180844e66 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -980,3 +980,6 @@ int virQEMUCapsProbeQMPMachineTypes(virQEMUCaps *qemuCaps, virDomainVirtType virtType, qemuMonitor *mon); + +bool +virQEMUCapsKVMSupportsVMTypeTDX(void) ATTRIBUTE_MOCKABLE; diff --git a/tests/domaincapsmock.c b/tests/domaincapsmock.c index cb6e98dbb8..7bece6c8c1 100644 --- a/tests/domaincapsmock.c +++ b/tests/domaincapsmock.c @@ -48,6 +48,12 @@ virHostCPUGetPhysAddrSize(const virArch hostArch, } #if WITH_QEMU +bool +virQEMUCapsKVMSupportsVMTypeTDX(void) +{ + return true; +} + static bool (*real_virQEMUCapsGetKVMSupportsSecureGuest)(virQEMUCaps *qemuCaps); bool -- 2.51.1