diff mbox series

[RFC,v2,05/69] KVM: TDX: Add architectural definitions for structures and values

Message ID d29b2ac2090f20e8de96888742feb413f597f1dc.1625186503.git.isaku.yamahata@intel.com (mailing list archive)
State New, archived
Headers show
Series KVM: X86: TDX support | expand

Commit Message

Isaku Yamahata July 2, 2021, 10:04 p.m. UTC
From: Sean Christopherson <sean.j.christopherson@intel.com>

Add structures and values that are architecturally defined in
[1] chapter 18 ABI Reference: Data Types and in [1] 20.2.1 SEAMCALL
Instruction(Common) Table 20.4 SEAMCALL Instruction Leaf Numbers
Definition.

[1] TDX Module Spec
https://software.intel.com/content/dam/develop/external/us/en/documents/intel-tdx-guest-hypervisor-communication-interface.pdf

Co-developed-by: Kai Huang <kai.huang@linux.intel.com>
Signed-off-by: Kai Huang <kai.huang@linux.intel.com>
Co-developed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Co-developed-by: Chao Gao <chao.gao@intel.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
---
 arch/x86/kvm/vmx/tdx_arch.h | 307 ++++++++++++++++++++++++++++++++++++
 1 file changed, 307 insertions(+)
 create mode 100644 arch/x86/kvm/vmx/tdx_arch.h

Comments

Erdem Aktas July 31, 2021, 1:04 a.m. UTC | #1
On Fri, Jul 2, 2021 at 3:05 PM <isaku.yamahata@intel.com> wrote:
> +/* Management class fields */
> +enum tdx_guest_management {
> +       TD_VCPU_PEND_NMI = 11,
> +};
> +
> +/* @field is any of enum tdx_guest_management */
> +#define TDVPS_MANAGEMENT(field)        BUILD_TDX_FIELD(32, (field))

I am a little confused with this. According to the spec, PEND_NMI has
a field code of 0x200000000000000B
I can understand that 0x20 is the class code and the PEND_NMI field code is 0xB.
On the other hand, for the LAST_EXIT_TSC the field code is  0xA00000000000000A.
Based on your code and the table in the spec, I can see that there is
an additional mask (1ULL<<63) for readonly fields.
Is this information correct and is this included in the spec? I tried
to find it but somehow I do not see it clearly defined.

> +#define TDX1_NR_TDCX_PAGES             4
> +#define TDX1_NR_TDVPX_PAGES            5
> +
> +#define TDX1_MAX_NR_CPUID_CONFIGS      6
Why is this just 6? I am looking at the CPUID table in the spec and
there are already more than 6 CPUID leaves there.

> +#define TDX1_MAX_NR_CMRS               32
> +#define TDX1_MAX_NR_TDMRS              64
> +#define TDX1_MAX_NR_RSVD_AREAS         16
> +#define TDX1_PAMT_ENTRY_SIZE           16
> +#define TDX1_EXTENDMR_CHUNKSIZE                256

I believe all of the defined variables above need to be enumerated
with TDH.SYS.INFO.

> +#define TDX_TDMR_ADDR_ALIGNMENT        512
Is TDX_TDMR_ADDR_ALIGNMENT used anywhere or is it just for completeness?

> +#define TDX_TDMR_INFO_ALIGNMENT        512
Why do we have alignment of 512, I am assuming to make it cache line
size aligned for efficiency?


> +#define TDX_TDSYSINFO_STRUCT_ALIGNEMNT 1024

typo: ALIGNEMNT -> ALIGNMENT

-Erdem
Xiaoyao Li Aug. 2, 2021, 1:25 p.m. UTC | #2
On 7/31/2021 9:04 AM, Erdem Aktas wrote:
> On Fri, Jul 2, 2021 at 3:05 PM <isaku.yamahata@intel.com> wrote:
>> +/* Management class fields */
>> +enum tdx_guest_management {
>> +       TD_VCPU_PEND_NMI = 11,
>> +};
>> +
>> +/* @field is any of enum tdx_guest_management */
>> +#define TDVPS_MANAGEMENT(field)        BUILD_TDX_FIELD(32, (field))
> 
> I am a little confused with this. According to the spec, PEND_NMI has
> a field code of 0x200000000000000B
> I can understand that 0x20 is the class code and the PEND_NMI field code is 0xB.
> On the other hand, for the LAST_EXIT_TSC the field code is  0xA00000000000000A.

> Based on your code and the table in the spec, I can see that there is
> an additional mask (1ULL<<63) for readonly fields

