Skip to content

Commit 0d20742

Browse files
committed
Merge branch 'kvm-tdx-initialization' into HEAD
This series kicks off the actual interaction of KVM with the TDX module. This series encompasses the basic setup for using the TDX module from KVM, and the creation of TD VMs and vCPUs. The TDX Module is a software component that runs in a special CPU mode called SEAM (Secure Arbitration Mode). Loading it is mostly handled outside of KVM by the core kernel. Once it’s loaded KVM can interact with the TDX Module via a new instruction called SEAMCALL to virtualize a TD guests. This instruction can be used to make various types of seamcalls, with names organized into a hierarchy. The format is TDH.[AREA].[ACTION], where “TDH” stands for “Trust Domain Host”, and differentiates from another set of calls that can be done by the guest “TDG”. The KVM relevant areas of SEAMCALLs are: SYS – TDX module management, static metadata reading. MNG – TD management. VM scoped things that operate on a TDX module controlled structure called the TDCS. VP – vCPU management. vCPU scoped things that operate on TDX module controlled structures called the TDVPS. PHYMEM - Operations related to physical memory management (page reclaiming, cache operations, etc). This series introduces some TDX specific KVM APIs and stops short of fully “finalizing” the creation of a TD VM. The part of initializing a guest where initial private memory is loaded is left to a separate MMU related series.
2 parents 74c1807 + 7c035be commit 0d20742

File tree

30 files changed

+2695
-134
lines changed

30 files changed

+2695
-134
lines changed

arch/x86/include/asm/kvm-x86-ops.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ KVM_X86_OP(has_emulated_msr)
2121
KVM_X86_OP(vcpu_after_set_cpuid)
2222
KVM_X86_OP(vm_init)
2323
KVM_X86_OP_OPTIONAL(vm_destroy)
24+
KVM_X86_OP_OPTIONAL(vm_pre_destroy)
2425
KVM_X86_OP_OPTIONAL_RET0(vcpu_precreate)
2526
KVM_X86_OP(vcpu_create)
2627
KVM_X86_OP(vcpu_free)
@@ -125,7 +126,8 @@ KVM_X86_OP(leave_smm)
125126
KVM_X86_OP(enable_smi_window)
126127
#endif
127128
KVM_X86_OP_OPTIONAL(dev_get_attr)
128-
KVM_X86_OP_OPTIONAL(mem_enc_ioctl)
129+
KVM_X86_OP(mem_enc_ioctl)
130+
KVM_X86_OP_OPTIONAL(vcpu_mem_enc_ioctl)
129131
KVM_X86_OP_OPTIONAL(mem_enc_register_region)
130132
KVM_X86_OP_OPTIONAL(mem_enc_unregister_region)
131133
KVM_X86_OP_OPTIONAL(vm_copy_enc_context_from)

