@@ -14,6 +14,7 @@
struct sgx_epc_page {
unsigned long desc;
+ void *owner;
struct list_head list;
};
@@ -65,7 +66,7 @@ static inline void __iomem *sgx_epc_addr(struct sgx_epc_page *page)
return section->va + (page->desc & PAGE_MASK) - section->pa;
}
-/**
+/*
* ENCLS_FAULT_FLAG - flag signifying an ENCLS return code is a trapnr
*
* ENCLS has its own (positive value) error codes and also generates
@@ -309,4 +310,8 @@ static inline int __emodt(struct sgx_secinfo *secinfo, void __iomem *addr)
return __encls_ret_2(SGX_EMODT, secinfo, addr);
}
+struct sgx_epc_page *sgx_alloc_page(void *owner, bool reclaim);
+int __sgx_free_page(struct sgx_epc_page *page);
+void sgx_free_page(struct sgx_epc_page *page);
+
#endif /* _ASM_X86_SGX_H */
@@ -19,6 +19,92 @@ EXPORT_SYMBOL_GPL(sgx_epc_sections);
static int sgx_nr_epc_sections;
+/**
+ * sgx_alloc_page - Allocate an EPC page
+ * @owner: the owner of the EPC page
+ * @reclaim: wait and reclaim pages up until we get one
+ *
+ * Try to grab a page from the free EPC page list. If there is a free page
+ * available, it is returned to the caller. The @reclaim parameter hints
+ * the EPC memory manager to swap pages when required.
+ *
+ * Return:
+ * a pointer to a &struct sgx_epc_page instace,
+ * -errno on error
+ */
+struct sgx_epc_page *sgx_alloc_page(void *owner, bool reclaim)
+{
+ struct sgx_epc_section *section;
+ struct sgx_epc_page *page;
+ int i;
+
+ for (i = 0; i < sgx_nr_epc_sections; i++) {
+ section = &sgx_epc_sections[i];
+ spin_lock(§ion->lock);
+ if (section->free_cnt) {
+ page = section->pages[section->free_cnt - 1];
+ section->free_cnt--;
+ }
+ spin_unlock(§ion->lock);
+
+ if (page) {
+ page->owner = owner;
+ return page;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(sgx_alloc_page);
+
+/**
+ * __sgx_free_page - Free an EPC page
+ * @page: pointer a previously allocated EPC page
+ *
+ * Invaldate an EPC page and insert it back to the list of free pages.
+ *
+ * Return:
+ * 0 on success
+ * -EBUSY if the page cannot be removed from the active list
+ * SGX error code if EREMOVE fails
+ */
+int __sgx_free_page(struct sgx_epc_page *page)
+{
+ struct sgx_epc_section *section = sgx_epc_section(page);
+ int ret;
+
+ ret = __eremove(sgx_epc_addr(page));
+ if (ret)
+ return ret;
+
+ spin_lock(§ion->lock);
+ section->pages[section->free_cnt++] = page;
+ spin_unlock(§ion->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__sgx_free_page);
+
+/**
+ * sgx_free_page - Free an EPC page and WARN on failure
+ * @page: pointer to a previously allocated EPC page
+ *
+ * EREMOVE an EPC page and insert it back to the list of free pages.
+ * If the page is reclaimable, deletes it from the active page list.
+ * WARN on any failure. For use when the call site cannot (or chooses
+ * not to) handle failure, i.e. the page is leaked on failure.
+ */
+void sgx_free_page(struct sgx_epc_page *page)
+{
+ int ret;
+
+ ret = __sgx_free_page(page);
+ WARN(ret < 0, "sgx: cannot free page, reclaim in-progress");
+ WARN(ret > 0, "sgx: EREMOVE returned %d (0x%x)", ret, ret);
+}
+EXPORT_SYMBOL_GPL(sgx_free_page);
+
+
static __init void sgx_free_epc_section(struct sgx_epc_section *section)
{
int i;