No. bit 63 is not for readonly fields, but for non_arch fields.

Please see 18.7.1 General definition

> Is this information correct and is this included in the spec? I tried
> to find it but somehow I do not see it clearly defined.
> 
>> +#define TDX1_NR_TDCX_PAGES             4
>> +#define TDX1_NR_TDVPX_PAGES            5
>> +
>> +#define TDX1_MAX_NR_CPUID_CONFIGS      6
> Why is this just 6? I am looking at the CPUID table in the spec and
> there are already more than 6 CPUID leaves there.

This is the number of CPUID config reported by TDH.SYS.INFO. Current KVM 
only reports 6 leaves.

>> +#define TDX1_MAX_NR_CMRS               32
>> +#define TDX1_MAX_NR_TDMRS              64
>> +#define TDX1_MAX_NR_RSVD_AREAS         16
>> +#define TDX1_PAMT_ENTRY_SIZE           16
>> +#define TDX1_EXTENDMR_CHUNKSIZE                256
> 
> I believe all of the defined variables above need to be enumerated
> with TDH.SYS.INFO.

No. Only TDX1_MAX_NR_TDMRS, TDX1_MAX_NR_RSVD_AREAS and 
TDX1_PAMT_ENTRY_SIZE can be enumerated from TDH.SYS.INFO.

- TDX1_MAX_NR_CMRS is described in 18.6.3 CMR_INFO, which tells

   TDH.SYS.INFO leaf function returns a MAX_CMRS(32) entry array
   of CMR_INFO entries.

- TDX1_EXTENDMR_CHUNKSIZE is describe in 20.2.23 TDH.MR.EXTEND

>> +#define TDX_TDMR_ADDR_ALIGNMENT        512
> Is TDX_TDMR_ADDR_ALIGNMENT used anywhere or is it just for completeness?

It's the leftover during rebase. We will clean it up.

>> +#define TDX_TDMR_INFO_ALIGNMENT        512
> Why do we have alignment of 512, I am assuming to make it cache line
> size aligned for efficiency?

It should be leftover too.

SEAMCALL TDH.SYS.INFO requires each cmr info in CMR_INFO_ARRAY to be 
512B aligned

> 
>> +#define TDX_TDSYSINFO_STRUCT_ALIGNEMNT 1024
> 
> typo: ALIGNEMNT -> ALIGNMENT
> 
> -Erdem
>
Erdem Aktas Aug. 4, 2021, 8:43 p.m. UTC | #3
On Mon, Aug 2, 2021 at 6:25 AM Xiaoyao Li <xiaoyao.li@intel.com> wrote:
>
> No. bit 63 is not for readonly fields, but for non_arch fields.
>
> Please see 18.7.1 General definition
Thank you so much! make sense.

> > Is this information correct and is this included in the spec? I tried
> > to find it but somehow I do not see it clearly defined.
> >
> >> +#define TDX1_NR_TDCX_PAGES             4
> >> +#define TDX1_NR_TDVPX_PAGES            5
> >> +
> >> +#define TDX1_MAX_NR_CPUID_CONFIGS      6
> > Why is this just 6? I am looking at the CPUID table in the spec and
> > there are already more than 6 CPUID leaves there.
>
> This is the number of CPUID config reported by TDH.SYS.INFO. Current KVM
> only reports 6 leaves.

I, personally, still think that it should be enumerated, rather than
hardcoded. It is not clear to me why it is 6 and nothing in the spec
says it will not change.

> >> +#define TDX1_MAX_NR_CMRS               32
> >> +#define TDX1_MAX_NR_TDMRS              64
> >> +#define TDX1_MAX_NR_RSVD_AREAS         16
> >> +#define TDX1_PAMT_ENTRY_SIZE           16
> >> +#define TDX1_EXTENDMR_CHUNKSIZE                256
> >
> > I believe all of the defined variables above need to be enumerated
> > with TDH.SYS.INFO.
>
> No. Only TDX1_MAX_NR_TDMRS, TDX1_MAX_NR_RSVD_AREAS and
> TDX1_PAMT_ENTRY_SIZE can be enumerated from TDH.SYS.INFO.
>
> - TDX1_MAX_NR_CMRS is described in 18.6.3 CMR_INFO, which tells
>
>    TDH.SYS.INFO leaf function returns a MAX_CMRS(32) entry array
>    of CMR_INFO entries.
>
> - TDX1_EXTENDMR_CHUNKSIZE is describe in 20.2.23 TDH.MR.EXTEND

