This patch adds SGX CPUID support for KVM_GET_SUPPORTED_CPUID IOCTL. We need to only expose SGX CPUID when enable_sgx is valid, as enable_sgx may be false, for example, when user deliberately disables SGX, or when SGX initialization fails, in which case hardware will still reports valid SGX CPUID. As enable_sgx is not exposed to arch/x86/kvm/cpuid.c, we need to do SGX related CPUID in vmx.c, for which kvm_x86_ops->set_supported_cpuid is extended to meet SGX's need, and do_cpuid_1_ent is also exposed to VMX. Signed-off-by: Kai Huang <kai.huang@xxxxxxxxxxxxxxx> --- arch/x86/include/asm/kvm_host.h | 3 +- arch/x86/kvm/cpuid.c | 13 ++++---- arch/x86/kvm/cpuid.h | 2 ++ arch/x86/kvm/svm.c | 5 ++- arch/x86/kvm/vmx.c | 71 +++++++++++++++++++++++++++++++++++++++-- 5 files changed, 83 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 1d622334fc0e..d7254f36b17d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -978,7 +978,8 @@ struct kvm_x86_ops { void (*set_tdp_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); - void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry); + int (*set_supported_cpuid)(u32 func, u32 index, + struct kvm_cpuid_entry2 *entry, int *nent, int maxnent); bool (*has_wbinvd_exit)(void); diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index efde6cc50875..d2c396b0b32f 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -274,7 +274,7 @@ static void cpuid_mask(u32 *word, int wordnum) *word &= boot_cpu_data.x86_capability[wordnum]; } -static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function, +void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function, u32 index) { entry->function = function; @@ -283,6 +283,7 @@ static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function, &entry->eax, &entry->ebx, &entry->ecx, &entry->edx); entry->flags = 0; } +EXPORT_SYMBOL_GPL(do_cpuid_1_ent); static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry, u32 func, u32 index, int *nent, int maxnent) @@ -402,7 +403,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, switch (function) { case 0: - entry->eax = min(entry->eax, (u32)0xd); + entry->eax = min(entry->eax, (u32)0x12); break; case 1: entry->edx &= kvm_cpuid_1_edx_x86_features; @@ -573,6 +574,9 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, } break; } + case 0x12: + /* Intel SGX CPUID. Passthrough to VMX to handle. */ + break; case KVM_CPUID_SIGNATURE: { static const char signature[12] = "KVMKVMKVM\0\0"; const u32 *sigptr = (const u32 *)signature; @@ -651,10 +655,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, break; } - kvm_x86_ops->set_supported_cpuid(function, entry); - - r = 0; - + r = kvm_x86_ops->set_supported_cpuid(function, index, entry, nent, maxnent); out: put_cpu(); diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 35058c2c0eea..de658f4fa1c6 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -6,6 +6,8 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu); bool kvm_mpx_supported(void); +void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function, + u32 index); struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, u32 function, u32 index); int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid, diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 5fba70646c32..678b30d2a188 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -4988,7 +4988,8 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu) entry->ecx &= ~bit(X86_FEATURE_X2APIC); } -static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) +static int svm_set_supported_cpuid(u32 func, u32 index, + struct kvm_cpuid_entry2 *entry, int *nent, int maxnent) { switch (func) { case 0x1: @@ -5017,6 +5018,8 @@ static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) break; } + + return 0; } static int svm_get_lpage_level(void) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 4b368a0af9bd..31de95986dbd 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -9493,10 +9493,75 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu) nested_vmx_cr_fixed1_bits_update(vcpu); } -static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) +static int vmx_set_supported_cpuid(u32 func, u32 index, + struct kvm_cpuid_entry2 *entry, int *nent, int maxnent) { - if (func == 1 && nested) - entry->ecx |= bit(X86_FEATURE_VMX); + int r = -E2BIG; + + switch (func) { + case 0x1: + if (nested) + entry->ecx |= bit(X86_FEATURE_VMX); + break; + case 0x7: + if (index == 0 && enable_sgx) { + entry->ebx |= bit(X86_FEATURE_SGX); + if (boot_cpu_has(X86_FEATURE_SGX_LAUNCH_CONTROL)) + entry->ecx |= + bit(X86_FEATURE_SGX_LAUNCH_CONTROL); + } + break; + case 0x12: { + WARN_ON(index != 0); + + if (enable_sgx) { + if (*nent >= maxnent) + goto out; + + /* do_cpuid_1_ent has already been called for index 0 */ + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + + /* Index 1: SECS.ATTRIBUTE */ + do_cpuid_1_ent(++entry, 0x12, 0x1); + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + ++*nent; + + if (*nent >= maxnent) + goto out; + + /* + * Index 2: EPC section + * + * Note: We only report one EPC section as userspace + * doesn't need to know physical EPC info. In fact, + * KVM_SET_CPUID2 should contain guest's virtual EPC + * base & size, in which case one virtual EPC section + * is obviously enough for guest. + */ + do_cpuid_1_ent(++entry, 0x12, 0x2); + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + /* + * Don't report physical EPC info as userspace doesn't + * need to know. + */ + entry->eax &= 0xf; + entry->ebx = 0; + entry->ecx &= 0xf; + entry->edx = 0; + ++*nent; + } + else + entry->eax = entry->ebx = entry->ecx = entry->edx = 0; + + break; + } + default: + break; + } + + r = 0; +out: + return r; } static void nested_ept_inject_page_fault(struct kvm_vcpu *vcpu, -- 2.11.0