diff mbox series

[RFC,v2,06/44] hw/i386: Introduce kvm-type for TDX guest

Message ID 04c08d0770736cfa2e3148489602bc42492c78f3.1625704980.git.isaku.yamahata@intel.com (mailing list archive)
State New, archived
Headers show
Series TDX support | expand

Commit Message

Isaku Yamahata July 8, 2021, 12:54 a.m. UTC
From: Xiaoyao Li <xiaoyao.li@intel.com>

Introduce a machine property, kvm-type, to allow the user to create a
Trusted Domain eXtensions (TDX) VM, a.k.a. a Trusted Domain (TD), e.g.:

 # $QEMU \
	-machine ...,kvm-type=tdx \
	...

Only two types are supported: "legacy" and "tdx", with "legacy" being
the default.

Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Co-developed-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
---
 default-configs/devices/i386-softmmu.mak |  1 +
 hw/i386/Kconfig                          |  5 +++
 hw/i386/x86.c                            | 44 ++++++++++++++++++++++++
 include/hw/i386/x86.h                    |  1 +
 include/sysemu/tdx.h                     | 10 ++++++
 target/i386/kvm/kvm-stub.c               |  5 +++
 target/i386/kvm/kvm.c                    | 16 +++++++++
 target/i386/kvm/kvm_i386.h               |  1 +
 target/i386/kvm/meson.build              |  1 +
 target/i386/kvm/tdx-stub.c               | 10 ++++++
 target/i386/kvm/tdx.c                    | 30 ++++++++++++++++
 11 files changed, 124 insertions(+)
 create mode 100644 include/sysemu/tdx.h
 create mode 100644 target/i386/kvm/tdx-stub.c
 create mode 100644 target/i386/kvm/tdx.c

Comments

Connor Kuehl July 22, 2021, 5:53 p.m. UTC | #1
On 7/7/21 7:54 PM, isaku.yamahata@gmail.com wrote:
> From: Xiaoyao Li <xiaoyao.li@intel.com>
> 
> Introduce a machine property, kvm-type, to allow the user to create a
> Trusted Domain eXtensions (TDX) VM, a.k.a. a Trusted Domain (TD), e.g.:
> 
>   # $QEMU \
> 	-machine ...,kvm-type=tdx \
> 	...
> 
> Only two types are supported: "legacy" and "tdx", with "legacy" being
> the default.
> 
> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> Co-developed-by: Sean Christopherson <sean.j.christopherson@intel.com>
> Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>

I am not a QEMU command line expert, so my mental model of this may be
wrong, but:

This seems to have a very broad scope on the command line and I
am wondering if it's possible to associate it with a TDX command
line object specifically to narrow its scope.

I.e., is it possible to express this on the command line when
launching something that is _not_ meant to be powered by TDX,
such as an SEV guest? If it doesn't make sense to express that
command line argument in a situation like that, perhaps it could
be constrained only to the TDX-specific commandline objects.
Gerd Hoffmann Aug. 26, 2021, 10:22 a.m. UTC | #2
On Wed, Jul 07, 2021 at 05:54:36PM -0700, isaku.yamahata@gmail.com wrote:
> From: Xiaoyao Li <xiaoyao.li@intel.com>
> 
> Introduce a machine property, kvm-type, to allow the user to create a
> Trusted Domain eXtensions (TDX) VM, a.k.a. a Trusted Domain (TD), e.g.:
> 
>  # $QEMU \
> 	-machine ...,kvm-type=tdx \
> 	...

Can we align sev and tdx better than that?

SEV is enabled this way:

qemu -machine ...,confidential-guest-support=sev0 \
     -object sev-guest,id=sev0,...

(see docs/amd-memory-encryption.txt for details).

tdx could likewise use a tdx-guest object (and both sev-guest and
tdx-guest should probably have a common parent object type) to enable
and configure tdx support.

take care,
  Gerd