arch/x86/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,7 @@ struct kvm_x86_ops {
16651665
unsigned int vm_size;
16661666
int (*vm_init)(struct kvm *kvm);
16671667
void (*vm_destroy)(struct kvm *kvm);
1668+
void (*vm_pre_destroy)(struct kvm *kvm);
16681669

16691670
/* Create, but do not attach this VCPU */
16701671
int (*vcpu_precreate)(struct kvm *kvm);
@@ -1848,6 +1849,7 @@ struct kvm_x86_ops {
18481849

18491850
int (*dev_get_attr)(u32 group, u64 attr, u64 *val);
18501851
int (*mem_enc_ioctl)(struct kvm *kvm, void __user *argp);
1852+
int (*vcpu_mem_enc_ioctl)(struct kvm_vcpu *vcpu, void __user *argp);
18511853
int (*mem_enc_register_region)(struct kvm *kvm, struct kvm_enc_region *argp);
18521854
int (*mem_enc_unregister_region)(struct kvm *kvm, struct kvm_enc_region *argp);
18531855
int (*vm_copy_enc_context_from)(struct kvm *kvm, unsigned int source_fd);

arch/x86/include/asm/shared/tdx.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@
7171
#define TDVMCALL_GET_QUOTE 0x10002
7272
#define TDVMCALL_REPORT_FATAL_ERROR 0x10003
7373

74-
#define TDVMCALL_STATUS_RETRY 1
74+
/*
75+
* TDG.VP.VMCALL Status Codes (returned in R10)
76+
*/
77+
#define TDVMCALL_STATUS_SUCCESS 0x0000000000000000ULL
78+
#define TDVMCALL_STATUS_RETRY 0x0000000000000001ULL
79+
#define TDVMCALL_STATUS_INVALID_OPERAND 0x8000000000000000ULL
7580

7681
/*
7782
* Bitmasks of exposed registers (with VMM).

arch/x86/include/asm/tdx.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <linux/init.h>
77
#include <linux/bits.h>
8+
#include <linux/mmzone.h>
89

910
#include <asm/errno.h>
1011
#include <asm/ptrace.h>
@@ -33,6 +34,8 @@
3334
#ifndef __ASSEMBLY__
3435

3536
#include <uapi/asm/mce.h>
37+
#include <asm/tdx_global_metadata.h>
38+
#include <linux/pgtable.h>
3639

3740
/*
3841
* Used by the #VE exception handler to gather the #VE exception
@@ -119,11 +122,68 @@ static inline u64 sc_retry(sc_func_t func, u64 fn,
119122
int tdx_cpu_enable(void);
120123
int tdx_enable(void);
121124
const char *tdx_dump_mce_info(struct mce *m);
125+
const struct tdx_sys_info *tdx_get_sysinfo(void);
126+
127+
int tdx_guest_keyid_alloc(void);
128+
u32 tdx_get_nr_guest_keyids(void);
129+
void tdx_guest_keyid_free(unsigned int keyid);
130+
131+
struct tdx_td {
132+
/* TD root structure: */
133+
struct page *tdr_page;
134+
135+
int tdcs_nr_pages;
136+
/* TD control structure: */
137+
struct page **tdcs_pages;
138+
139+
/* Size of `tdcx_pages` in struct tdx_vp */
140+
int tdcx_nr_pages;
141+
};
142+
143+
struct tdx_vp {
144+
/* TDVP root page */
145+
struct page *tdvpr_page;
146+
147+
/* TD vCPU control structure: */
148+
struct page **tdcx_pages;
149+
};
150+
151+
152+
static inline u64 mk_keyed_paddr(u16 hkid, struct page *page)
153+
{
154+
u64 ret;
155+
156+
ret = page_to_phys(page);
157+
/* KeyID bits are just above the physical address bits: */
158+
ret |= (u64)hkid << boot_cpu_data.x86_phys_bits;
159+
160+
return ret;
161+
162+
}
163+
164+
u64 tdh_mng_addcx(struct tdx_td *td, struct page *tdcs_page);
165+
u64 tdh_vp_addcx(struct tdx_vp *vp, struct page *tdcx_page);
166+
u64 tdh_mng_key_config(struct tdx_td *td);
167+
u64 tdh_mng_create(struct tdx_td *td, u16 hkid);
168+
u64 tdh_vp_create(struct tdx_td *td, struct tdx_vp *vp);
169+
u64 tdh_mng_rd(struct tdx_td *td, u64 field, u64 *data);
170+
u64 tdh_vp_flush(struct tdx_vp *vp);
171+
u64 tdh_mng_vpflushdone(struct tdx_td *td);
172+
u64 tdh_mng_key_freeid(struct tdx_td *td);
173+
u64 tdh_mng_init(struct tdx_td *td, u64 td_params, u64 *extended_err);
174+
u64 tdh_vp_init(struct tdx_vp *vp, u64 initial_rcx, u32 x2apicid);
175+
u64 tdh_vp_rd(struct tdx_vp *vp, u64 field, u64 *data);
176+
u64 tdh_vp_wr(struct tdx_vp *vp, u64 field, u64 data, u64 mask);
177+
u64 tdh_phymem_page_reclaim(struct page *page, u64 *tdx_pt, u64 *tdx_owner, u64 *tdx_size);
178+
u64 tdh_phymem_cache_wb(bool resume);
179+
u64 tdh_phymem_page_wbinvd_tdr(struct tdx_td *td);
122180
#else
123181
static inline void tdx_init(void) { }
124182
static inline int tdx_cpu_enable(void) { return -ENODEV; }
125183
static inline int tdx_enable(void) { return -ENODEV; }
184+
static inline u32 tdx_get_nr_guest_keyids(void) { return 0; }
126185
static inline const char *tdx_dump_mce_info(struct mce *m) { return NULL; }
186+
static inline const struct tdx_sys_info *tdx_get_sysinfo(void) { return NULL; }
127187
#endif /* CONFIG_INTEL_TDX_HOST */
128188

129189
#endif /* !__ASSEMBLY__ */

arch/x86/virt/vmx/tdx/tdx_global_metadata.h renamed to arch/x86/include/asm/tdx_global_metadata.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,28 @@ struct tdx_sys_info_tdmr {
1717
u16 pamt_1g_entry_size;
1818
};
1919

20+
struct tdx_sys_info_td_ctrl {
21+
u16 tdr_base_size;
22+
u16 tdcs_base_size;
23+
u16 tdvps_base_size;
24+
};
25+
26+
struct tdx_sys_info_td_conf {
27+
u64 attributes_fixed0;
28+
u64 attributes_fixed1;
29+
u64 xfam_fixed0;
30+
u64 xfam_fixed1;
31+
u16 num_cpuid_config;
32+
u16 max_vcpus_per_td;
33+
u64 cpuid_config_leaves[128];
34+
u64 cpuid_config_values[128][2];
35+
};
36+
2037
struct tdx_sys_info {
2138
struct tdx_sys_info_features features;
2239
struct tdx_sys_info_tdmr tdmr;
40+
struct tdx_sys_info_td_ctrl td_ctrl;
41+
struct tdx_sys_info_td_conf td_conf;
2342
};
2443

2544
#endif

arch/x86/include/uapi/asm/kvm.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,4 +927,64 @@ struct kvm_hyperv_eventfd {
927927
#define KVM_X86_SNP_VM 4
928928
#define KVM_X86_TDX_VM 5
929929

930+
/* Trust Domain eXtension sub-ioctl() commands. */
931+
enum kvm_tdx_cmd_id {
932+
KVM_TDX_CAPABILITIES = 0,
933+
KVM_TDX_INIT_VM,
934+
KVM_TDX_INIT_VCPU,
935+
KVM_TDX_GET_CPUID,
936+
937+
KVM_TDX_CMD_NR_MAX,
938+
};
939+
940+
struct kvm_tdx_cmd {
941+
/* enum kvm_tdx_cmd_id */
942+
__u32 id;
943+
/* flags for sub-commend. If sub-command doesn't use this, set zero. */
944+
__u32 flags;
945+
/*
946+
* data for each sub-command. An immediate or a pointer to the actual
947+
* data in process virtual address. If sub-command doesn't use it,
948+
* set zero.
949+
*/
950+
__u64 data;
951+
/*
952+
* Auxiliary error code. The sub-command may return TDX SEAMCALL
953+
* status code in addition to -Exxx.
954+
*/
955+
__u64 hw_error;
956+
};
957+
958+
struct kvm_tdx_capabilities {
959+
__u64 supported_attrs;
960+
__u64 supported_xfam;
961+
__u64 reserved[254];
962+
963+
/* Configurable CPUID bits for userspace */
964+
struct kvm_cpuid2 cpuid;
965+
};
966+
967+
struct kvm_tdx_init_vm {
968+
__u64 attributes;
969+
__u64 xfam;
970+
__u64 mrconfigid[6]; /* sha384 digest */
971+
__u64 mrowner[6]; /* sha384 digest */
972+
__u64 mrownerconfig[6]; /* sha384 digest */
973+
974+
/* The total space for TD_PARAMS before the CPUIDs is 256 bytes */
975+
__u64 reserved[12];
976+
977+
/*
978+
* Call KVM_TDX_INIT_VM before vcpu creation, thus before
979+
* KVM_SET_CPUID2.
980+
* This configuration supersedes KVM_SET_CPUID2s for VCPUs because the
981+
* TDX module directly virtualizes those CPUIDs without VMM. The user
982+
* space VMM, e.g. qemu, should make KVM_SET_CPUID2 consistent with
983+
* those values. If it doesn't, KVM may have wrong idea of vCPUIDs of
984+
* the guest, and KVM may wrongly emulate CPUIDs or MSRs that the TDX
985+
* module doesn't virtualize.
986+
*/
987+
struct kvm_cpuid2 cpuid;
988+
};
989+
930990
#endif /* _ASM_X86_KVM_H */

arch/x86/kvm/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ config KVM_SW_PROTECTED_VM
9494
config KVM_INTEL
9595
tristate "KVM for Intel (and compatible) processors support"
9696
depends on KVM && IA32_FEAT_CTL
97+
select KVM_GENERIC_PRIVATE_MEM if INTEL_TDX_HOST
98+
select KVM_GENERIC_MEMORY_ATTRIBUTES if INTEL_TDX_HOST
9799
help
98100
Provides support for KVM on processors equipped with Intel's VT
99101
extensions, a.k.a. Virtual Machine Extensions (VMX).
@@ -128,6 +130,16 @@ config X86_SGX_KVM
128130

129131
If unsure, say N.
130132

133+
config KVM_INTEL_TDX
134+
bool "Intel Trust Domain Extensions (TDX) support"
135+
default y
136+
depends on INTEL_TDX_HOST
137+
help
138+
Provides support for launching Intel Trust Domain Extensions (TDX)
139+
confidential VMs on Intel processors.
140+
141+
If unsure, say N.
142+
131143
config KVM_AMD
132144
tristate "KVM for AMD processors support"
133145
depends on KVM && (CPU_SUP_AMD || CPU_SUP_HYGON)

arch/x86/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
2020

2121
kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
2222
kvm-intel-$(CONFIG_KVM_HYPERV) += vmx/hyperv.o vmx/hyperv_evmcs.o
23+
kvm-intel-$(CONFIG_KVM_INTEL_TDX) += vmx/tdx.o
2324

2425
kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o
2526

arch/x86/kvm/cpuid.c

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,8 @@ u32 xstate_required_size(u64 xstate_bv, bool compacted)
8282
return ret;
8383
}
8484

85-
/*
86-
* Magic value used by KVM when querying userspace-provided CPUID entries and
87-
* doesn't care about the CPIUD index because the index of the function in
88-
* question is not significant. Note, this magic value must have at least one
89-
* bit set in bits[63:32] and must be consumed as a u64 by cpuid_entry2_find()
90-
* to avoid false positives when processing guest CPUID input.
91-
*/
92-
#define KVM_CPUID_INDEX_NOT_SIGNIFICANT -1ull
93-
94-
static struct kvm_cpuid_entry2 *cpuid_entry2_find(struct kvm_vcpu *vcpu,
95-
u32 function, u64 index)
85+
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry2(
86+
struct kvm_cpuid_entry2 *entries, int nent, u32 function, u64 index)
9687
{
9788
struct kvm_cpuid_entry2 *e;
9889
int i;
@@ -109,8 +100,8 @@ static struct kvm_cpuid_entry2 *cpuid_entry2_find(struct kvm_vcpu *vcpu,
109100
*/
110101
lockdep_assert_irqs_enabled();
111102

112-
for (i = 0; i < vcpu->arch.cpuid_nent; i++) {
113-
e = &vcpu->arch.cpuid_entries[i];
103+
for (i = 0; i < nent; i++) {
104+
e = &entries[i];
114105

115106
if (e->function != function)
116107
continue;
@@ -141,26 +132,7 @@ static struct kvm_cpuid_entry2 *cpuid_entry2_find(struct kvm_vcpu *vcpu,
141132

142133
return NULL;
143134
}
144-
145-
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry_index(struct kvm_vcpu *vcpu,
146-
u32 function, u32 index)
147-
{
148-
return cpuid_entry2_find(vcpu, function, index);
149-
}
150-
EXPORT_SYMBOL_GPL(kvm_find_cpuid_entry_index);
151-
152-
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
153-
u32 function)
154-
{
155-
return cpuid_entry2_find(vcpu, function, KVM_CPUID_INDEX_NOT_SIGNIFICANT);
156-
}
157-
EXPORT_SYMBOL_GPL(kvm_find_cpuid_entry);
158-
159-
/*
160-
* cpuid_entry2_find() and KVM_CPUID_INDEX_NOT_SIGNIFICANT should never be used
161-
* directly outside of kvm_find_cpuid_entry() and kvm_find_cpuid_entry_index().
162-
*/
163-
#undef KVM_CPUID_INDEX_NOT_SIGNIFICANT
135+
EXPORT_SYMBOL_GPL(kvm_find_cpuid_entry2);
164136

165137
static int kvm_check_cpuid(struct kvm_vcpu *vcpu)
166138
{
@@ -491,6 +463,20 @@ int cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu)
491463
return 36;
492464
}
493465

466+
int cpuid_query_maxguestphyaddr(struct kvm_vcpu *vcpu)
467+
{
468+
struct kvm_cpuid_entry2 *best;
469+
470+
best = kvm_find_cpuid_entry(vcpu, 0x80000000);
471+
if (!best || best->eax < 0x80000008)
472+
goto not_found;
473+
best = kvm_find_cpuid_entry(vcpu, 0x80000008);
474+
if (best)
475+
return (best->eax >> 16) & 0xff;
476+
not_found:
477+
return 0;
478+
}
479+
494480
/*
495481
* This "raw" version returns the reserved GPA bits without any adjustments for
496482
* encryption technologies that usurp bits. The raw mask should be used if and

arch/x86/kvm/cpuid.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,34 @@ void kvm_set_cpu_caps(void);
1212

1313
void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu);
1414
void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu);
15-
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry_index(struct kvm_vcpu *vcpu,
16-
u32 function, u32 index);
17-
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
18-
u32 function);
15+
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry2(struct kvm_cpuid_entry2 *entries,
16+
int nent, u32 function, u64 index);
17+
/*
18+
* Magic value used by KVM when querying userspace-provided CPUID entries and
19+
* doesn't care about the CPIUD index because the index of the function in
20+
* question is not significant. Note, this magic value must have at least one
21+
* bit set in bits[63:32] and must be consumed as a u64 by kvm_find_cpuid_entry2()
22+
* to avoid false positives when processing guest CPUID input.
23+
*
24+
* KVM_CPUID_INDEX_NOT_SIGNIFICANT should never be used directly outside of
25+
* kvm_find_cpuid_entry2() and kvm_find_cpuid_entry().
26+
*/
27+
#define KVM_CPUID_INDEX_NOT_SIGNIFICANT -1ull
28+
29+
static inline struct kvm_cpuid_entry2 *kvm_find_cpuid_entry_index(struct kvm_vcpu *vcpu,
30+
u32 function, u32 index)
31+
{
32+
return kvm_find_cpuid_entry2(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent,
33+
function, index);
34+
}
35+
36+
static inline struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
37+
u32 function)
38+
{
39+
return kvm_find_cpuid_entry2(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent,
40+
function, KVM_CPUID_INDEX_NOT_SIGNIFICANT);
41+
}
42+
1943
int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid,
2044
struct kvm_cpuid_entry2 __user *entries,
2145
unsigned int type);
@@ -35,6 +59,7 @@ void __init kvm_init_xstate_sizes(void);
3559
u32 xstate_required_size(u64 xstate_bv, bool compacted);
3660

3761
int cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu);
62+
int cpuid_query_maxguestphyaddr(struct kvm_vcpu *vcpu);
3863
u64 kvm_vcpu_reserved_gpa_bits_raw(struct kvm_vcpu *vcpu);
3964

4065
static inline int cpuid_maxphyaddr(struct kvm_vcpu *vcpu)

0 commit comments

Comments
 (0)