@@ -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);
@@ -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();
@@ -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,
@@ -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)
@@ -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,
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@linux.intel.com> --- 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(-)