From patchwork Mon Feb 22 14:29:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 62585 Delivered-To: patch@linaro.org Received: by 10.112.43.199 with SMTP id y7csp1291778lbl; Mon, 22 Feb 2016 07:06:00 -0800 (PST) X-Received: by 10.98.7.14 with SMTP id b14mr39304397pfd.40.1456153560005; Mon, 22 Feb 2016 07:06:00 -0800 (PST) Return-Path: Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id 19si40242772pfk.37.2016.02.22.07.05.59 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 22 Feb 2016 07:05:59 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:1868:205::9 as permitted sender) client-ip=2001:1868:205::9; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org designates 2001:1868:205::9 as permitted sender) smtp.mailfrom=linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org; dkim=neutral (body hash did not verify) header.i=@linaro.org Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aXs2V-0001dt-Ao; Mon, 22 Feb 2016 15:04:43 +0000 Received: from mail-wm0-x234.google.com ([2a00:1450:400c:c09::234]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1aXrUe-0003su-Vm for linux-arm-kernel@lists.infradead.org; Mon, 22 Feb 2016 14:30:24 +0000 Received: by mail-wm0-x234.google.com with SMTP id g62so166273503wme.0 for ; Mon, 22 Feb 2016 06:29:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6sn0MzAh0lf78JFTccKkH0r6NmRLxnNDrrth85J34uc=; b=isqWTUHUjWV/gjq/i/ypQdXAgvDoAJXsQsYN5krAaaqT2j49+Xb1Ym/HhctI+O4mUn TTiVw5a4VtivC+H1QwmmrB9qw5ngtTwL8ld9/2H6+lOCnS3ExR5jXi/SvXhR5mAUf5lG gFykjoDXbMxX11caK8l3hHNDJMpc83oRtwd6g= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6sn0MzAh0lf78JFTccKkH0r6NmRLxnNDrrth85J34uc=; b=kGEoGDIIjB1X8xgQ5lI180IoFwzDiiicm61FufOhPoGYRIefpAdlc7nhTF3mg5mF9E 0bx7xthxDEcrjI7CqoywHfJ9Iy0XNaHoNBFMAAsii8SKrBDUtupoStLhy5yRhIdwiyvZ FGWrZ6kkzapXbtvsEyacnqbhDQUMfNWxA8Z81+WmAjZWn9piQxqy7c4kYR0Dyz2TTLwi A5a+xJrMgSOMTQmcTaqHONiXY7QF2LmmdETMu1QbVt7Pd4O6O1CwSBC8kbziHg6Ae0Fm UtFsUgZG/qpNcL/tXKartDSPIvnwpnT8wrwauiYxQKZL21D4D0b6wWrZYqgnqGiXQnIE fwZg== X-Gm-Message-State: AG10YOTrbWzzrekHmDkMP1+HbW8tNb+Z8Um7z1NSWxdtFVNQVRcnV6wD1eQ4u2rt2orUgbtY X-Received: by 10.194.246.35 with SMTP id xt3mr31222121wjc.57.1456151363031; Mon, 22 Feb 2016 06:29:23 -0800 (PST) Received: from localhost.localdomain ([195.55.142.58]) by smtp.gmail.com with ESMTPSA id e19sm21402599wmd.1.2016.02.22.06.29.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 22 Feb 2016 06:29:22 -0800 (PST) From: Ard Biesheuvel To: linux-arm-kernel@lists.infradead.org, linux-efi@vger.kernel.org, matt@codeblueprint.co.uk, sai.praneeth.prakhya@intel.com Subject: [PATCH 4/5] efi: implement generic support for the Memory Attributes table Date: Mon, 22 Feb 2016 15:29:14 +0100 Message-Id: <1456151355-25943-1-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1456151158-25849-4-git-send-email-ard.biesheuvel@linaro.org> References: <1456151158-25849-4-git-send-email-ard.biesheuvel@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160222_062946_287226_CA944210 X-CRM114-Status: GOOD ( 25.56 ) X-Spam-Score: -2.7 (--) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-2.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [2a00:1450:400c:c09:0:0:0:234 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, pjones@redhat.com, linux@arm.linux.org.uk, leif.lindholm@linaro.org, Ard Biesheuvel MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org This implements shared support for discovering the presence of the Memory Attributes table, and for parsing and validating its contents. The table is validated against the construction rules in the UEFI spec. Since this is a new table, it makes sense to complain if we encounter a table that does not follow those rules. The parsing and validation routine takes a callback that can be specified per architecture, that gets passed each unique validated region, with the virtual address retrieved from the ordinary memory map. Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/Makefile | 2 +- drivers/firmware/efi/memattr.c | 137 ++++++++++++++++++++ include/linux/efi.h | 6 + 3 files changed, 144 insertions(+), 1 deletion(-) -- 2.5.0 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 62e654f255f4..d5be62399130 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -9,7 +9,7 @@ # KASAN_SANITIZE_runtime-wrappers.o := n -obj-$(CONFIG_EFI) += efi.o vars.o reboot.o +obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_ESRT) += esrt.o obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c new file mode 100644 index 000000000000..059cf4522a7d --- /dev/null +++ b/drivers/firmware/efi/memattr.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2016 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include + +static int __initdata tbl_size; + +/* + * Reserve the memory associated with the Memory Attributes configuration + * table, if it exists. + */ +int __init efi_memattr_init(void) +{ + efi_memory_attributes_table_t *tbl; + + if (efi.mem_attr_table == EFI_INVALID_TABLE_ADDR) + return 0; + + tbl = early_memremap(efi.mem_attr_table, sizeof(*tbl)); + if (!tbl) { + pr_err("Failed to map EFI Memory Attribute table @ 0x%lx\n", + efi.mem_attr_table); + return -ENOMEM; + } + + tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size; + memblock_reserve(efi.mem_attr_table, tbl_size); + early_memunmap(tbl, sizeof(*tbl)); + return 0; +} + +/* + * Returns a copy @out of the UEFI memory descriptor @in if it is covered + * entirely by a UEFI memory map entry with matching attributes. The virtual + * address of @out is set according to the matching entry that was found. + */ +static bool validate_entry(const efi_memory_desc_t *in, efi_memory_desc_t *out) +{ + u64 in_paddr = in->phys_addr; + u64 in_size = in->num_pages << EFI_PAGE_SHIFT; + efi_memory_desc_t *md; + + if (in->type != EFI_RUNTIME_SERVICES_CODE && + in->type != EFI_RUNTIME_SERVICES_DATA) { + pr_warn("MEMATTR table entry type should be RuntimeServiceCode or RuntimeServicesData\n"); + return false; + } + if (!(in->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP))) { + pr_warn("MEMATTR table entry attributes invalid: RO and XP bits both cleared\n"); + return false; + } + if (PAGE_SIZE > EFI_PAGE_SIZE && + (!PAGE_ALIGNED(in->phys_addr) || + !PAGE_ALIGNED(in->num_pages << EFI_PAGE_SHIFT))) { + pr_warn("MEMATTR table entry misaligned\n"); + return false; + } + for_each_efi_memory_desc(&memmap, md) { + u64 md_paddr = md->phys_addr; + u64 md_size = md->num_pages << EFI_PAGE_SHIFT; + + if (!(md->attribute & EFI_MEMORY_RUNTIME)) + continue; + if (md->virt_addr == 0) + /* no virtual mapping has been installed by the stub */ + break; + if (md_paddr <= in_paddr && (in_paddr - md_paddr) < md_size) { + /* + * This entry covers the start of @in, check whether + * it covers the end as well. + */ + if (md_paddr + md_size < in_paddr + in_size) { + pr_warn("MEMATTR table entry covers multiple UEFI memory map regions\n"); + return false; + } + if (md->type != in->type) { + pr_warn("MEMATTR table entry type deviates from UEFI memory map region type\n"); + return false; + } + *out = *in; + out->virt_addr = in_paddr + + (md->virt_addr - md->phys_addr); + return true; + } + } + return false; +} + +int __init efi_memattr_apply_permissions(struct mm_struct *mm, + efi_memattr_perm_setter fn) +{ + efi_memory_attributes_table_t *tbl; + int i, ret; + + if (tbl_size <= sizeof(*tbl)) + return 0; + + tbl = memremap(efi.mem_attr_table, tbl_size, MEMREMAP_WB); + if (!tbl) { + pr_err("Failed to map EFI Memory Attribute table @ 0x%lx\n", + efi.mem_attr_table); + return -ENOMEM; + } + + if (efi_enabled(EFI_DBG)) + pr_info("Processing UEFI Memory Attributes table:\n"); + + for (i = ret = 0; ret == 0 && i < tbl->num_entries; i++) { + efi_memory_desc_t md; + unsigned long size; + bool valid; + char buf[64]; + + valid = validate_entry((void *)tbl->entry + i * tbl->desc_size, + &md); + size = md.num_pages << EFI_PAGE_SHIFT; + if (efi_enabled(EFI_DBG) || !valid) + pr_info(" 0x%012llx-0x%012llx %s\n", md.phys_addr, + md.phys_addr + size - 1, + efi_md_typeattr_format(buf, sizeof(buf), &md)); + + if (valid) + ret = fn(mm, &md); + } + memunmap(tbl); + return ret; +} diff --git a/include/linux/efi.h b/include/linux/efi.h index 808d97299c70..94e41872e5e6 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -966,6 +966,12 @@ extern void __init efi_fake_memmap(void); static inline void efi_fake_memmap(void) { } #endif +typedef int (*efi_memattr_perm_setter)(struct mm_struct *, efi_memory_desc_t *); + +extern int efi_memattr_init(void); +extern int efi_memattr_apply_permissions(struct mm_struct *mm, + efi_memattr_perm_setter fn); + /* Iterate through an efi_memory_map */ #define for_each_efi_memory_desc(m, md) \ for ((md) = (m)->map; \