Xiaoyao Li Nov. 24, 2021, 7:31 a.m. UTC | #3
On 8/26/2021 6:22 PM, Gerd Hoffmann wrote:
> On Wed, Jul 07, 2021 at 05:54:36PM -0700, isaku.yamahata@gmail.com wrote:
>> From: Xiaoyao Li <xiaoyao.li@intel.com>
>>
>> Introduce a machine property, kvm-type, to allow the user to create a
>> Trusted Domain eXtensions (TDX) VM, a.k.a. a Trusted Domain (TD), e.g.:
>>
>>   # $QEMU \
>> 	-machine ...,kvm-type=tdx \
>> 	...

Sorry for the very late reply.

> Can we align sev and tdx better than that?
> 
> SEV is enabled this way:
> 
> qemu -machine ...,confidential-guest-support=sev0 \
>       -object sev-guest,id=sev0,...
> 
> (see docs/amd-memory-encryption.txt for details).
> 
> tdx could likewise use a tdx-guest object (and both sev-guest and
> tdx-guest should probably have a common parent object type) to enable
> and configure tdx support.

yes, sev only introduced a new object and passed it to 
confidential-guest-support. This is because SEV doesn't require the new 
type of VM.
However, TDX does require a new type of VM.

If we read KVM code, there is a parameter of CREATE_VM to pass the 
vm_type, though x86 doesn't use this field so far. On QEMU side, it also 
has the codes to pass/configure vm-type in command line. Of cousre, x86 
arch doesn't implement it. With upcoming TDX, it will implement and use 
vm type for TDX. That's the reason we wrote this patch to implement 
kvm-type for x86, similar to other arches.

yes, of course we can infer the vm_type from "-object tdx-guest". But I 
prefer to just use vm_type. Let's see others opinion.

thanks,
-Xiaoyao

> take care,
>    Gerd
>
Daniel P. Berrangé Jan. 10, 2022, 11:18 a.m. UTC | #4
On Wed, Nov 24, 2021 at 03:31:13PM +0800, Xiaoyao Li wrote:
> On 8/26/2021 6:22 PM, Gerd Hoffmann wrote:
> > On Wed, Jul 07, 2021 at 05:54:36PM -0700, isaku.yamahata@gmail.com wrote:
> > > From: Xiaoyao Li <xiaoyao.li@intel.com>
> > > 
> > > Introduce a machine property, kvm-type, to allow the user to create a
> > > Trusted Domain eXtensions (TDX) VM, a.k.a. a Trusted Domain (TD), e.g.:
> > > 
> > >   # $QEMU \
> > > 	-machine ...,kvm-type=tdx \
> > > 	...
> 
> Sorry for the very late reply.
> 
> > Can we align sev and tdx better than that?
> > 
> > SEV is enabled this way:
> > 
> > qemu -machine ...,confidential-guest-support=sev0 \
> >       -object sev-guest,id=sev0,...
> > 
> > (see docs/amd-memory-encryption.txt for details).
> > 
> > tdx could likewise use a tdx-guest object (and both sev-guest and
> > tdx-guest should probably have a common parent object type) to enable
> > and configure tdx support.
> 
> yes, sev only introduced a new object and passed it to
> confidential-guest-support. This is because SEV doesn't require the new type
> of VM.
> However, TDX does require a new type of VM.
> 
> If we read KVM code, there is a parameter of CREATE_VM to pass the vm_type,
> though x86 doesn't use this field so far. On QEMU side, it also has the
> codes to pass/configure vm-type in command line. Of cousre, x86 arch doesn't
> implement it. With upcoming TDX, it will implement and use vm type for TDX.
> That's the reason we wrote this patch to implement kvm-type for x86, similar
> to other arches.
> 
> yes, of course we can infer the vm_type from "-object tdx-guest". But I
> prefer to just use vm_type. Let's see others opinion.

