[PATCH 05/10] kvm: x86: add KVM_GET_SUPPORTED_CPUID SGX support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux