@@ -9,6 +9,7 @@
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include "arch.h"
+#include "encls.h"
#include "sgx.h"
struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS];
@@ -16,6 +17,95 @@ EXPORT_SYMBOL_GPL(sgx_epc_sections);
int sgx_nr_epc_sections;
+static struct sgx_epc_page *sgx_section_get_page(
+ struct sgx_epc_section *section)
+{
+ struct sgx_epc_page *page;
+
+ if (!section->free_cnt)
+ return NULL;
+
+ page = list_first_entry(§ion->page_list,
+ struct sgx_epc_page, list);
+ list_del_init(&page->list);
+ section->free_cnt--;
+ return page;
+}
+
+/**
+ * sgx_alloc_page - Allocate an EPC page
+ *
+ * Try to grab a page from the free EPC page list.
+ *
+ * Return:
+ * a pointer to a &struct sgx_epc_page instance,
+ * -errno on error
+ */
+struct sgx_epc_page *sgx_alloc_page(void)
+{
+ 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);
+ page = sgx_section_get_page(section);
+ spin_unlock(§ion->lock);
+
+ if (page)
+ return page;
+ }
+
+ return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL_GPL(sgx_alloc_page);
+
+/**
+ * __sgx_free_page - Free an EPC page
+ * @page: pointer a previously allocated EPC page
+ *
+ * EREMOVE an EPC page and insert it back to the list of free pages.
+ *
+ * Return:
+ * 0 on success
+ * 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);
+ list_add_tail(&page->list, §ion->page_list);
+ section->free_cnt++;
+ 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, and WARN
+ * if EREMOVE fails. 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: 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)
{
struct sgx_epc_page *page;
@@ -64,4 +64,8 @@ extern int sgx_nr_epc_sections;
int sgx_page_reclaimer_init(void);
+struct sgx_epc_page *sgx_alloc_page(void);
+int __sgx_free_page(struct sgx_epc_page *page);
+void sgx_free_page(struct sgx_epc_page *page);
+
#endif /* _X86_SGX_H */