It isn't just SEV that is using the confidential-guest-support approach.
This was done for PPC64 and S390x too.  This gives QEMU a standard
internal interface to declare that a confidential guest is being used /
configured. IMHO, TDX needs to use this too, unless there's a compelling
technical reason why it is a bad approach & needs to diverge from every
other confidential guest impl in QEMU.

Regards,
Daniel
Xiaoyao Li Jan. 10, 2022, 12:01 p.m. UTC | #5
On 1/10/2022 7:18 PM, Daniel P. Berrangé wrote:
> On Wed, Nov 24, 2021 at 03:31:13PM +0800, Xiaoyao Li wrote:
>> On 8/26/2021 6:22 PM, Gerd Hoffmann wrote:
>>> On Wed, Jul 07, 2021 at 05:54:36PM -0700, isaku.yamahata@gmail.com wrote:
>>>> From: Xiaoyao Li <xiaoyao.li@intel.com>
>>>>
>>>> Introduce a machine property, kvm-type, to allow the user to create a
>>>> Trusted Domain eXtensions (TDX) VM, a.k.a. a Trusted Domain (TD), e.g.:
>>>>
>>>>    # $QEMU \
>>>> 	-machine ...,kvm-type=tdx \
>>>> 	...
>>
>> Sorry for the very late reply.
>>
>>> Can we align sev and tdx better than that?
>>>
>>> SEV is enabled this way:
>>>
>>> qemu -machine ...,confidential-guest-support=sev0 \
>>>        -object sev-guest,id=sev0,...
>>>
>>> (see docs/amd-memory-encryption.txt for details).
>>>
>>> tdx could likewise use a tdx-guest object (and both sev-guest and
>>> tdx-guest should probably have a common parent object type) to enable
>>> and configure tdx support.
>>
>> yes, sev only introduced a new object and passed it to
>> confidential-guest-support. This is because SEV doesn't require the new type
>> of VM.
>> However, TDX does require a new type of VM.
>>
>> If we read KVM code, there is a parameter of CREATE_VM to pass the vm_type,
>> though x86 doesn't use this field so far. On QEMU side, it also has the
>> codes to pass/configure vm-type in command line. Of cousre, x86 arch doesn't
>> implement it. With upcoming TDX, it will implement and use vm type for TDX.
>> That's the reason we wrote this patch to implement kvm-type for x86, similar
>> to other arches.
>>
>> yes, of course we can infer the vm_type from "-object tdx-guest". But I
>> prefer to just use vm_type. Let's see others opinion.
> 
> It isn't just SEV that is using the confidential-guest-support approach.
> This was done for PPC64 and S390x too.  This gives QEMU a standard
> internal interface to declare that a confidential guest is being used /
> configured. IMHO, TDX needs to use this too, unless there's a compelling
> technical reason why it is a bad approach & needs to diverge from every
> other confidential guest impl in QEMU.
> 

Forgot to tell the update that we went the direction to identify the TDX 
vm_type based on confidential-guest_support like below:


if (ms->cgs && object_dynamic_cast(OBJECT(ms->cgs), TYPE_TDX_GUEST)) {
         kvm_type = KVM_X86_TDX_VM;
} else {
         kvm_type = KVM_X86_DEFAULT_VM;
}


I think it's what you want, right?

