Skip to content

Commit 61bb282

Browse files
yamahatabonzini
authored andcommitted
KVM: TDX: Get system-wide info about TDX module on initialization
TDX KVM needs system-wide information about the TDX module. Generate the data based on tdx_sysinfo td_conf CPUID data. Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com> Co-developed-by: Xiaoyao Li <xiaoyao.li@intel.com> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com> Co-developed-by: Tony Lindgren <tony.lindgren@linux.intel.com> Signed-off-by: Tony Lindgren <tony.lindgren@linux.intel.com> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com> --- - Clarify comment about EAX[23:16] in td_init_cpuid_entry2() (Xiaoyao) - Add comment for configurable CPUID bits (Xiaoyao) Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent b2aaf38 commit 61bb282

File tree

3 files changed

+150
-0
lines changed

3 files changed

+150
-0
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,8 @@ struct kvm_hyperv_eventfd {
929929

930930
/* Trust Domain eXtension sub-ioctl() commands. */
931931
enum kvm_tdx_cmd_id {
932+
KVM_TDX_CAPABILITIES = 0,
933+
932934
KVM_TDX_CMD_NR_MAX,
933935
};
934936

@@ -950,4 +952,13 @@ struct kvm_tdx_cmd {
950952
__u64 hw_error;
951953
};
952954

955+
struct kvm_tdx_capabilities {
956+
__u64 supported_attrs;
957+
__u64 supported_xfam;
958+
__u64 reserved[254];
959+
960+
/* Configurable CPUID bits for userspace */
961+
struct kvm_cpuid2 cpuid;
962+
};
963+
953964
#endif /* _ASM_X86_KVM_H */

arch/x86/kvm/vmx/tdx.c

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ static enum cpuhp_state tdx_cpuhp_state;
3333

3434
static const struct tdx_sys_info *tdx_sysinfo;
3535

36+
#define KVM_SUPPORTED_TD_ATTRS (TDX_TD_ATTR_SEPT_VE_DISABLE)
37+
3638
static __always_inline struct kvm_tdx *to_kvm_tdx(struct kvm *kvm)
3739
{
3840
return container_of(kvm, struct kvm_tdx, kvm);
@@ -43,6 +45,129 @@ static __always_inline struct vcpu_tdx *to_tdx(struct kvm_vcpu *vcpu)
4345
return container_of(vcpu, struct vcpu_tdx, vcpu);
4446
}
4547

48+
static u64 tdx_get_supported_attrs(const struct tdx_sys_info_td_conf *td_conf)
49+
{
50+
u64 val = KVM_SUPPORTED_TD_ATTRS;
51+
52+
if ((val & td_conf->attributes_fixed1) != td_conf->attributes_fixed1)
53+
return 0;
54+
55+
val &= td_conf->attributes_fixed0;
56+
57+
return val;
58+
}
59+
60+
static u64 tdx_get_supported_xfam(const struct tdx_sys_info_td_conf *td_conf)
61+
{
62+
u64 val = kvm_caps.supported_xcr0 | kvm_caps.supported_xss;
63+
64+
if ((val & td_conf->xfam_fixed1) != td_conf->xfam_fixed1)
65+
return 0;
66+
67+
val &= td_conf->xfam_fixed0;
68+
69+
return val;
70+
}
71+
72+
static u32 tdx_set_guest_phys_addr_bits(const u32 eax, int addr_bits)
73+
{
74+
return (eax & ~GENMASK(23, 16)) | (addr_bits & 0xff) << 16;
75+
}
76+
77+
#define KVM_TDX_CPUID_NO_SUBLEAF ((__u32)-1)
78+
79+
static void td_init_cpuid_entry2(struct kvm_cpuid_entry2 *entry, unsigned char idx)
80+
{
81+
const struct tdx_sys_info_td_conf *td_conf = &tdx_sysinfo->td_conf;
82+
83+
entry->function = (u32)td_conf->cpuid_config_leaves[idx];
84+
entry->index = td_conf->cpuid_config_leaves[idx] >> 32;
85+
entry->eax = (u32)td_conf->cpuid_config_values[idx][0];
86+
entry->ebx = td_conf->cpuid_config_values[idx][0] >> 32;
87+
entry->ecx = (u32)td_conf->cpuid_config_values[idx][1];
88+
entry->edx = td_conf->cpuid_config_values[idx][1] >> 32;
89+
90+
if (entry->index == KVM_TDX_CPUID_NO_SUBLEAF)
91+
entry->index = 0;
92+
93+
/*
94+
* The TDX module doesn't allow configuring the guest phys addr bits
95+
* (EAX[23:16]). However, KVM uses it as an interface to the userspace
96+
* to configure the GPAW. Report these bits as configurable.
97+
*/
98+
if (entry->function == 0x80000008)
99+
entry->eax = tdx_set_guest_phys_addr_bits(entry->eax, 0xff);
100+
}
101+
102+
static int init_kvm_tdx_caps(const struct tdx_sys_info_td_conf *td_conf,
103+
struct kvm_tdx_capabilities *caps)
104+
{
105+
int i;
106+
107+
caps->supported_attrs = tdx_get_supported_attrs(td_conf);
108+
if (!caps->supported_attrs)
109+
return -EIO;
110+
111+
caps->supported_xfam = tdx_get_supported_xfam(td_conf);
112+
if (!caps->supported_xfam)
113+
return -EIO;
114+
115+
caps->cpuid.nent = td_conf->num_cpuid_config;
116+
117+
for (i = 0; i < td_conf->num_cpuid_config; i++)
118+
td_init_cpuid_entry2(&caps->cpuid.entries[i], i);
119+
120+
return 0;
121+
}
122+
123+
static int tdx_get_capabilities(struct kvm_tdx_cmd *cmd)
124+
{
125+
const struct tdx_sys_info_td_conf *td_conf = &tdx_sysinfo->td_conf;
126+
struct kvm_tdx_capabilities __user *user_caps;
127+
struct kvm_tdx_capabilities *caps = NULL;
128+
int ret = 0;
129+
130+
/* flags is reserved for future use */
131+
if (cmd->flags)
132+
return -EINVAL;
133+
134+
caps = kmalloc(sizeof(*caps) +
135+
sizeof(struct kvm_cpuid_entry2) * td_conf->num_cpuid_config,
136+
GFP_KERNEL);
137+
if (!caps)
138+
return -ENOMEM;
139+
140+
user_caps = u64_to_user_ptr(cmd->data);
141+
if (copy_from_user(caps, user_caps, sizeof(*caps))) {
142+
ret = -EFAULT;
143+
goto out;
144+
}
145+
146+
if (caps->cpuid.nent < td_conf->num_cpuid_config) {
147+
ret = -E2BIG;
148+
goto out;
149+
}
150+
151+
ret = init_kvm_tdx_caps(td_conf, caps);
152+
if (ret)
153+
goto out;
154+
155+
if (copy_to_user(user_caps, caps, sizeof(*caps))) {
156+
ret = -EFAULT;
157+
goto out;
158+
}
159+
160+
if (copy_to_user(user_caps->cpuid.entries, caps->cpuid.entries,
161+
caps->cpuid.nent *
162+
sizeof(caps->cpuid.entries[0])))
163+
ret = -EFAULT;
164+
165+
out:
166+
/* kfree() accepts NULL. */
167+
kfree(caps);
168+
return ret;
169+
}
170+
46171
int tdx_vm_ioctl(struct kvm *kvm, void __user *argp)
47172
{
48173
struct kvm_tdx_cmd tdx_cmd;
@@ -61,6 +186,9 @@ int tdx_vm_ioctl(struct kvm *kvm, void __user *argp)
61186
mutex_lock(&kvm->lock);
62187

63188
switch (tdx_cmd.id) {
189+
case KVM_TDX_CAPABILITIES:
190+
r = tdx_get_capabilities(&tdx_cmd);
191+
break;
64192
default:
65193
r = -EINVAL;
66194
goto out;
@@ -160,11 +288,20 @@ static int __init __tdx_bringup(void)
160288
goto get_sysinfo_err;
161289
}
162290

291+
/* Check TDX module and KVM capabilities */
292+
if (!tdx_get_supported_attrs(&tdx_sysinfo->td_conf) ||
293+
!tdx_get_supported_xfam(&tdx_sysinfo->td_conf))
294+
goto get_sysinfo_err;
295+
296+
if (!(tdx_sysinfo->features.tdx_features0 & MD_FIELD_ID_FEATURES0_TOPOLOGY_ENUM))
297+
goto get_sysinfo_err;
298+
163299
/*
164300
* Leave hardware virtualization enabled after TDX is enabled
165301
* successfully. TDX CPU hotplug depends on this.
166302
*/
167303
return 0;
304+
168305
get_sysinfo_err:
169306
__tdx_cleanup();
170307
tdx_bringup_err:

arch/x86/kvm/vmx/tdx_arch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,6 @@ struct td_params {
121121
#define TDX_MIN_TSC_FREQUENCY_KHZ (100 * 1000)
122122
#define TDX_MAX_TSC_FREQUENCY_KHZ (10 * 1000 * 1000)
123123

124+
#define MD_FIELD_ID_FEATURES0_TOPOLOGY_ENUM BIT_ULL(20)
125+
124126
#endif /* __KVM_X86_TDX_ARCH_H */

0 commit comments

Comments
 (0)