[intel-sgx-kernel-dev] intel_isgx: adding multiple EPC support
diff mbox

Message ID 1495799473-3053-1-git-send-email-serge.ayoun@intel.com
State New
Headers show

Commit Message

Ayoun, Serge May 26, 2017, 11:51 a.m. UTC
For systems with multiple EPC regions cpuidid leaf 18 sub leaf 3, 4,...
describes those regions.
At driver initialization time, cpuid leaf 18 subleaf 2 and beyond
are invoked in order to enumerate those different EPC chunks and
until valid bit is not set.
Epc pages are inserted to the free list accordingly.

Signed-off-by: Serge Ayoun <serge.ayoun@intel.com>
---
 drivers/platform/x86/intel_sgx.h      | 13 ++++--
 drivers/platform/x86/intel_sgx_main.c | 83 +++++++++++++++++++++++------------
 drivers/platform/x86/intel_sgx_util.c | 12 ++++-
 3 files changed, 74 insertions(+), 34 deletions(-)

Patch
diff mbox

diff --git a/drivers/platform/x86/intel_sgx.h b/drivers/platform/x86/intel_sgx.h
index ed9e8e6..6b0c043 100644
--- a/drivers/platform/x86/intel_sgx.h
+++ b/drivers/platform/x86/intel_sgx.h
@@ -155,12 +155,17 @@  struct sgx_encl {
 	struct mmu_notifier mmu_notifier;
 };
 
-extern struct workqueue_struct *sgx_add_page_wq;
-extern unsigned long sgx_epc_base;
-extern unsigned long sgx_epc_size;
+struct sgx_epc_bank {
 #ifdef CONFIG_X86_64
-extern void *sgx_epc_mem;
+	void *mem;
 #endif
+	unsigned long start;
+	unsigned long end;
+};
+
+extern struct workqueue_struct *sgx_add_page_wq;
+extern struct sgx_epc_bank sgx_epcs[];
+extern int sgx_num_epc;
 extern u64 sgx_encl_size_max_32;
 extern u64 sgx_encl_size_max_64;
 extern u64 sgx_xfrm_mask;
diff --git a/drivers/platform/x86/intel_sgx_main.c b/drivers/platform/x86/intel_sgx_main.c
index 63cca6a..ed136db 100644
--- a/drivers/platform/x86/intel_sgx_main.c
+++ b/drivers/platform/x86/intel_sgx_main.c
@@ -83,11 +83,9 @@ 
  */
 
 struct workqueue_struct *sgx_add_page_wq;
-unsigned long sgx_epc_base;
-unsigned long sgx_epc_size;
-#ifdef CONFIG_X86_64
-void *sgx_epc_mem;
-#endif
+#define MAX_EPCS 8
+struct sgx_epc_bank sgx_epcs[MAX_EPCS];
+int sgx_num_epc;
 u64 sgx_encl_size_max_32 = ENCL_SIZE_MAX_32;
 u64 sgx_encl_size_max_64 = ENCL_SIZE_MAX_64;
 u64 sgx_xfrm_mask = 0x3;