BTW, the whole next version of TDX QEMU series should be released with 
next version of TDX KVM series. But I cannot tell the exact date yet.
Daniel P. Berrangé Jan. 10, 2022, 12:05 p.m. UTC | #6
On Mon, Jan 10, 2022 at 08:01:33PM +0800, Xiaoyao Li wrote:
> On 1/10/2022 7:18 PM, Daniel P. Berrangé wrote:
> > On Wed, Nov 24, 2021 at 03:31:13PM +0800, Xiaoyao Li wrote:
> > > On 8/26/2021 6:22 PM, Gerd Hoffmann wrote:
> > > > On Wed, Jul 07, 2021 at 05:54:36PM -0700, isaku.yamahata@gmail.com wrote:
> > > > > From: Xiaoyao Li <xiaoyao.li@intel.com>
> > > > > 
> > > > > Introduce a machine property, kvm-type, to allow the user to create a
> > > > > Trusted Domain eXtensions (TDX) VM, a.k.a. a Trusted Domain (TD), e.g.:
> > > > > 
> > > > >    # $QEMU \
> > > > > 	-machine ...,kvm-type=tdx \
> > > > > 	...
> > > 
> > > Sorry for the very late reply.
> > > 
> > > > Can we align sev and tdx better than that?
> > > > 
> > > > SEV is enabled this way:
> > > > 
> > > > qemu -machine ...,confidential-guest-support=sev0 \
> > > >        -object sev-guest,id=sev0,...
> > > > 
> > > > (see docs/amd-memory-encryption.txt for details).
> > > > 
> > > > tdx could likewise use a tdx-guest object (and both sev-guest and
> > > > tdx-guest should probably have a common parent object type) to enable
> > > > and configure tdx support.
> > > 
> > > yes, sev only introduced a new object and passed it to
> > > confidential-guest-support. This is because SEV doesn't require the new type
> > > of VM.
> > > However, TDX does require a new type of VM.
> > > 
> > > If we read KVM code, there is a parameter of CREATE_VM to pass the vm_type,
> > > though x86 doesn't use this field so far. On QEMU side, it also has the
> > > codes to pass/configure vm-type in command line. Of cousre, x86 arch doesn't
> > > implement it. With upcoming TDX, it will implement and use vm type for TDX.
> > > That's the reason we wrote this patch to implement kvm-type for x86, similar
> > > to other arches.
> > > 
> > > yes, of course we can infer the vm_type from "-object tdx-guest". But I
> > > prefer to just use vm_type. Let's see others opinion.
> > 
> > It isn't just SEV that is using the confidential-guest-support approach.
> > This was done for PPC64 and S390x too.  This gives QEMU a standard
> > internal interface to declare that a confidential guest is being used /
> > configured. IMHO, TDX needs to use this too, unless there's a compelling
> > technical reason why it is a bad approach & needs to diverge from every
> > other confidential guest impl in QEMU.
> > 
> 
> Forgot to tell the update that we went the direction to identify the TDX
> vm_type based on confidential-guest_support like below:
> 
> 
> if (ms->cgs && object_dynamic_cast(OBJECT(ms->cgs), TYPE_TDX_GUEST)) {
>         kvm_type = KVM_X86_TDX_VM;
> } else {
>         kvm_type = KVM_X86_DEFAULT_VM;
> }
> 
> 
> I think it's what you want, right?

Yes, that seems reasonable

Regards,
Daniel
diff mbox series

Patch

diff --git a/default-configs/devices/i386-softmmu.mak b/default-configs/devices/i386-softmmu.mak
index 84d1a2487c..6e805407b8 100644
--- a/default-configs/devices/i386-softmmu.mak
+++ b/default-configs/devices/i386-softmmu.mak
@@ -18,6 +18,7 @@ 
 #CONFIG_QXL=n
 #CONFIG_SEV=n
 #CONFIG_SGA=n
+#CONFIG_TDX=n
 #CONFIG_TEST_DEVICES=n
 #CONFIG_TPM_CRB=n
 #CONFIG_TPM_TIS_ISA=n
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index aacb6f6d96..01633123e0 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -2,6 +2,10 @@  config SEV
     bool
     depends on KVM
 
+config TDX
+    bool
+    depends on KVM
+
 config PC
     bool
     imply APPLESMC
@@ -17,6 +21,7 @@  config PC
     imply PVPANIC_ISA
     imply QXL
     imply SEV
+    imply TDX
     imply SGA
     imply TEST_DEVICES
     imply TPM_CRB
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 00448ed55a..ed15f6f2cf 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -21,6 +21,7 @@ 
  * THE SOFTWARE.
  */
 #include "qemu/osdep.h"