Thanks for the pointers for MAX_CMRS and TDX1_EXTENDMR_CHUNKSIZE.
Will the rest of it be enumerated or hardcoded?

> >> +#define TDX_TDMR_ADDR_ALIGNMENT        512
> > Is TDX_TDMR_ADDR_ALIGNMENT used anywhere or is it just for completeness?
>
> It's the leftover during rebase. We will clean it up.
Thanks!

> SEAMCALL TDH.SYS.INFO requires each cmr info in CMR_INFO_ARRAY to be
> 512B aligned

Make sense, Thanks for the explanation.
Sean Christopherson Aug. 4, 2021, 11:13 p.m. UTC | #4
On Wed, Aug 04, 2021, Erdem Aktas wrote:
> On Mon, Aug 2, 2021 at 6:25 AM Xiaoyao Li <xiaoyao.li@intel.com> wrote:
> > > Is this information correct and is this included in the spec? I tried
> > > to find it but somehow I do not see it clearly defined.
> > >
> > >> +#define TDX1_NR_TDCX_PAGES             4
> > >> +#define TDX1_NR_TDVPX_PAGES            5
> > >> +
> > >> +#define TDX1_MAX_NR_CPUID_CONFIGS      6
> > > Why is this just 6? I am looking at the CPUID table in the spec and
> > > there are already more than 6 CPUID leaves there.
> >
> > This is the number of CPUID config reported by TDH.SYS.INFO. Current KVM
> > only reports 6 leaves.
> 
> I, personally, still think that it should be enumerated, rather than
> hardcoded. It is not clear to me why it is 6 and nothing in the spec
> says it will not change.

It's both hardcoded and enumerated.  KVM's hardcoded value is specifically the
maximum value expected for TDX-Module modules supporting the so called "1.0" spec.
It's certainly possible a spec change could bump the maximum, but KVM will refuse
to use a module with higher maximums until Linux/KVM is updated to play nice with
the new module.

Having hardcoded maximum allows for simpler and more efficient code, as loops and
arrays can be statically defined instead of having to pass around the enumerated
values.

And we'd want sanity checking anyways, e.g. if the TDX-module pulled a stupid and
reported that it needs 4000 TDCX pages.  This approach gives KVM documented values
to sanity check, e.g. instead of arbitrary magic numbers.

The downside of this approach is that KVM will need to be updated to play nice
with a new module if any of these maximums are raised.  But, IMO that's acceptable
because I can't imagine a scenario where anyone would want to load a TDX module
without first testing the daylights out of the specific kernel+TDX combination,
especially a TDX-module that by definition includes new features.

> > >> +#define TDX1_MAX_NR_CMRS               32
> > >> +#define TDX1_MAX_NR_TDMRS              64
> > >> +#define TDX1_MAX_NR_RSVD_AREAS         16
> > >> +#define TDX1_PAMT_ENTRY_SIZE           16
> > >> +#define TDX1_EXTENDMR_CHUNKSIZE                256
> > >
> > > I believe all of the defined variables above need to be enumerated
> > > with TDH.SYS.INFO.

And they are, though I believe the code for doing the actual SEAMCALL wasn't
posted in this series.  The output is sanity checked by tdx_hardware_enable():

+	tdx_caps.tdcs_nr_pages = tdsysinfo->tdcs_base_size / PAGE_SIZE;
+	if (tdx_caps.tdcs_nr_pages != TDX1_NR_TDCX_PAGES)
+		return -EIO;
+
+	tdx_caps.tdvpx_nr_pages = tdsysinfo->tdvps_base_size / PAGE_SIZE - 1;
+	if (tdx_caps.tdvpx_nr_pages != TDX1_NR_TDVPX_PAGES)
+		return -EIO;
+
+	tdx_caps.attrs_fixed0 = tdsysinfo->attributes_fixed0;
+	tdx_caps.attrs_fixed1 = tdsysinfo->attributes_fixed1;
+	tdx_caps.xfam_fixed0 =	tdsysinfo->xfam_fixed0;
+	tdx_caps.xfam_fixed1 = tdsysinfo->xfam_fixed1;
+
+	tdx_caps.nr_cpuid_configs = tdsysinfo->num_cpuid_config;
+	if (tdx_caps.nr_cpuid_configs > TDX1_MAX_NR_CPUID_CONFIGS)
+		return -EIO;
+
diff mbox series

Patch

