Message ID | d29b2ac2090f20e8de96888742feb413f597f1dc.1625186503.git.isaku.yamahata@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM: X86: TDX support | expand |
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
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 >
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.
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 --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 */