+#include <linux/kvm.h>
 #include "qemu/error-report.h"
 #include "qemu/option.h"
 #include "qemu/cutils.h"
@@ -31,6 +32,7 @@ 
 #include "qapi/qmp/qerror.h"
 #include "qapi/qapi-visit-common.h"
 #include "qapi/visitor.h"
+#include "sysemu/kvm_int.h"
 #include "sysemu/qtest.h"
 #include "sysemu/whpx.h"
 #include "sysemu/numa.h"
@@ -1263,6 +1265,42 @@  static void x86_machine_set_bus_lock_ratelimit(Object *obj, Visitor *v,
     visit_type_uint64(v, name, &x86ms->bus_lock_ratelimit, errp);
 }
 
+static char *x86_get_kvm_type(Object *obj, Error **errp)
+{
+    X86MachineState *x86ms = X86_MACHINE(obj);
+
+    return g_strdup(x86ms->kvm_type);
+}
+
+static void x86_set_kvm_type(Object *obj, const char *value, Error **errp)
+{
+    X86MachineState *x86ms = X86_MACHINE(obj);
+
+    g_free(x86ms->kvm_type);
+    x86ms->kvm_type = g_strdup(value);
+}
+
+static int x86_kvm_type(MachineState *ms, const char *vm_type)
+{
+    int kvm_type;
+
+    if (!vm_type || !strcmp(vm_type, "") ||
+        !g_ascii_strcasecmp(vm_type, "legacy")) {
+        kvm_type = KVM_X86_LEGACY_VM;
+    } else if (!g_ascii_strcasecmp(vm_type, "tdx")) {
+        kvm_type = KVM_X86_TDX_VM;
+    } else {
+        error_report("Unknown kvm-type specified '%s'", vm_type);
+        exit(1);
+    }
+    if (kvm_set_vm_type(ms, kvm_type)) {
+        error_report("kvm-type '%s' not supported by KVM", vm_type);
+        exit(1);
+    }
+
+    return kvm_type;
+}
+
 static void x86_machine_initfn(Object *obj)
 {
     X86MachineState *x86ms = X86_MACHINE(obj);
@@ -1273,6 +1311,11 @@  static void x86_machine_initfn(Object *obj)
     x86ms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
     x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
     x86ms->bus_lock_ratelimit = 0;
+
+    object_property_add_str(obj, "kvm-type",
+                            x86_get_kvm_type, x86_set_kvm_type);
+    object_property_set_description(obj, "kvm-type",
+                                    "KVM guest type (legacy, tdx)");
 }
 
 static void x86_machine_class_init(ObjectClass *oc, void *data)
@@ -1284,6 +1327,7 @@  static void x86_machine_class_init(ObjectClass *oc, void *data)
     mc->cpu_index_to_instance_props = x86_cpu_index_to_props;
     mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
     mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
+    mc->kvm_type = x86_kvm_type;
     x86mc->compat_apic_id_mode = false;
     x86mc->save_tsc_khz = true;
     nc->nmi_monitor_handler = x86_nmi;
diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index 6e9244a82c..a450b5e226 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -56,6 +56,7 @@  struct X86MachineState {
 
     /* RAM information (sizes, addresses, configuration): */
     ram_addr_t below_4g_mem_size, above_4g_mem_size;
+    char *kvm_type;
 
     /* CPU and apic information: */
     bool apic_xrupt_override;
diff --git a/include/sysemu/tdx.h b/include/sysemu/tdx.h
new file mode 100644
index 0000000000..60ebded851
--- /dev/null
+++ b/include/sysemu/tdx.h
@@ -0,0 +1,10 @@ 
+#ifndef QEMU_TDX_H
+#define QEMU_TDX_H
+
+#ifndef CONFIG_USER_ONLY
+#include "sysemu/kvm.h"
+
+bool kvm_has_tdx(KVMState *s);
+#endif
+
+#endif
diff --git a/target/i386/kvm/kvm-stub.c b/target/i386/kvm/kvm-stub.c
index 92f49121b8..e9221de76f 100644
--- a/target/i386/kvm/kvm-stub.c
+++ b/target/i386/kvm/kvm-stub.c
@@ -39,3 +39,8 @@  bool kvm_hv_vpindex_settable(void)
 {
     return false;
 }
+
+int kvm_set_vm_type(MachineState *ms, int kvm_type)
+{
+    return 0;
+}
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 0558e4b506..a3d5b334d1 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -27,6 +27,7 @@ 
 #include "sysemu/hw_accel.h"
 #include "sysemu/kvm_int.h"
 #include "sysemu/runstate.h"
+#include "sysemu/tdx.h"
 #include "kvm_i386.h"
 #include "sev_i386.h"
 #include "hyperv.h"
@@ -132,9 +133,24 @@  static struct kvm_cpuid2 *cpuid_cache;
 static struct kvm_cpuid2 *hv_cpuid_cache;
 static struct kvm_msr_list *kvm_feature_msrs;
 
+
 #define BUS_LOCK_SLICE_TIME 1000000000ULL /* ns */
 static RateLimit bus_lock_ratelimit_ctrl;
 
+static int vm_type;
+
+int kvm_set_vm_type(MachineState *ms, int kvm_type)
+{
+    if (kvm_type == KVM_X86_LEGACY_VM ||
+        (kvm_type == KVM_X86_TDX_VM &&
+         kvm_has_tdx(KVM_STATE(ms->accelerator)))) {
+        vm_type = kvm_type;
+        return 0;
+    }
+
+    return -ENOTSUP;
+}
+
 int kvm_has_pit_state2(void)
 {
     return has_pit_state2;
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index c9a92578b1..8e63365162 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -41,6 +41,7 @@  bool kvm_has_adjust_clock(void);
 bool kvm_has_adjust_clock_stable(void);
 bool kvm_has_exception_payload(void);
 void kvm_synchronize_all_tsc(void);
+int kvm_set_vm_type(MachineState *ms, int kvm_type);
 void kvm_arch_reset_vcpu(X86CPU *cs);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 
diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build
index 0a533411ca..3c143a3c93 100644
--- a/target/i386/kvm/meson.build
+++ b/target/i386/kvm/meson.build
@@ -6,3 +6,4 @@  i386_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files(
 ))
 
 i386_softmmu_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c'))
+i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdx.c'), if_false: files('tdx-stub.c'))
diff --git a/target/i386/kvm/tdx-stub.c b/target/i386/kvm/tdx-stub.c
new file mode 100644
index 0000000000..e1eb09cae1
--- /dev/null
+++ b/target/i386/kvm/tdx-stub.c
@@ -0,0 +1,10 @@ 
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "sysemu/tdx.h"
+
+#ifndef CONFIG_USER_ONLY
+bool kvm_has_tdx(KVMState *s)
+{
+        return false;
+}
+#endif
diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c
new file mode 100644
index 0000000000..e62a570f75
--- /dev/null
+++ b/target/i386/kvm/tdx.c
@@ -0,0 +1,30 @@ 
+/*
+ * QEMU TDX support
+ *
+ * Copyright Intel
+ *
+ * Author:
+ *      Xiaoyao Li <xiaoyao.li@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include <linux/kvm.h>
+
+#include "cpu.h"
+#include "hw/boards.h"
+#include "qapi/error.h"
+#include "qom/object_interfaces.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/kvm.h"
+#include "sysemu/kvm_int.h"
+#include "sysemu/tdx.h"
+
+bool kvm_has_tdx(KVMState *s)
+{
+    return !!(kvm_check_extension(s, KVM_CAP_VM_TYPES) & BIT(KVM_X86_TDX_VM));
+}