Received: by 2002:a05:6902:102b:0:0:0:0 with SMTP id x11csp827830ybt; Wed, 17 Jun 2020 15:15:49 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzlu6EEJxR2u21fzzdRj9Ik5DJcOAZVmgYOW/XdOw/UI40/Obs31lBy6XXt6nWx8vp3JLBm X-Received: by 2002:a17:906:6d19:: with SMTP id m25mr1195150ejr.524.1592432149361; Wed, 17 Jun 2020 15:15:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1592432149; cv=none; d=google.com; s=arc-20160816; b=MctmOmPPZHrwDKWznFuPU55q/wGK45JLn2tGAAN9sdPqdozb5pDWao7GUNUub9Z6ix HEbdJJfxO4ITHkWtqkoFHPLK9Osob6DwS6Zs/48AfyaiTltCZsPPnOi6yxvZon8pp4px kuVkSWpZ+uDOGlRbRcP9tfHkfLbLMFazdo5xsewlE3XHVJ1vbVXBW/T4pre8j86/Su3G xedkmDSEa34gxYDbGxJKxutS6fs1StAP2++73ygf288YbD1ZAnrfcm3o/SRwqGzO6Sqr 8xJWEqIvi41M63qt3yK7t1AVE03ypDJozLof3WRNOtUKFRuED1Cl5GO1dvYf85N0JNuh l3DA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :ironport-sdr:ironport-sdr; bh=wp1ob9tsLJ6UmmLpW/c+fB3zFoWdD2X5Daue3Ie7U4o=; b=IEb3YoPDtctn/pBetGy7aIMMTPErQdRIS3hPi4CayHvU73o9M5efsFdBlXCkJclVDs YqwFXa3ArEee/n+1rhVRb4/Ps0YTTyw6Auf0ToVt3TY1H3myEzaDpg81JCTJtld6tpwt ixAhXe4llkEMMJXGXwqh0yGkyM+y8HW+wG01o37Pw2f7Cycvem3VFEter6oQNFBXWT3r p0C6ygQXMHgYJB2/ZAlOydfYfXk9gT4LASw4y/JkkcGZ3AvTHzPHAaserrvlUfHij5TA r7IG+IXCsDWrrcUKfuPUHrAzBUnk+OhKh3OpLwahUQvcF3TdUp3cMQxgXwsMkNztugJo KNmw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id m10si680047ejc.104.2020.06.17.15.15.27; Wed, 17 Jun 2020 15:15:49 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727111AbgFQWLM (ORCPT + 99 others); Wed, 17 Jun 2020 18:11:12 -0400 Received: from mga05.intel.com ([192.55.52.43]:51098 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726758AbgFQWLL (ORCPT ); Wed, 17 Jun 2020 18:11:11 -0400 IronPort-SDR: 34gvk+b8z6fELEm7zodaJwD+Vf9flnMhV4gdBn8GhXiQTW9wOY1cY3b1Kp99TofPP4ipxxEF5B +mZujn4MQOPA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2020 15:10:56 -0700 IronPort-SDR: pXTGe9Z0S1N/2sICqyn5pxKeyA8c1PlPQNIbeCQ+pGtTcPmQQ8HbKceDttOmziXT+Dxt0gbpCO uwqmydU1uIjA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,523,1583222400"; d="scan'208";a="421288212" Received: from ysharon1-mobl1.ger.corp.intel.com (HELO localhost) ([10.252.49.131]) by orsmga004.jf.intel.com with ESMTP; 17 Jun 2020 15:10:42 -0700 From: Jarkko Sakkinen To: x86@kernel.org, linux-sgx@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Sean Christopherson , Jethro Beekman , Serge Ayoun , Jarkko Sakkinen , akpm@linux-foundation.org, andriy.shevchenko@linux.intel.com, asapek@google.com, bp@alien8.de, cedric.xing@intel.com, chenalexchen@google.com, conradparker@google.com, cyhanish@google.com, dave.hansen@intel.com, haitao.huang@intel.com, josh@joshtriplett.org, kai.huang@intel.com, kai.svahn@intel.com, kmoy@google.com, ludloff@google.com, luto@kernel.org, nhorman@redhat.com, npmccallum@redhat.com, puiterwijk@redhat.com, rientjes@google.com, tglx@linutronix.de, yaozhangx@google.com Subject: [PATCH v33 08/21] x86/sgx: Initialize metadata for Enclave Page Cache (EPC) sections Date: Thu, 18 Jun 2020 01:08:30 +0300 Message-Id: <20200617220844.57423-9-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200617220844.57423-1-jarkko.sakkinen@linux.intel.com> References: <20200617220844.57423-1-jarkko.sakkinen@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Sean Christopherson Enumerate Enclave Page Cache (EPC) sections via CPUID and add the data structures necessary to track EPC pages so that they can be easily borrowed for different uses. Embed section index to the first eight bits of the EPC page descriptor. Existing client hardware supports only a single section, while upcoming server hardware will support at most eight sections. Thus, eight bits should be enough for long term needs. Acked-by: Jethro Beekman Signed-off-by: Sean Christopherson Co-developed-by: Serge Ayoun Signed-off-by: Serge Ayoun Co-developed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- arch/x86/Kconfig | 17 +++ arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/sgx/Makefile | 2 + arch/x86/kernel/cpu/sgx/main.c | 216 +++++++++++++++++++++++++++++++ arch/x86/kernel/cpu/sgx/sgx.h | 53 ++++++++ 5 files changed, 289 insertions(+) create mode 100644 arch/x86/kernel/cpu/sgx/Makefile create mode 100644 arch/x86/kernel/cpu/sgx/main.c create mode 100644 arch/x86/kernel/cpu/sgx/sgx.h diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6a0cc524882d..e9a9c530c087 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1926,6 +1926,23 @@ config X86_INTEL_TSX_MODE_AUTO side channel attacks- equals the tsx=auto command line parameter. endchoice +config INTEL_SGX + bool "Intel SGX" + depends on X86_64 && CPU_SUP_INTEL + depends on CRYPTO=y + depends on CRYPTO_SHA256=y + select SRCU + select MMU_NOTIFIER + help + Intel(R) Software Guard eXtensions (SGX) is a set of CPU instructions + that can be used by applications to set aside private regions of code + and data, referred to as enclaves. An enclave's private memory can + only be accessed by code running within the enclave. Accesses from + outside the enclave, including other enclaves, are disallowed by + hardware. + + If unsure, say N. + config EFI bool "EFI runtime service support" depends on ACPI diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index dba6a83bc349..b00f801601f3 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_X86_MCE) += mce/ obj-$(CONFIG_MTRR) += mtrr/ obj-$(CONFIG_MICROCODE) += microcode/ obj-$(CONFIG_X86_CPU_RESCTRL) += resctrl/ +obj-$(CONFIG_INTEL_SGX) += sgx/ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makefile new file mode 100644 index 000000000000..79510ce01b3b --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/Makefile @@ -0,0 +1,2 @@ +obj-y += \ + main.o diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c new file mode 100644 index 000000000000..c5831e3db14a --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-17 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include "encls.h" + +struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; +static int sgx_nr_epc_sections; +static struct task_struct *ksgxswapd_tsk; + +static void sgx_sanitize_section(struct sgx_epc_section *section) +{ + struct sgx_epc_page *page; + LIST_HEAD(secs_list); + int ret; + + while (!list_empty(§ion->unsanitized_page_list)) { + if (kthread_should_stop()) + return; + + spin_lock(§ion->lock); + + page = list_first_entry(§ion->unsanitized_page_list, + struct sgx_epc_page, list); + + ret = __eremove(sgx_get_epc_addr(page)); + if (!ret) + list_move(&page->list, §ion->page_list); + else + list_move_tail(&page->list, &secs_list); + + spin_unlock(§ion->lock); + + cond_resched(); + } +} + +static int ksgxswapd(void *p) +{ + int i; + + set_freezable(); + + /* + * Reset all pages to uninitialized state. Pages could be in initialized + * on kmemexec. + */ + for (i = 0; i < sgx_nr_epc_sections; i++) + sgx_sanitize_section(&sgx_epc_sections[i]); + + /* + * 2nd round for the SECS pages as they cannot be removed when they + * still hold child pages. + */ + for (i = 0; i < sgx_nr_epc_sections; i++) { + sgx_sanitize_section(&sgx_epc_sections[i]); + + /* Should never happen. */ + if (!list_empty(&sgx_epc_sections[i].unsanitized_page_list)) + WARN(1, "EPC section %d has unsanitized pages.\n", i); + } + + return 0; +} + +static bool __init sgx_page_reclaimer_init(void) +{ + struct task_struct *tsk; + + tsk = kthread_run(ksgxswapd, NULL, "ksgxswapd"); + if (IS_ERR(tsk)) + return false; + + ksgxswapd_tsk = tsk; + + return true; +} + +static void __init sgx_free_epc_section(struct sgx_epc_section *section) +{ + struct sgx_epc_page *page; + + while (!list_empty(§ion->page_list)) { + page = list_first_entry(§ion->page_list, + struct sgx_epc_page, list); + list_del(&page->list); + kfree(page); + } + + while (!list_empty(§ion->unsanitized_page_list)) { + page = list_first_entry(§ion->unsanitized_page_list, + struct sgx_epc_page, list); + list_del(&page->list); + kfree(page); + } + + memunmap(section->va); +} + +static bool __init sgx_setup_epc_section(u64 addr, u64 size, + unsigned long index, + struct sgx_epc_section *section) +{ + unsigned long nr_pages = size >> PAGE_SHIFT; + struct sgx_epc_page *page; + unsigned long i; + + section->va = memremap(addr, size, MEMREMAP_WB); + if (!section->va) + return false; + + section->pa = addr; + spin_lock_init(§ion->lock); + INIT_LIST_HEAD(§ion->page_list); + INIT_LIST_HEAD(§ion->unsanitized_page_list); + + for (i = 0; i < nr_pages; i++) { + page = kzalloc(sizeof(*page), GFP_KERNEL); + if (!page) + goto err_out; + + page->desc = (addr + (i << PAGE_SHIFT)) | index; + list_add_tail(&page->list, §ion->unsanitized_page_list); + } + + return true; + +err_out: + sgx_free_epc_section(section); + return false; +} + +static void __init sgx_page_cache_teardown(void) +{ + int i; + + for (i = 0; i < sgx_nr_epc_sections; i++) + sgx_free_epc_section(&sgx_epc_sections[i]); +} + +/** + * A section metric is concatenated in a way that @low bits 12-31 define the + * bits 12-31 of the metric and @high bits 0-19 define the bits 32-51 of the + * metric. + */ +static inline u64 __init sgx_calc_section_metric(u64 low, u64 high) +{ + return (low & GENMASK_ULL(31, 12)) + + ((high & GENMASK_ULL(19, 0)) << 32); +} + +static bool __init sgx_page_cache_init(void) +{ + u32 eax, ebx, ecx, edx, type; + u64 pa, size; + int i; + + for (i = 0; i < ARRAY_SIZE(sgx_epc_sections); i++) { + cpuid_count(SGX_CPUID, i + SGX_CPUID_FIRST_VARIABLE_SUB_LEAF, + &eax, &ebx, &ecx, &edx); + + type = eax & SGX_CPUID_SUB_LEAF_TYPE_MASK; + if (type == SGX_CPUID_SUB_LEAF_INVALID) + break; + + if (type != SGX_CPUID_SUB_LEAF_EPC_SECTION) { + pr_err_once("Unknown EPC section type: %u\n", type); + break; + } + + pa = sgx_calc_section_metric(eax, ebx); + size = sgx_calc_section_metric(ecx, edx); + + pr_info("EPC section 0x%llx-0x%llx\n", pa, pa + size - 1); + + if (!sgx_setup_epc_section(pa, size, i, &sgx_epc_sections[i])) { + pr_err("No free memory for an EPC section\n"); + break; + } + + sgx_nr_epc_sections++; + } + + if (!sgx_nr_epc_sections) { + pr_err("There are zero EPC sections.\n"); + return false; + } + + return true; +} + +static void __init sgx_init(void) +{ + if (!boot_cpu_has(X86_FEATURE_SGX)) + return; + + if (!sgx_page_cache_init()) + return; + + if (!sgx_page_reclaimer_init()) + goto err_page_cache; + + return; + +err_page_cache: + sgx_page_cache_teardown(); +} + +device_initcall(sgx_init); diff --git a/arch/x86/kernel/cpu/sgx/sgx.h b/arch/x86/kernel/cpu/sgx/sgx.h new file mode 100644 index 000000000000..6508bfefd6d9 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/sgx.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +#ifndef _X86_SGX_H +#define _X86_SGX_H + +#include +#include +#include +#include +#include +#include +#include "arch.h" + +#undef pr_fmt +#define pr_fmt(fmt) "sgx: " fmt + +struct sgx_epc_page { + unsigned long desc; + struct list_head list; +}; + +/* + * The firmware can define multiple chunks of EPC to the different areas of the + * physical memory e.g. for memory areas of the each node. This structure is + * used to store EPC pages for one EPC section and virtual memory area where + * the pages have been mapped. + */ +struct sgx_epc_section { + unsigned long pa; + void *va; + struct list_head page_list; + struct list_head unsanitized_page_list; + spinlock_t lock; +}; + +#define SGX_EPC_SECTION_MASK GENMASK(7, 0) +#define SGX_MAX_EPC_SECTIONS (SGX_EPC_SECTION_MASK + 1) + +extern struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; + +static inline struct sgx_epc_section *sgx_get_epc_section( + struct sgx_epc_page *page) +{ + return &sgx_epc_sections[page->desc & SGX_EPC_SECTION_MASK]; +} + +static inline void *sgx_get_epc_addr(struct sgx_epc_page *page) +{ + struct sgx_epc_section *section = sgx_get_epc_section(page); + + return section->va + (page->desc & PAGE_MASK) - section->pa; +} + +#endif /* _X86_SGX_H */ -- 2.25.1