From: Xiaoyao Li <xiaoyao.li@xxxxxxxxx> While TDX module reports a set of capabilities/features that it supports, what KVM currently supports might be a subset of them. E.g., DEBUG and PERFMON are supported by TDX module but currently not supported by KVM. Introduce a new struct kvm_tdx_caps to store KVM's capabilities of TDX. supported_attrs and suppported_xfam are validated against fixed0/1 values enumerated by TDX module. Configurable CPUID bits derive from TDX module plus applying KVM's capabilities (KVM_GET_SUPPORTED_CPUID), i.e., mask off the bits that are configurable in the view of TDX module but not supported by KVM yet. KVM_TDX_CPUID_NO_SUBLEAF is the concept from TDX module, switch it to 0 and use KVM_CPUID_FLAG_SIGNIFCANT_INDEX, which are the concept of KVM. Signed-off-by: Xiaoyao Li <xiaoyao.li@xxxxxxxxx> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@xxxxxxxxx> --- uAPI breakout v1: - Change setup_kvm_tdx_caps() to use the exported 'struct tdx_sysinfo' pointer. - Change how to copy 'kvm_tdx_cpuid_config' since 'struct tdx_sysinfo' doesn't have 'kvm_tdx_cpuid_config'. - Updates for uAPI changes --- arch/x86/include/uapi/asm/kvm.h | 2 - arch/x86/kvm/vmx/tdx.c | 81 +++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 47caf508cca7..c9eb2e2f5559 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -952,8 +952,6 @@ struct kvm_tdx_cmd { __u64 hw_error; }; -#define KVM_TDX_CPUID_NO_SUBLEAF ((__u32)-1) - struct kvm_tdx_cpuid_config { __u32 leaf; __u32 sub_leaf; diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 90b44ebaf864..d89973e554f6 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -31,6 +31,19 @@ static void __used tdx_guest_keyid_free(int keyid) ida_free(&tdx_guest_keyid_pool, keyid); } +#define KVM_TDX_CPUID_NO_SUBLEAF ((__u32)-1) + +struct kvm_tdx_caps { + u64 supported_attrs; + u64 supported_xfam; + + u16 num_cpuid_config; + /* This must the last member. */ + DECLARE_FLEX_ARRAY(struct kvm_tdx_cpuid_config, cpuid_configs); +}; + +static struct kvm_tdx_caps *kvm_tdx_caps; + static int tdx_get_capabilities(struct kvm_tdx_cmd *cmd) { const struct tdx_sysinfo_td_conf *td_conf = &tdx_sysinfo->td_conf; @@ -131,6 +144,68 @@ int tdx_vm_ioctl(struct kvm *kvm, void __user *argp) return r; } +#define KVM_SUPPORTED_TD_ATTRS (TDX_TD_ATTR_SEPT_VE_DISABLE) + +static int __init setup_kvm_tdx_caps(void) +{ + const struct tdx_sysinfo_td_conf *td_conf = &tdx_sysinfo->td_conf; + u64 kvm_supported; + int i; + + kvm_tdx_caps = kzalloc(sizeof(*kvm_tdx_caps) + + sizeof(struct kvm_tdx_cpuid_config) * td_conf->num_cpuid_config, + GFP_KERNEL); + if (!kvm_tdx_caps) + return -ENOMEM; + + kvm_supported = KVM_SUPPORTED_TD_ATTRS; + if ((kvm_supported & td_conf->attributes_fixed1) != td_conf->attributes_fixed1) + goto err; + + kvm_tdx_caps->supported_attrs = kvm_supported & td_conf->attributes_fixed0; + + kvm_supported = kvm_caps.supported_xcr0 | kvm_caps.supported_xss; + + /* + * PT and CET can be exposed to TD guest regardless of KVM's XSS, PT + * and, CET support. + */ + kvm_supported |= XFEATURE_MASK_PT | XFEATURE_MASK_CET_USER | + XFEATURE_MASK_CET_KERNEL; + if ((kvm_supported & td_conf->xfam_fixed1) != td_conf->xfam_fixed1) + goto err; + + kvm_tdx_caps->supported_xfam = kvm_supported & td_conf->xfam_fixed0; + + kvm_tdx_caps->num_cpuid_config = td_conf->num_cpuid_config; + for (i = 0; i < td_conf->num_cpuid_config; i++) { + struct kvm_tdx_cpuid_config source = { + .leaf = (u32)td_conf->cpuid_config_leaves[i], + .sub_leaf = td_conf->cpuid_config_leaves[i] >> 32, + .eax = (u32)td_conf->cpuid_config_values[i].eax_ebx, + .ebx = td_conf->cpuid_config_values[i].eax_ebx >> 32, + .ecx = (u32)td_conf->cpuid_config_values[i].ecx_edx, + .edx = td_conf->cpuid_config_values[i].ecx_edx >> 32, + }; + struct kvm_tdx_cpuid_config *dest = + &kvm_tdx_caps->cpuid_configs[i]; + + memcpy(dest, &source, sizeof(struct kvm_tdx_cpuid_config)); + if (dest->sub_leaf == KVM_TDX_CPUID_NO_SUBLEAF) + dest->sub_leaf = 0; + } + + return 0; +err: + kfree(kvm_tdx_caps); + return -EIO; +} + +static void free_kvm_tdx_cap(void) +{ + kfree(kvm_tdx_caps); +} + static int tdx_online_cpu(unsigned int cpu) { unsigned long flags; @@ -217,11 +292,16 @@ static int __init __tdx_bringup(void) goto get_sysinfo_err; } + r = setup_kvm_tdx_caps(); + if (r) + goto get_sysinfo_err; + /* * Leave hardware virtualization enabled after TDX is enabled * successfully. TDX CPU hotplug depends on this. */ return 0; + get_sysinfo_err: __do_tdx_cleanup(); tdx_bringup_err: @@ -232,6 +312,7 @@ static int __init __tdx_bringup(void) void tdx_cleanup(void) { if (enable_tdx) { + free_kvm_tdx_cap(); __do_tdx_cleanup(); kvm_disable_virtualization(); } -- 2.34.1