@@ -164,7 +162,8 @@  static unsigned long sgx_get_unmapped_area(struct file *file,
 static int sgx_init_platform(void)
 {
 	unsigned int eax, ebx, ecx, edx;
-	int i;
+	unsigned long size;
+	int i, leaf;
 
 	cpuid(0, &eax, &ebx, &ecx, &edx);
 	if (eax < SGX_CPUID) {
@@ -203,19 +202,32 @@  static int sgx_init_platform(void)
 		sgx_encl_size_max_32 = 1ULL << ((edx >> 8) & 0xFF);
 	}
 
-	cpuid_count(SGX_CPUID, 0x2, &eax, &ebx, &ecx, &edx);
-
-	/* The should be at least one EPC area or something is wrong. */
-	if ((eax & 0xf) != 0x1)
-		return -ENODEV;
-
-	sgx_epc_base = (((u64)(ebx & 0xfffff)) << 32) +
-		(u64)(eax & 0xfffff000);
-	sgx_epc_size = (((u64)(edx & 0xfffff)) << 32) +
-		(u64)(ecx & 0xfffff000);
+	leaf = 2;
+	sgx_num_epc = 0;
+	do {
+		cpuid_count(SGX_CPUID, leaf, &eax, &ebx, &ecx, &edx);
+		if (eax & 0xf) {
+			sgx_epcs[sgx_num_epc].start =
+				(((u64) (ebx & 0xfffff)) << 32) +
+				(u64) (eax & 0xfffff000);
+			size = (((u64) (edx & 0xfffff)) << 32) +
+				(u64) (ecx & 0xfffff000);
+			sgx_epcs[sgx_num_epc].end =
+				sgx_epcs[sgx_num_epc].start + size;
+			if (!sgx_epcs[sgx_num_epc].start)
+				return -ENODEV;
+			sgx_num_epc++;
+			leaf++;
+		} else {
+			break;
+		}
+	} while (sgx_num_epc < MAX_EPCS);
 
-	if (!sgx_epc_base)
+	/* There should be at least one EPC area or something is wrong. */
+	if (!sgx_num_epc) {
+		WARN();
 		return -ENODEV;
+	}
 
 	return 0;
 }
@@ -250,7 +262,7 @@  static int sgx_pm_resume(struct device *dev)
 static int sgx_dev_init(struct device *dev)
 {
 	unsigned int wq_flags;
-	int ret;
+	int ret, i;
 
 	pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n");
 
@@ -261,18 +273,27 @@  static int sgx_dev_init(struct device *dev)
 	if (ret)
 		return ret;
 
-	pr_info("intel_sgx: EPC memory range 0x%lx-0x%lx\n", sgx_epc_base,
-		sgx_epc_base + sgx_epc_size);
+	pr_info("intel_sgx: Number of EPCs %d\n", sgx_num_epc);
 
+	for (i = 0; i < sgx_num_epc; i++) {
+		pr_info("intel_sgx: EPC memory range 0x%lx-0x%lx\n",
+			sgx_epcs[i].start, sgx_epcs[i].end);
 #ifdef CONFIG_X86_64
-	sgx_epc_mem = ioremap_cache(sgx_epc_base, sgx_epc_size);
-	if (!sgx_epc_mem)
-		return -ENOMEM;
+		sgx_epcs[i].mem = ioremap_cache(sgx_epcs[i].start,
+					sgx_epcs[i].end - sgx_epcs[i].start);
+		if (!sgx_epcs[i].mem) {
+			sgx_num_epc = i;
+			ret = -ENOMEM;
+			goto out_iounmap;
+		}
 #endif
-
-	ret = sgx_page_cache_init(sgx_epc_base, sgx_epc_size);
-	if (ret)
-		goto out_iounmap;
+		ret = sgx_page_cache_init(sgx_epcs[i].start,
+			sgx_epcs[i].end - sgx_epcs[i].start);
+		if (ret) {
+			sgx_num_epc = i+1;
+			goto out_iounmap;
+		}
+	}
 
 	wq_flags = WQ_UNBOUND | WQ_FREEZABLE;
 #ifdef WQ_NON_REENETRANT
@@ -297,7 +318,8 @@  static int sgx_dev_init(struct device *dev)
 	destroy_workqueue(sgx_add_page_wq);
 out_iounmap:
 #ifdef CONFIG_X86_64
-	iounmap(sgx_epc_mem);
+	for (i = 0; i < sgx_num_epc; i++)
+		iounmap(sgx_epcs[i].mem);
 #endif
 	return ret;
 }
@@ -352,10 +374,13 @@  static int sgx_drv_probe(struct platform_device *pdev)
 
 static int sgx_drv_remove(struct platform_device *pdev)
 {
+	int i;
+
 	misc_deregister(&sgx_dev);
 	destroy_workqueue(sgx_add_page_wq);
 #ifdef CONFIG_X86_64
-	iounmap(sgx_epc_mem);
+	for (i = 0; i < sgx_num_epc; i++)
+		iounmap(sgx_epcs[i].mem);
 #endif
 	sgx_page_cache_teardown();
 
diff --git a/drivers/platform/x86/intel_sgx_util.c b/drivers/platform/x86/intel_sgx_util.c
index 2c390c5..b921fa7 100644
--- a/drivers/platform/x86/intel_sgx_util.c
+++ b/drivers/platform/x86/intel_sgx_util.c
@@ -66,7 +66,17 @@  void *sgx_get_epc_page(struct sgx_epc_page *entry)
 #ifdef CONFIG_X86_32
 	return kmap_atomic_pfn(PFN_DOWN(entry->pa));
 #else
-	return sgx_epc_mem + (entry->pa - sgx_epc_base);
+	int i;
+
+	for (i = 0; i < sgx_num_epc; i++) {
+		if (entry->pa < sgx_epcs[i].end &&
+		    entry->pa >= sgx_epcs[i].start) {
+			return sgx_epcs[i].mem +
+				(entry->pa - sgx_epcs[i].start);
+		}
+	}
+
+	return NULL;
 #endif
 }