Received: by 2002:ac0:98c7:0:0:0:0:0 with SMTP id g7-v6csp2693091imd; Fri, 2 Nov 2018 16:19:49 -0700 (PDT) X-Google-Smtp-Source: AJdET5fSUH8CuycnBw0+oM8Mehxj6IYLwfc9BvET6oNIXpoRF7Cp+xpoNGeG4H9tdCLlsScKLrzP X-Received: by 2002:a17:902:b784:: with SMTP id e4-v6mr13158194pls.45.1541200789519; Fri, 02 Nov 2018 16:19:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1541200789; cv=none; d=google.com; s=arc-20160816; b=zxUGmR6ymP9H3SVkAbET3uSnXWCPpYaMGD48JLbNDttPNM/+gZ4/uq+Ww3+f88ue84 q+wiWr5pYaZZeVmTVy+daUyOQwUfRg9rGwDqfsjQaq3GYfl1ruC8wNIzD9/5UrQUXH8c bcja7cL4RvXXTIzH2SQUcsbmvcEANkq9hFyp1Ps0zgYjMy7b5GVl+T6G0+pA0GCXZW4v 4F+ss7UYHGNzc5A7nsg1kxO9Wb910tCZARRkcXSpet5FJh2ztap33uGmBQj4jCa3HfOS HW8QRHO2vX9leHFLDosS6+Tin1edZhxImeWrVNeOOTr99A0xv1vUPKNdNar6u2vkLl5n PHdg== 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; bh=nkZEmJO2p77X1T8tpmuT0oS6Y+aTbqSTmqOF+i2QvJA=; b=azPgKjFjinSLASeyRKO+JnO5cXg5Y5w9vpoFQcipSaZ5lXZCele09FL7tEEuatMQsh tkKVAi8lKR9K+pmwjIwLLZwMpIlvCMv2KVBHifLR40Ee154Icvw4i5B1DXfboXltCisG EYB2TibyrLyKjwuIw6bDYvsclWhABPKcp1aRFEjBiFeLMOdU3bGDbg+7M2je7d9AaWMN zDiGO3QdS9QqWEuDRWXJWJv7R4tKky1fdjMO1w9ijU6oYANaowPzq1iZxm3CE4n1JC0g 7YeJNZGFOfH3wo4+VwSf9lU0+8EWdvIMDdKfNIitzJWqLXsgrvJorZq/71IXALPQksIV 1/4Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 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. [209.132.180.67]) by mx.google.com with ESMTP id 31-v6si3268667plc.140.2018.11.02.16.19.34; Fri, 02 Nov 2018 16:19:49 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 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 S1728603AbeKCI02 (ORCPT + 99 others); Sat, 3 Nov 2018 04:26:28 -0400 Received: from mga14.intel.com ([192.55.52.115]:32587 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728357AbeKCI01 (ORCPT ); Sat, 3 Nov 2018 04:26:27 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 02 Nov 2018 16:17:19 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,457,1534834800"; d="scan'208";a="270988112" Received: from btyborox-mobl.ger.corp.intel.com (HELO localhost) ([10.249.254.138]) by orsmga005.jf.intel.com with ESMTP; 02 Nov 2018 16:17:10 -0700 From: Jarkko Sakkinen To: x86@kernel.org, platform-driver-x86@vger.kernel.org, linux-sgx@vger.kernel.org Cc: dave.hansen@intel.com, sean.j.christopherson@intel.com, nhorman@redhat.com, npmccallum@redhat.com, serge.ayoun@intel.com, shay.katz-zamir@intel.com, haitao.huang@intel.com, mark.shanahan@intel.com, andriy.shevchenko@linux.intel.com, Suresh Siddha , Jarkko Sakkinen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Reinette Chatre , "Rafael J. Wysocki" , "Kirill A. Shutemov" , linux-kernel@vger.kernel.org (open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)) Subject: [PATCH v15 16/23] x86/sgx: Enumerate and track EPC sections Date: Sat, 3 Nov 2018 01:11:15 +0200 Message-Id: <20181102231320.29164-17-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181102231320.29164-1-jarkko.sakkinen@linux.intel.com> References: <20181102231320.29164-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 allocated, freed and managed. As a system may have multiple EPC sections, invoke CPUID on SGX sub-leafs until an invalid leaf is encountered. On NUMA systems, a node can have at most one bank. A bank can be at most part of two nodes. SGX supports both nodes with a single memory controller and also sub-cluster nodes with severals memory controllers on a single die. For simplicity, support a maximum of eight EPC sections. Current client hardware supports only a single section, while upcoming server hardware will support at most eight sections. Bounding the number of sections also allows the section ID to be embedded along with a page's offset in a single unsigned long, enabling easy retrieval of both the VA and PA for a given page. Co-developed-by: Jarkko Sakkinen Co-developed-by: Suresh Siddha Co-developed-by: Serge Ayoun Signed-off-by: Serge Ayoun Signed-off-by: Suresh Siddha Signed-off-by: Sean Christopherson Signed-off-by: Jarkko Sakkinen --- arch/x86/Kconfig | 17 ++++ arch/x86/include/asm/sgx.h | 57 +++++++++++++ arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/intel_sgx.c | 137 ++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100644 arch/x86/kernel/cpu/intel_sgx.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 1a0be022f91d..b47e1a144409 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1913,6 +1913,23 @@ config X86_INTEL_MEMORY_PROTECTION_KEYS If unsure, say y. +config INTEL_SGX_CORE + bool "Intel SGX core functionality" + depends on X86_64 && CPU_SUP_INTEL + help + Intel Software Guard eXtensions (SGX) CPU feature that allows ring 3 + applications to create enclaves: private regions of memory that are + architecturally protected from unauthorized access and/or modification. + + This option enables kernel recognition of SGX, high-level management + of the Enclave Page Cache (EPC), tracking and writing of SGX Launch + Enclave Hash MSRs, and allows for virtualization of SGX via KVM. By + itself, this option does not provide SGX support to userspace. + + For details, see Documentation/x86/intel_sgx.rst + + If unsure, say N. + config EFI bool "EFI runtime service support" depends on ACPI diff --git a/arch/x86/include/asm/sgx.h b/arch/x86/include/asm/sgx.h index 23361d508348..aa51165eb3a8 100644 --- a/arch/x86/include/asm/sgx.h +++ b/arch/x86/include/asm/sgx.h @@ -5,9 +5,66 @@ #ifndef _ASM_X86_SGX_H #define _ASM_X86_SGX_H +#include +#include +#include +#include #include #include +struct sgx_epc_page { + unsigned long desc; + struct list_head list; +}; + +/** + * struct sgx_epc_section + * + * 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 __iomem *va; + struct sgx_epc_page **pages; + unsigned long free_cnt; + spinlock_t lock; +}; + +#define SGX_MAX_EPC_SECTIONS 8 + +extern struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; + +/** + * enum sgx_epc_page_desc - bits and masks for an EPC page's descriptor + * %SGX_EPC_SECTION_MASK: SGX allows to have multiple EPC sections in the + * physical memory. The existing and near-future + * hardware defines at most eight sections, hence + * three bits to hold a section. + * %SGX_EPC_PAGE_RECLAIMABLE: The page page is reclaimable. Used when freeing + * a page to know that we also need to remove the + * page from the list of reclaimable pages. + */ +enum sgx_epc_page_desc { + SGX_EPC_SECTION_MASK = GENMASK_ULL(3, 0), + SGX_EPC_PAGE_RECLAIMABLE = BIT(4), + /* bits 12-63 are reserved for the physical page address of the page */ +}; + +static inline struct sgx_epc_section *sgx_epc_section(struct sgx_epc_page *page) +{ + return &sgx_epc_sections[page->desc & SGX_EPC_SECTION_MASK]; +} + +static inline void __iomem *sgx_epc_addr(struct sgx_epc_page *page) +{ + struct sgx_epc_section *section = sgx_epc_section(page); + + return section->va + (page->desc & PAGE_MASK) - section->pa; +} + /** * ENCLS_FAULT_FLAG - flag signifying an ENCLS return code is a trapnr * diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 347137e80bf5..71876f2b35fc 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o obj-$(CONFIG_INTEL_RDT) += intel_rdt.o intel_rdt_rdtgroup.o intel_rdt_monitor.o obj-$(CONFIG_INTEL_RDT) += intel_rdt_ctrlmondata.o intel_rdt_pseudo_lock.o CFLAGS_intel_rdt_pseudo_lock.o = -I$(src) +obj-$(CONFIG_INTEL_SGX_CORE) += intel_sgx.o obj-$(CONFIG_X86_MCE) += mcheck/ obj-$(CONFIG_MTRR) += mtrr/ diff --git a/arch/x86/kernel/cpu/intel_sgx.c b/arch/x86/kernel/cpu/intel_sgx.c new file mode 100644 index 000000000000..b86aa4111592 --- /dev/null +++ b/arch/x86/kernel/cpu/intel_sgx.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-17 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include + +struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS]; +EXPORT_SYMBOL_GPL(sgx_epc_sections); + +static int sgx_nr_epc_sections; + +static __init void sgx_free_epc_section(struct sgx_epc_section *section) +{ + int i; + + for (i = 0; i < section->free_cnt && section->pages[i]; i++) + kfree(section->pages[i]); + kfree(section->pages); + iounmap(section->va); +} + +static __init int sgx_init_epc_section(u64 addr, u64 size, unsigned long index, + struct sgx_epc_section *section) +{ + unsigned long nr_pages = size >> PAGE_SHIFT; + unsigned long i; + + section->va = ioremap_cache(addr, size); + if (!section->va) + return -ENOMEM; + + section->pa = addr; + section->free_cnt = nr_pages; + spin_lock_init(§ion->lock); + + section->pages = kcalloc(nr_pages, sizeof(struct sgx_epc_page *), + GFP_KERNEL); + if (!section->pages) + goto out; + + for (i = 0; i < nr_pages; i++) { + section->pages[i] = kzalloc(sizeof(struct sgx_epc_page), + GFP_KERNEL); + if (!section->pages[i]) + goto out; + + section->pages[i]->desc = (addr + (i << PAGE_SHIFT)) | index; + } + + return 0; +out: + sgx_free_epc_section(section); + return -ENOMEM; +} + +static __init void 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 sgx_calc_section_metric(u64 low, u64 high) +{ + return (low & GENMASK_ULL(31, 12)) + + ((high & GENMASK_ULL(19, 0)) << 32); +} + +static __init int sgx_page_cache_init(void) +{ + u32 eax, ebx, ecx, edx, type; + u64 pa, size; + int ret; + int i; + + BUILD_BUG_ON(SGX_MAX_EPC_SECTIONS > (SGX_EPC_SECTION_MASK + 1)); + + for (i = 0; i < SGX_MAX_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("sgx: Unknown sub-leaf type: %u\n", type); + continue; + } + + pa = sgx_calc_section_metric(eax, ebx); + size = sgx_calc_section_metric(ecx, edx); + pr_info("sgx: EPC section 0x%llx-0x%llx\n", pa, pa + size - 1); + + ret = sgx_init_epc_section(pa, size, i, &sgx_epc_sections[i]); + if (ret) { + sgx_page_cache_teardown(); + return ret; + } + + sgx_nr_epc_sections++; + } + + if (!sgx_nr_epc_sections) { + pr_err("sgx: There are zero EPC sections.\n"); + return -ENODEV; + } + + return 0; +} + +static __init int sgx_init(void) +{ + int ret; + + if (!boot_cpu_has(X86_FEATURE_SGX)) + return false; + + ret = sgx_page_cache_init(); + if (ret) + return ret; + + return 0; +} + +arch_initcall(sgx_init); -- 2.19.1