diff --git a/arch/x86/kvm/vmx/tdx_arch.h b/arch/x86/kvm/vmx/tdx_arch.h
new file mode 100644
index 000000000000..57e9ea4a7fad
--- /dev/null
+++ b/arch/x86/kvm/vmx/tdx_arch.h
@@ -0,0 +1,307 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_X86_TDX_ARCH_H
+#define __KVM_X86_TDX_ARCH_H
+
+#include <linux/types.h>
+
+/*
+ * TDX SEAMCALL API function leaves
+ */
+#define SEAMCALL_TDH_VP_ENTER			0
+#define SEAMCALL_TDH_MNG_ADDCX			1
+#define SEAMCALL_TDH_MEM_PAGE_ADD		2
+#define SEAMCALL_TDH_MEM_SEPT_ADD		3
+#define SEAMCALL_TDH_VP_ADDCX			4
+#define SEAMCALL_TDH_MEM_PAGE_AUG		6
+#define SEAMCALL_TDH_MEM_RANGE_BLOCK		7
+#define SEAMCALL_TDH_MNG_KEY_CONFIG		8
+#define SEAMCALL_TDH_MNG_CREATE			9
+#define SEAMCALL_TDH_VP_CREATE			10
+#define SEAMCALL_TDH_MNG_RD			11
+#define SEAMCALL_TDH_PHYMEM_PAGE_RD		12
+#define SEAMCALL_TDH_MNG_WR			13
+#define SEAMCALL_TDH_PHYMEM_PAGE_WR		14
+#define SEAMCALL_TDH_MEM_PAGE_DEMOTE		15
+#define SEAMCALL_TDH_MR_EXTEND			16
+#define SEAMCALL_TDH_MR_FINALIZE		17
+#define SEAMCALL_TDH_VP_FLUSH			18
+#define SEAMCALL_TDH_MNG_VPFLUSHDONE		19
+#define SEAMCALL_TDH_MNG_KEY_FREEID		20
+#define SEAMCALL_TDH_MNG_INIT			21
+#define SEAMCALL_TDH_VP_INIT			22
+#define SEAMCALL_TDH_MEM_PAGE_PROMOTE		23
+#define SEAMCALL_TDH_PHYMEM_PAGE_RDMD		24
+#define SEAMCALL_TDH_MEM_SEPT_RD		25
+#define SEAMCALL_TDH_VP_RD			26
+#define SEAMCALL_TDH_MNG_KEY_RECLAIMID		27
+#define SEAMCALL_TDH_PHYMEM_PAGE_RECLAIM	28
+#define SEAMCALL_TDH_MEM_PAGE_REMOVE		29
+#define SEAMCALL_TDH_MEM_SEPT_REMOVE		30
+#define SEAMCALL_TDH_SYS_KEY_CONFIG		31
+#define SEAMCALL_TDH_SYS_INFO			32
+#define SEAMCALL_TDH_SYS_INIT			33
+#define SEAMCALL_TDH_SYS_LP_INIT		35
+#define SEAMCALL_TDH_SYS_TDMR_INIT		36
+#define SEAMCALL_TDH_MEM_TRACK			38
+#define SEAMCALL_TDH_MEM_RANGE_UNBLOCK		39
+#define SEAMCALL_TDH_PHYMEM_CACHE_WB		40
+#define SEAMCALL_TDH_PHYMEM_PAGE_WBINVD		41
+#define SEAMCALL_TDH_MEM_SEPT_WR		42
+#define SEAMCALL_TDH_VP_WR			43
+#define SEAMCALL_TDH_SYS_LP_SHUTDOWN		44
+#define SEAMCALL_TDH_SYS_CONFIG			45
+
+#define TDG_VP_VMCALL_GET_TD_VM_CALL_INFO		0x10000
+#define TDG_VP_VMCALL_MAP_GPA				0x10001
+#define TDG_VP_VMCALL_GET_QUOTE				0x10002
+#define TDG_VP_VMCALL_REPORT_FATAL_ERROR		0x10003
+#define TDG_VP_VMCALL_SETUP_EVENT_NOTIFY_INTERRUPT	0x10004
+
+/* TDX control structure (TDR/TDCS/TDVPS) field access codes */
+#define TDX_CLASS_SHIFT		56
+#define TDX_FIELD_MASK		GENMASK_ULL(31, 0)
+
+#define BUILD_TDX_FIELD(class, field)	\
+	(((u64)(class) << TDX_CLASS_SHIFT) | ((u64)(field) & TDX_FIELD_MASK))
+
+/* @field is the VMCS field encoding */
+#define TDVPS_VMCS(field)	BUILD_TDX_FIELD(0, (field))
+
+/*
+ * @offset is the offset (in bytes) from the beginning of the architectural
+ * virtual APIC page.
+ */
+#define TDVPS_APIC(offset)	BUILD_TDX_FIELD(1, (offset))
+
+/* @gpr is the index of a general purpose register, e.g. eax=0 */
+#define TDVPS_GPR(gpr)		BUILD_TDX_FIELD(16, (gpr))
+
+#define TDVPS_DR(dr)		BUILD_TDX_FIELD(17, (0 + (dr)))
+
+enum tdx_guest_other_state {
+	TD_VCPU_XCR0 = 32,
+	TD_VCPU_IWK_ENCKEY0 = 64,
+	TD_VCPU_IWK_ENCKEY1,
+	TD_VCPU_IWK_ENCKEY2,
+	TD_VCPU_IWK_ENCKEY3,
+	TD_VCPU_IWK_INTKEY0 = 68,
+	TD_VCPU_IWK_INTKEY1,
+	TD_VCPU_IWK_FLAGS = 70,
+};
+
+/* @field is any of enum tdx_guest_other_state */
+#define TDVPS_STATE(field)	BUILD_TDX_FIELD(17, (field))
+
+/* @msr is the MSR index */
+#define TDVPS_MSR(msr)		BUILD_TDX_FIELD(19, (msr))
+
+/* Management class fields */
+enum tdx_guest_management {
+	TD_VCPU_PEND_NMI = 11,
+};
+
+/* @field is any of enum tdx_guest_management */
+#define TDVPS_MANAGEMENT(field)	BUILD_TDX_FIELD(32, (field))
+
+#define TDX1_NR_TDCX_PAGES		4
+#define TDX1_NR_TDVPX_PAGES		5
+
+#define TDX1_MAX_NR_CPUID_CONFIGS	6
+#define TDX1_MAX_NR_CMRS		32
+#define TDX1_MAX_NR_TDMRS		64
+#define TDX1_MAX_NR_RSVD_AREAS		16
+#define TDX1_PAMT_ENTRY_SIZE		16
+#define TDX1_EXTENDMR_CHUNKSIZE		256
+
+struct tdx_cpuid_config {
+	u32 leaf;
+	u32 sub_leaf;
+	u32 eax;
+	u32 ebx;
+	u32 ecx;
+	u32 edx;
+} __packed;
+
+struct tdx_cpuid_value {
+	u32 eax;
+	u32 ebx;
+	u32 ecx;
+	u32 edx;
+} __packed;
+
+#define TDX1_TD_ATTRIBUTE_DEBUG		BIT_ULL(0)
+#define TDX1_TD_ATTRIBUTE_PKS		BIT_ULL(30)
+#define TDX1_TD_ATTRIBUTE_KL		BIT_ULL(31)
+#define TDX1_TD_ATTRIBUTE_PERFMON	BIT_ULL(63)
+
+/*
+ * TD_PARAMS is provided as an input to TDH_MNG_INIT, the size of which is 1024B.
+ */
+struct td_params {
+	u64 attributes;
+	u64 xfam;
+	u32 max_vcpus;
+	u32 reserved0;
+
+	u64 eptp_controls;
+	u64 exec_controls;
+	u16 tsc_frequency;
+	u8  reserved1[38];
+
+	u64 mrconfigid[6];
+	u64 mrowner[6];
+	u64 mrownerconfig[6];
+	u64 reserved2[4];
+
+	union {
+		struct tdx_cpuid_value cpuid_values[0];
+		u8 reserved3[768];
+	};
+} __packed __aligned(1024);
+
+/* Guest uses MAX_PA for GPAW when set. */
+#define TDX1_EXEC_CONTROL_MAX_GPAW      BIT_ULL(0)
+
+/*
+ * TDX1 requires the frequency to be defined in units of 25MHz, which is the
+ * frequency of the core crystal clock on TDX-capable platforms, i.e. TDX-SEAM
+ * can only program frequencies that are multiples of 25MHz.  The frequency
+ * must be between 1ghz and 10ghz (inclusive).
+ */
+#define TDX1_TSC_KHZ_TO_25MHZ(tsc_in_khz)	((tsc_in_khz) / (25 * 1000))
+#define TDX1_TSC_25MHZ_TO_KHZ(tsc_in_25mhz)	((tsc_in_25mhz) * (25 * 1000))
+#define TDX1_MIN_TSC_FREQUENCY_KHZ		(100 * 1000)
+#define TDX1_MAX_TSC_FREQUENCY_KHZ		(10 * 1000 * 1000)
+
+struct tdmr_reserved_area {
+	u64 offset;
+	u64 size;
+} __packed;
+
+#define TDX_TDMR_ADDR_ALIGNMENT	512
+#define TDX_TDMR_INFO_ALIGNMENT	512
+struct tdmr_info {
+	u64 base;
+	u64 size;
+	u64 pamt_1g_base;
+	u64 pamt_1g_size;
+	u64 pamt_2m_base;
+	u64 pamt_2m_size;
+	u64 pamt_4k_base;
+	u64 pamt_4k_size;
+	struct tdmr_reserved_area reserved_areas[TDX1_MAX_NR_RSVD_AREAS];
+} __packed __aligned(TDX_TDMR_INFO_ALIGNMENT);
+
+#define TDX_CMR_INFO_ARRAY_ALIGNMENT	512
+struct cmr_info {
+	u64 base;
+	u64 size;
+} __packed;
+
+#define TDX_TDSYSINFO_STRUCT_ALIGNEMNT	1024
+struct tdsysinfo_struct {
+	/* TDX-SEAM Module Info */
+	u32 attributes;
+	u32 vendor_id;
+	u32 build_date;
+	u16 build_num;
+	u16 minor_version;
+	u16 major_version;
+	u8 reserved0[14];
+	/* Memory Info */
+	u16 max_tdmrs;
+	u16 max_reserved_per_tdmr;
+	u16 pamt_entry_size;
+	u8 reserved1[10];
+	/* Control Struct Info */
+	u16 tdcs_base_size;
+	u8 reserved2[2];
+	u16 tdvps_base_size;
+	u8 tdvps_xfam_dependent_size;
+	u8 reserved3[9];
+	/* TD Capabilities */
+	u64 attributes_fixed0;
+	u64 attributes_fixed1;
+	u64 xfam_fixed0;
+	u64 xfam_fixed1;
+	u8 reserved4[32];
+	u32 num_cpuid_config;
+	union {
+		struct tdx_cpuid_config cpuid_configs[0];
+		u8 reserved5[892];
+	};
+} __packed __aligned(TDX_TDSYSINFO_STRUCT_ALIGNEMNT);
+
+struct tdx_ex_ret {
+	union {
+		/* Used to retrieve values from hardware. */
+		struct {
+			u64 rcx;
+			u64 rdx;
+			u64 r8;
+			u64 r9;
+			u64 r10;
+			u64 r11;
+		};
+		/* Functions that walk SEPT */
+		struct {
+			u64 septe;
+			struct {
+				u64 level		:3;
+				u64 sept_reserved_0	:5;
+				u64 state		:8;
+				u64 sept_reserved_1	:48;
+			};
+		};
+		/* TD_MNG_{RD,WR} return the TDR, field code, and value. */
+		struct {
+			u64 tdr;
+			u64 field;
+			u64 field_val;
+		};
+		/* TD_MNG_{RD,WR}MEM return the address and its value. */
+		struct {
+			u64 addr;
+			u64 val;
+		};
+		/* TDH_PHYMEM_PAGE_RDMD and TDH_PHYMEM_PAGE_RECLAIM return page metadata. */
+		struct {
+			u64 page_type;
+			u64 owner;
+			u64 page_size;
+		};
+		/*
+		 * TDH_SYS_INFO returns the buffer address and its size, and the
+		 * CMR_INFO address and its number of entries.
+		 */
+		struct {
+			u64 buffer;
+			u64 nr_bytes;
+			u64 cmr_info;
+			u64 nr_cmr_entries;
+		};
+		/*
+		 * TDH_MNG_INIT and TDH_SYS_INIT return CPUID info on error.  Note, only
+		 * the leaf and subleaf are valid on TDH_MNG_INIT error.
+		 */
+		struct {
+			u32 leaf;
+			u32 subleaf;
+			u32 eax_mask;
+			u32 ebx_mask;
+			u32 ecx_mask;
+			u32 edx_mask;
+			u32 eax_val;
+			u32 ebx_val;
+			u32 ecx_val;
+			u32 edx_val;
+		};
+		/* TDH_SYS_TDMR_INIT returns the input PA and next PA. */
+		struct {
+			u64 prev;
+			u64 next;
+		};
+	};
+};
+
+#endif /* __KVM_X86_TDX_ARCH_H */