@@ -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;
@@ -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();
@@ -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
}
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(-)