Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp485960pxb; Wed, 18 Nov 2020 09:22:17 -0800 (PST) X-Google-Smtp-Source: ABdhPJwrBmyZNf8SYp7KoM4mipsMktfDSnmcWSXQxBl54GgZmYpGU8yY1zQ6zDa0rSWj/u3Nq9TB X-Received: by 2002:a17:906:f247:: with SMTP id gy7mr25034951ejb.48.1605720137606; Wed, 18 Nov 2020 09:22:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605720137; cv=none; d=google.com; s=arc-20160816; b=JPbQWn1x0dBqp2BvbAULrGtVQ54OJCHMSfKKIHSPGGfZc59g4vJbJ3vBjf4lP1CRAT kKToOvbfyOW97IvEDdcxqzSigxdZ3poOPeJ7q9xPm48QEsAe1PFO5au/SNGxvVEd3VVN xw7CNB0LBxQNBC9Y7rUHUAuSGbGg42N3KdLGapIRURT2HCf4s/QzRUFciybez9wdLr0v x1M4l7uRJoJlyQaCanPGKGuXt3YJ+0g03ADkLBHf60iBgE6I7E8f2dD7Mkul+cs9Fq/9 pgS7rRQgXAs89g+GTz86vGOgIv3/b/QajriisKw9UXV6gfAgnxMmCDHemFtHxb3nlGT6 VKbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:robot-unsubscribe :robot-id:message-id:mime-version:references:in-reply-to:cc:subject :to:reply-to:sender:from:dkim-signature:dkim-signature:date; bh=utu8mXfJMoOQe4yyZ6T8G2N/JDq5vuFbnFVK382uGMU=; b=kfcAHGmwJlQvuLXTwTEkzO2WprMODOpFGv6PQ0b1DUex5PshfI5rHHKPs1+ffoKedd /rklmtk7+/08hp5RNSyb39H4+PsMp8piuKsUo/6JiXnes+tsDNZmje7wt4RXfo5WX2s+ fBBKXjRzmKU0EYUOJ104hjOpk7MGWmQ5bkkunVY9Xt0wPOE1ngy6QJciL3nrUFApeVTM fjmSwsdXULIj9p+YTLE5Ljf7lPca0PZs7Vhve3DHCuZqksOeKyz7nyNBBcfRcbVSNcyk qHUxXW9x+ReOdiSDolNqzWgArvWinylpbbifVMuAtlpqnwsBAq4l37mfk3CMtokWyM5K u2+g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=YAxMFXB0; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e; 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=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f10si16392128edx.567.2020.11.18.09.21.54; Wed, 18 Nov 2020 09:22:17 -0800 (PST) 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; dkim=pass header.i=@linutronix.de header.s=2020 header.b=YAxMFXB0; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e; 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=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728176AbgKRRSc (ORCPT + 99 others); Wed, 18 Nov 2020 12:18:32 -0500 Received: from Galois.linutronix.de ([193.142.43.55]:56246 "EHLO galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728155AbgKRRSb (ORCPT ); Wed, 18 Nov 2020 12:18:31 -0500 Date: Wed, 18 Nov 2020 17:18:27 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1605719908; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=utu8mXfJMoOQe4yyZ6T8G2N/JDq5vuFbnFVK382uGMU=; b=YAxMFXB0ensIMzhg8jwn0GaSaAsDOCNiiRh4xXqXo0pRm1/0IvcpZ76QHINs5zE0Vih3oF VC9X05Hf6HAdwZfCCw4R991JNd8hs2tOaGN7rahRtdhehMfiDz2nljx3aIiw+J4L7k5FjN LSZKpnmhbjGlNdliVjvvpGg4MHJXHMkHas31X2unGfiRFHGwIeGR8V4OAn2JSxOFqHZtgZ KhH8qiilzeYkYQgpBawhDgT4r7vZ0+pDVTbRrUkXe2Fgw2nlD+9s5wBiLm0UKhpwU1FSyI yBZuuGr8Y2J/2YUQoEo++K47Z6EN1tlSg2cVT7OMvZafIr6c3ikEwvzJfSjvPg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1605719908; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=utu8mXfJMoOQe4yyZ6T8G2N/JDq5vuFbnFVK382uGMU=; b=fEz2L5jeNYad6PCliqlJjyWyOk3fXy1AwpiRmijU7JPav8i6/T58i7RsN3U1fzvKk/71AS 3jCHlTNBJv3Q/gCw== From: "tip-bot2 for Sean Christopherson" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: x86/sgx] x86/sgx: Initialize metadata for Enclave Page Cache (EPC) sections Cc: Sean Christopherson , Serge Ayoun , Jarkko Sakkinen , Borislav Petkov , Jethro Beekman , x86@kernel.org, linux-kernel@vger.kernel.org In-Reply-To: <20201112220135.165028-6-jarkko@kernel.org> References: <20201112220135.165028-6-jarkko@kernel.org> MIME-Version: 1.0 Message-ID: <160571990772.11244.15200375874379034363.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The following commit has been merged into the x86/sgx branch of tip: Commit-ID: e7e0545299d8cb0fd6fe3ba50401b7f5c3937362 Gitweb: https://git.kernel.org/tip/e7e0545299d8cb0fd6fe3ba50401b7f5c39= 37362 Author: Sean Christopherson AuthorDate: Fri, 13 Nov 2020 00:01:16 +02:00 Committer: Borislav Petkov CommitterDate: Tue, 17 Nov 2020 14:36:13 +01:00 x86/sgx: Initialize metadata for Enclave Page Cache (EPC) sections Although carved out of normal DRAM, enclave memory is marked in the system memory map as reserved and is not managed by the core mm. There may be several regions spread across the system. Each contiguous region is called an Enclave Page Cache (EPC) section. EPC sections are enumerated via CPUID Enclave pages can only be accessed when they are mapped as part of an enclave, by a hardware thread running inside the enclave. Parse CPUID data, create metadata for EPC pages and populate a simple EPC page allocator. Although much smaller, =E2=80=98struct sgx_epc_page=E2= =80=99 metadata is the SGX analog of the core mm =E2=80=98struct page=E2=80=99. Similar to how the core mm=E2=80=99s page->flags encode zone and NUMA information, embed the EPC section index to the first eight bits of sgx_epc_page->desc. This allows a quick reverse lookup from EPC page to EPC section. 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. 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 Signed-off-by: Borislav Petkov Acked-by: Jethro Beekman Link: https://lkml.kernel.org/r/20201112220135.165028-6-jarkko@kernel.org --- arch/x86/Kconfig | 17 +++- arch/x86/kernel/cpu/Makefile | 1 +- arch/x86/kernel/cpu/sgx/Makefile | 2 +- arch/x86/kernel/cpu/sgx/main.c | 190 ++++++++++++++++++++++++++++++- arch/x86/kernel/cpu/sgx/sgx.h | 60 +++++++++- 5 files changed, 270 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 f6946b8..618d1aa 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1930,6 +1930,23 @@ config X86_INTEL_TSX_MODE_AUTO side channel attacks- equals the tsx=3Dauto command line parameter. endchoice =20 +config X86_SGX + bool "Software Guard eXtensions (SGX)" + depends on X86_64 && CPU_SUP_INTEL + depends on CRYPTO=3Dy + depends on CRYPTO_SHA256=3Dy + 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 93792b4..637b499 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_X86_MCE) +=3D mce/ obj-$(CONFIG_MTRR) +=3D mtrr/ obj-$(CONFIG_MICROCODE) +=3D microcode/ obj-$(CONFIG_X86_CPU_RESCTRL) +=3D resctrl/ +obj-$(CONFIG_X86_SGX) +=3D sgx/ =20 obj-$(CONFIG_X86_LOCAL_APIC) +=3D perfctr-watchdog.o =20 diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makef= ile new file mode 100644 index 0000000..79510ce --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/Makefile @@ -0,0 +1,2 @@ +obj-y +=3D \ + 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 0000000..187a237 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2016-20 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 *ksgxd_tsk; + +/* + * Reset dirty EPC pages to uninitialized state. Laundry can be left with SE= CS + * pages whose child pages blocked EREMOVE. + */ +static void sgx_sanitize_section(struct sgx_epc_section *section) +{ + struct sgx_epc_page *page; + LIST_HEAD(dirty); + int ret; + + while (!list_empty(§ion->laundry_list)) { + if (kthread_should_stop()) + return; + + spin_lock(§ion->lock); + + page =3D list_first_entry(§ion->laundry_list, + struct sgx_epc_page, list); + + ret =3D __eremove(sgx_get_epc_virt_addr(page)); + if (!ret) + list_move(&page->list, §ion->page_list); + else + list_move_tail(&page->list, &dirty); + + spin_unlock(§ion->lock); + + cond_resched(); + } + + list_splice(&dirty, §ion->laundry_list); +} + +static int ksgxd(void *p) +{ + int i; + + set_freezable(); + + /* + * Sanitize pages in order to recover from kexec(). The 2nd pass is + * required for SECS pages, whose child pages blocked EREMOVE. + */ + for (i =3D 0; i < sgx_nr_epc_sections; i++) + sgx_sanitize_section(&sgx_epc_sections[i]); + + for (i =3D 0; i < sgx_nr_epc_sections; i++) { + sgx_sanitize_section(&sgx_epc_sections[i]); + + /* Should never happen. */ + if (!list_empty(&sgx_epc_sections[i].laundry_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 =3D kthread_run(ksgxd, NULL, "ksgxd"); + if (IS_ERR(tsk)) + return false; + + ksgxd_tsk =3D tsk; + + return true; +} + +static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size, + unsigned long index, + struct sgx_epc_section *section) +{ + unsigned long nr_pages =3D size >> PAGE_SHIFT; + unsigned long i; + + section->virt_addr =3D memremap(phys_addr, size, MEMREMAP_WB); + if (!section->virt_addr) + return false; + + section->pages =3D vmalloc(nr_pages * sizeof(struct sgx_epc_page)); + if (!section->pages) { + memunmap(section->virt_addr); + return false; + } + + section->phys_addr =3D phys_addr; + spin_lock_init(§ion->lock); + INIT_LIST_HEAD(§ion->page_list); + INIT_LIST_HEAD(§ion->laundry_list); + + for (i =3D 0; i < nr_pages; i++) { + section->pages[i].section =3D index; + list_add_tail(§ion->pages[i].list, §ion->laundry_list); + } + + return true; +} + +/** + * 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 =3D 0; i < ARRAY_SIZE(sgx_epc_sections); i++) { + cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC, &eax, &ebx, &ecx, &edx); + + type =3D eax & SGX_CPUID_EPC_MASK; + if (type =3D=3D SGX_CPUID_EPC_INVALID) + break; + + if (type !=3D SGX_CPUID_EPC_SECTION) { + pr_err_once("Unknown EPC section type: %u\n", type); + break; + } + + pa =3D sgx_calc_section_metric(eax, ebx); + size =3D 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) +{ + int i; + + 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: + for (i =3D 0; i < sgx_nr_epc_sections; i++) { + vfree(sgx_epc_sections[i].pages); + memunmap(sgx_epc_sections[i].virt_addr); + } +} + +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 0000000..02afa84 --- /dev/null +++ b/arch/x86/kernel/cpu/sgx/sgx.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#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 + +#define SGX_MAX_EPC_SECTIONS 8 + +struct sgx_epc_page { + unsigned int section; + 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 phys_addr; + void *virt_addr; + struct list_head page_list; + struct list_head laundry_list; + struct sgx_epc_page *pages; + spinlock_t lock; +}; + +extern struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; + +static inline unsigned long sgx_get_epc_phys_addr(struct sgx_epc_page *page) +{ + struct sgx_epc_section *section =3D &sgx_epc_sections[page->section]; + unsigned long index; + + index =3D ((unsigned long)page - (unsigned long)section->pages) / sizeof(*p= age); + + return section->phys_addr + index * PAGE_SIZE; +} + +static inline void *sgx_get_epc_virt_addr(struct sgx_epc_page *page) +{ + struct sgx_epc_section *section =3D &sgx_epc_sections[page->section]; + unsigned long index; + + index =3D ((unsigned long)page - (unsigned long)section->pages) / sizeof(*p= age); + + return section->virt_addr + index * PAGE_SIZE; +} + +#endif /* _X86_SGX_H */