[intel-sgx-kernel-dev,v2,3/4] intel_sgx: combine epc_page and va_page into union
diff mbox

Message ID 1492704977-26510-4-git-send-email-sean.j.christopherson@intel.com
State New
Headers show

Commit Message

Sean Christopherson April 20, 2017, 4:16 p.m. UTC
Combine sgx_encl_page's epc_page and va_page into a union.  On-demand
VA slot/page allocations guarantees only one of epc_page or va_page
will be valid at any given time.

Add a new flag, SGX_ENCL_PAGE_EPC_VALID, to track if an encl page has
been loaded into the EPC.  If SGX_ENCL_PAGE_EPC_VALID is set, then the
epc_page member of the epc_page/va_page union is valid, otherwise
va_page *may* be valid, e.g. neither is valid if EADD has not been
completed.

Move the functionality of sgx_evict_page into the success path of
EWB, as the EPC page must be freed before updating the encl_page's
va_page.

Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
 drivers/platform/x86/intel_sgx/sgx.h            |  9 ++++++---
 drivers/platform/x86/intel_sgx/sgx_ioctl.c      |  2 ++
 drivers/platform/x86/intel_sgx/sgx_page_cache.c | 11 ++++++-----
 drivers/platform/x86/intel_sgx/sgx_util.c       | 11 +++++------
 4 files changed, 19 insertions(+), 14 deletions(-)

Patch
diff mbox

diff --git a/drivers/platform/x86/intel_sgx/sgx.h b/drivers/platform/x86/intel_sgx/sgx.h
index 958e37d..bd22554 100644
--- a/drivers/platform/x86/intel_sgx/sgx.h
+++ b/drivers/platform/x86/intel_sgx/sgx.h
@@ -91,15 +91,18 @@  static inline void sgx_free_va_slot(struct sgx_va_page *page,
 enum sgx_encl_page_flags {
 	SGX_ENCL_PAGE_TCS	= BIT(0),
 	SGX_ENCL_PAGE_RESERVED	= BIT(1),
+	SGX_ENCL_PAGE_EPC_VALID	= BIT(2),
 };
 
 struct sgx_encl_page {
 	unsigned long addr;
 	unsigned int flags;
-	struct sgx_epc_page *epc_page;
-	struct list_head load_list;
-	struct sgx_va_page *va_page;
 	unsigned int va_offset;
+	union {
+		struct sgx_epc_page *epc_page;
+		struct sgx_va_page *va_page;
+	};
+	struct list_head load_list;
 };
 
 struct sgx_tgid_ctx {
diff --git a/drivers/platform/x86/intel_sgx/sgx_ioctl.c b/drivers/platform/x86/intel_sgx/sgx_ioctl.c
index af80571..6719e56 100644
--- a/drivers/platform/x86/intel_sgx/sgx_ioctl.c
+++ b/drivers/platform/x86/intel_sgx/sgx_ioctl.c
@@ -267,6 +267,7 @@  static bool sgx_process_add_page_req(struct sgx_add_page_req *req)
 		goto out;
 	}
 
+	encl_page->flags |= SGX_ENCL_PAGE_EPC_VALID;
 	encl_page->epc_page = epc_page;
 	sgx_test_and_clear_young(encl_page, encl);
 	list_add_tail(&encl_page->load_list, &encl->load_list);
@@ -558,6 +559,7 @@  static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd,
 		goto out;
 	}
 
+	encl->secs_page.flags |= SGX_ENCL_PAGE_EPC_VALID;
 	encl->secs_page.epc_page = secs_epc;
 	createp->src = (unsigned long)encl->base;
 
diff --git a/drivers/platform/x86/intel_sgx/sgx_page_cache.c b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
index 19e6617..f3326e0 100644
--- a/drivers/platform/x86/intel_sgx/sgx_page_cache.c
+++ b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
@@ -330,10 +330,14 @@  static int __sgx_ewb(struct sgx_encl *encl,
 	sgx_put_page(va);
 	sgx_put_page(epc);
 
-	if (ret == SGX_SUCCESS)
+	if (ret == SGX_SUCCESS) {
+		encl_page->flags &= ~(SGX_ENCL_PAGE_RESERVED | SGX_ENCL_PAGE_EPC_VALID);
+		sgx_free_page(encl_page->epc_page, encl);
 		encl_page->va_page = va_page;
-	else
+	}
+	else {
 		sgx_free_va_slot(va_page, encl_page->va_offset);
+	}
 
 out_pcmd:
 	sgx_put_backing(pcmd, true);
@@ -368,9 +372,6 @@  static void sgx_evict_page(struct sgx_encl_page *entry,
 			   struct sgx_encl *encl)
 {
 	sgx_ewb(encl, entry);
-	sgx_free_page(entry->epc_page, encl);
-	entry->epc_page = NULL;
-	entry->flags &= ~SGX_ENCL_PAGE_RESERVED;
 }
 
 static void sgx_write_pages(struct sgx_encl *encl, struct list_head *src)
diff --git a/drivers/platform/x86/intel_sgx/sgx_util.c b/drivers/platform/x86/intel_sgx/sgx_util.c
index 3aacd5a..2ff9f85 100644
--- a/drivers/platform/x86/intel_sgx/sgx_util.c
+++ b/drivers/platform/x86/intel_sgx/sgx_util.c
@@ -232,6 +232,7 @@  static int sgx_eldu(struct sgx_encl *encl,
 		ret = -EFAULT;
 	} else {
 		sgx_free_va_slot(encl_page->va_page, encl_page->va_offset);
+		encl_page->flags |= SGX_ENCL_PAGE_EPC_VALID;
 		encl_page->epc_page = epc_page;
 	}
 
@@ -293,7 +294,7 @@  static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma,
 	}
 
 	/* Legal race condition, page is already faulted. */
-	if (entry->epc_page) {
+	if (entry->flags & SGX_ENCL_PAGE_EPC_VALID) {
 		if (reserve)
 			entry->flags |= SGX_ENCL_PAGE_RESERVED;
 		goto out;
@@ -307,7 +308,7 @@  static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma,
 	}
 
 	/* If SECS is evicted then reload it first */
-	if (!encl->secs_page.epc_page) {
+	if (!(encl->secs_page.flags & SGX_ENCL_PAGE_EPC_VALID)) {
 		secs_epc_page = sgx_alloc_page(SGX_ALLOC_ATOMIC);
 		if (IS_ERR(secs_epc_page)) {
 			rc = PTR_ERR(secs_epc_page);
@@ -398,7 +399,7 @@  void sgx_encl_release(struct kref *ref)
 
 	radix_tree_for_each_slot(slot, &encl->page_tree, &iter, 0) {
 		entry = *slot;
-		if (entry->epc_page) {
+		if (entry->flags & SGX_ENCL_PAGE_EPC_VALID) {
 			list_del(&entry->load_list);
 			sgx_free_page(entry->epc_page, encl);
 		}
@@ -414,11 +415,9 @@  void sgx_encl_release(struct kref *ref)
 		kfree(va_page);
 	}
 
-	if (encl->secs_page.epc_page)
+	if (encl->secs_page.flags & SGX_ENCL_PAGE_EPC_VALID)
 		sgx_free_page(encl->secs_page.epc_page, encl);
 
-	encl->secs_page.epc_page = NULL;
-
 	if (encl->tgid_ctx)
 		kref_put(&encl->tgid_ctx->refcount, sgx_tgid_ctx_release);