From patchwork Thu Apr 20 16:16:14 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Christopherson X-Patchwork-Id: 9690891 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C1B1860383 for ; Thu, 20 Apr 2017 16:16:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A33C028499 for ; Thu, 20 Apr 2017 16:16:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 97E87284A5; Thu, 20 Apr 2017 16:16:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 19B3E28499 for ; Thu, 20 Apr 2017 16:16:26 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 724D82194EB6A; Thu, 20 Apr 2017 09:16:25 -0700 (PDT) X-Original-To: intel-sgx-kernel-dev@lists.01.org Delivered-To: intel-sgx-kernel-dev@lists.01.org Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id EB9BD21954077 for ; Thu, 20 Apr 2017 09:16:23 -0700 (PDT) Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP; 20 Apr 2017 09:16:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.37,225,1488873600"; d="scan'208";a="251515785" Received: from sjchrist-ts.jf.intel.com ([10.54.74.20]) by fmsmga004.fm.intel.com with ESMTP; 20 Apr 2017 09:16:22 -0700 From: Sean Christopherson To: intel-sgx-kernel-dev@lists.01.org Date: Thu, 20 Apr 2017 09:16:14 -0700 Message-Id: <1492704977-26510-3-git-send-email-sean.j.christopherson@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1492704977-26510-1-git-send-email-sean.j.christopherson@intel.com> References: <1492704977-26510-1-git-send-email-sean.j.christopherson@intel.com> Subject: [intel-sgx-kernel-dev] [PATCH v2 2/4] intel_sgx: delay VA slot allocation until EWB X-BeenThere: intel-sgx-kernel-dev@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "Project: Intel® Software Guard Extensions for Linux*: https://01.org/intel-software-guard-extensions" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-sgx-kernel-dev-bounces@lists.01.org Sender: "intel-sgx-kernel-dev" X-Virus-Scanned: ClamAV using ClamSMTP Reserve enough VA slots/pages at enclave creation, but delay actual VA slot allocation until EWB. Track the number of EPC and VA pages that have been allocated and use those numbers to determine whether or not enough VA slots have been reserved. Rename sgx_init_page to sgx_alloc_va_page and check if we need a new VA page outside of the function. This allows __encl_add_page to do a single mutex_lock for its fast path; the lock cannot be held while allocating the VA page as allocating an EPC page may cause the thread to yield. Signed-off-by: Sean Christopherson --- drivers/platform/x86/intel_sgx/sgx.h | 12 +-- drivers/platform/x86/intel_sgx/sgx_ioctl.c | 103 +++++++++++------------- drivers/platform/x86/intel_sgx/sgx_page_cache.c | 43 +++++++++- drivers/platform/x86/intel_sgx/sgx_util.c | 5 +- 4 files changed, 94 insertions(+), 69 deletions(-) diff --git a/drivers/platform/x86/intel_sgx/sgx.h b/drivers/platform/x86/intel_sgx/sgx.h index 3451a56..958e37d 100644 --- a/drivers/platform/x86/intel_sgx/sgx.h +++ b/drivers/platform/x86/intel_sgx/sgx.h @@ -82,16 +82,6 @@ struct sgx_va_page { struct list_head list; }; -static inline unsigned int sgx_alloc_va_slot(struct sgx_va_page *page) -{ - int slot = find_first_zero_bit(page->slots, SGX_VA_SLOT_COUNT); - - if (slot < SGX_VA_SLOT_COUNT) - set_bit(slot, page->slots); - - return slot << 3; -} - static inline void sgx_free_va_slot(struct sgx_va_page *page, unsigned int offset) { @@ -129,6 +119,8 @@ enum sgx_encl_flags { struct sgx_encl { unsigned int flags; unsigned int secs_child_cnt; + unsigned int encl_page_cnt; + unsigned int va_page_cnt; struct mutex lock; struct mm_struct *mm; struct file *backing; diff --git a/drivers/platform/x86/intel_sgx/sgx_ioctl.c b/drivers/platform/x86/intel_sgx/sgx_ioctl.c index ba7c0d2..af80571 100644 --- a/drivers/platform/x86/intel_sgx/sgx_ioctl.c +++ b/drivers/platform/x86/intel_sgx/sgx_ioctl.c @@ -384,63 +384,48 @@ static int sgx_validate_secs(const struct sgx_secs *secs) return 0; } -static int sgx_init_page(struct sgx_encl *encl, - struct sgx_encl_page *entry, - unsigned long addr) +static int sgx_alloc_va_page(struct sgx_encl *encl) { struct sgx_va_page *va_page; struct sgx_epc_page *epc_page = NULL; - unsigned int va_offset = PAGE_SIZE; void *vaddr; int ret = 0; - list_for_each_entry(va_page, &encl->va_pages, list) { - va_offset = sgx_alloc_va_slot(va_page); - if (va_offset < PAGE_SIZE) - break; - } - - if (va_offset == PAGE_SIZE) { - va_page = kzalloc(sizeof(*va_page), GFP_KERNEL); - if (!va_page) - return -ENOMEM; - - epc_page = sgx_alloc_page(0); - if (IS_ERR(epc_page)) { - kfree(va_page); - return PTR_ERR(epc_page); - } - - vaddr = sgx_get_page(epc_page); - if (!vaddr) { - sgx_warn(encl, "kmap of a new VA page failed %d\n", - ret); - sgx_free_page(epc_page, encl); - kfree(va_page); - return -EFAULT; - } + va_page = kzalloc(sizeof(*va_page), GFP_KERNEL); + if (!va_page) + return -ENOMEM; - ret = __epa(vaddr); - sgx_put_page(vaddr); + epc_page = sgx_alloc_page(0); + if (IS_ERR(epc_page)) { + kfree(va_page); + return PTR_ERR(epc_page); + } - if (ret) { - sgx_warn(encl, "EPA returned %d\n", ret); - sgx_free_page(epc_page, encl); - kfree(va_page); - return -EFAULT; - } + vaddr = sgx_get_page(epc_page); + if (!vaddr) { + sgx_warn(encl, "kmap of a new VA page failed %d\n", + ret); + sgx_free_page(epc_page, encl); + kfree(va_page); + return -EFAULT; + } - va_page->epc_page = epc_page; - va_offset = sgx_alloc_va_slot(va_page); + ret = __epa(vaddr); + sgx_put_page(vaddr); - mutex_lock(&encl->lock); - list_add(&va_page->list, &encl->va_pages); - mutex_unlock(&encl->lock); + if (ret) { + sgx_warn(encl, "EPA returned %d\n", ret); + sgx_free_page(epc_page, encl); + kfree(va_page); + return -EFAULT; } - entry->va_page = va_page; - entry->va_offset = va_offset; - entry->addr = addr; + va_page->epc_page = epc_page; + + mutex_lock(&encl->lock); + encl->va_page_cnt++; + list_add(&va_page->list, &encl->va_pages); + mutex_unlock(&encl->lock); return 0; } @@ -549,8 +534,10 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd, if (ret) goto out; - ret = sgx_init_page(encl, &encl->secs_page, - encl->base + encl->size); + encl->encl_page_cnt++; + encl->secs_page.addr = encl->base + encl->size; + + ret = sgx_alloc_va_page(encl); if (ret) goto out; @@ -690,14 +677,21 @@ static int __encl_add_page(struct sgx_encl *encl, } } - ret = sgx_init_page(encl, encl_page, addp->addr); - if (ret) { - __free_page(tmp_page); - return -EINVAL; - } - mutex_lock(&encl->lock); + encl_page->addr = addp->addr; + encl->encl_page_cnt++; + + if (encl->encl_page_cnt > (encl->va_page_cnt * SGX_VA_SLOT_COUNT)) { + /* slow path, new VA page needed */ + mutex_unlock(&encl->lock); + ret = sgx_alloc_va_page(encl); + mutex_lock(&encl->lock); + if (ret) { + goto out; + } + } + if (encl->flags & (SGX_ENCL_INITIALIZED | SGX_ENCL_DEAD)) { ret = -EINVAL; goto out; @@ -752,8 +746,7 @@ static int __encl_add_page(struct sgx_encl *encl, if (ret) { kfree(req); - sgx_free_va_slot(encl_page->va_page, - encl_page->va_offset); + encl->encl_page_cnt--; } mutex_unlock(&encl->lock); diff --git a/drivers/platform/x86/intel_sgx/sgx_page_cache.c b/drivers/platform/x86/intel_sgx/sgx_page_cache.c index 85276db..19e6617 100644 --- a/drivers/platform/x86/intel_sgx/sgx_page_cache.c +++ b/drivers/platform/x86/intel_sgx/sgx_page_cache.c @@ -253,10 +253,36 @@ static void sgx_etrack(struct sgx_encl *encl) } } + +/** + * sgx_alloc_va_slot() - allocate VA slot from a VA page + * + * @encl: Enclave to allocate from + * @va_page: Pointer to a VA page pointer + * + * Returns the offset of a free VA slot and sets va_page to the corresponding + * VA page. If there are no free slots, returns PAGE_SIZE. + */ +static inline unsigned int sgx_alloc_va_slot(struct sgx_encl *encl, + struct sgx_va_page **va_page) +{ + unsigned int slot = SGX_VA_SLOT_COUNT; + list_for_each_entry((*va_page), &encl->va_pages, list) { + slot = find_first_zero_bit((*va_page)->slots, SGX_VA_SLOT_COUNT); + if (slot < SGX_VA_SLOT_COUNT) { + set_bit(slot, (*va_page)->slots); + break; + } + } + + return slot << 3; +} + static int __sgx_ewb(struct sgx_encl *encl, struct sgx_encl_page *encl_page) { struct sgx_page_info pginfo; + struct sgx_va_page *va_page; struct page *backing; struct page *pcmd; unsigned long pcmd_offset; @@ -282,8 +308,15 @@ static int __sgx_ewb(struct sgx_encl *encl, goto out; } + encl_page->va_offset = sgx_alloc_va_slot(encl, &va_page); + if (encl_page->va_offset == PAGE_SIZE) { + sgx_warn(encl, "allocating a VA slot for EWB failed\n"); + ret = -ENOMEM; + goto out_pcmd; + } + epc = sgx_get_page(encl_page->epc_page); - va = sgx_get_page(encl_page->va_page->epc_page); + va = sgx_get_page(va_page->epc_page); pginfo.srcpge = (unsigned long)kmap_atomic(backing); pginfo.pcmd = (unsigned long)kmap_atomic(pcmd) + pcmd_offset; @@ -296,8 +329,14 @@ static int __sgx_ewb(struct sgx_encl *encl, sgx_put_page(va); sgx_put_page(epc); - sgx_put_backing(pcmd, true); + if (ret == SGX_SUCCESS) + encl_page->va_page = va_page; + else + sgx_free_va_slot(va_page, encl_page->va_offset); + +out_pcmd: + sgx_put_backing(pcmd, true); out: sgx_put_backing(backing, true); return ret; diff --git a/drivers/platform/x86/intel_sgx/sgx_util.c b/drivers/platform/x86/intel_sgx/sgx_util.c index 716c1dd..3aacd5a 100644 --- a/drivers/platform/x86/intel_sgx/sgx_util.c +++ b/drivers/platform/x86/intel_sgx/sgx_util.c @@ -230,6 +230,9 @@ static int sgx_eldu(struct sgx_encl *encl, if (ret) { sgx_err(encl, "ELDU returned %d\n", ret); ret = -EFAULT; + } else { + sgx_free_va_slot(encl_page->va_page, encl_page->va_offset); + encl_page->epc_page = epc_page; } kunmap_atomic((void *)(unsigned long)(pginfo.pcmd - pcmd_offset)); @@ -316,8 +319,6 @@ static struct sgx_encl_page *sgx_do_fault(struct vm_area_struct *vma, if (rc) goto out; - encl->secs_page.epc_page = secs_epc_page; - /* Do not free */ secs_epc_page = NULL; }