From patchwork Sun Oct 2 09:56:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 611928 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 029BDC433FE for ; Sun, 2 Oct 2022 09:56:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229500AbiJBJ4m (ORCPT ); Sun, 2 Oct 2022 05:56:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48876 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229458AbiJBJ4l (ORCPT ); Sun, 2 Oct 2022 05:56:41 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E95032409F for ; Sun, 2 Oct 2022 02:56:39 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 70A2460EA6 for ; Sun, 2 Oct 2022 09:56:39 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 99CEFC433D7; Sun, 2 Oct 2022 09:56:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1664704598; bh=lpQ4+WmITmtmOnKFnxuwxQHGwlCFJ4zTtvospQM9GKk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=u75V4g0DaCA0ZQDJyuudL0J6EFnCEVUdstGm9JIJ8+8/bo6JA2B8PIvyXoOX8/Qaz AqZLqOlFoTNZ9lEyARC2NMC2meCMsnddw32aGqID86u4rY+pnQsR9zn/YZn+za7Yak hsLQxoo+S0DkynDmIJbMsZDmYz4C6sK5vZcSaubpeT57g+18nMkQuQcKdiycn6NS5w sR3XMwywW2gTcPJ1QsFZzxmiiL035nOOau/JoCE0zU41hZxxiyf8olX9yEQHoCljY/ ArHOoEtzIlCx410w7dZksLlUzN19E5vFGi9MRC3HHTytmhIaFwf1KqxhZPnssjhw0C CEX+v95o9W59g== From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: xen-devel@lists.xenproject.org, Ard Biesheuvel , Demi Marie Obenour , Peter Jones , Juergen Gross , Stefano Stabellini , Oleksandr Tyshchenko , Kees Cook , Anton Vorontsov , Colin Cross , Tony Luck , =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= Subject: [RFC PATCH 1/5] efi: Move EFI fake memmap support into x86 arch tree Date: Sun, 2 Oct 2022 11:56:22 +0200 Message-Id: <20221002095626.484279-2-ardb@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221002095626.484279-1-ardb@kernel.org> References: <20221002095626.484279-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=11648; i=ardb@kernel.org; h=from:subject; bh=lpQ4+WmITmtmOnKFnxuwxQHGwlCFJ4zTtvospQM9GKk=; b=owEB7QES/pANAwAKAcNPIjmS2Y8kAcsmYgBjOWA8zvxr8yONNNbEpLG35L+GKpYlawmf5lOH3UFh k0+XysqJAbMEAAEKAB0WIQT72WJ8QGnJQhU3VynDTyI5ktmPJAUCYzlgPAAKCRDDTyI5ktmPJHYaDA CRLj6/2ttCOAAK4GTtMzxeOtLDKOJFAVwaYboNA2SQYX1qMGjuRiSvqojDy9pdF/R2PSMfaLmujBG4 fgQl9zJoPjcdeC1T/S6aFhzAIAkLZEAUnl+zXy2BwAPDeFc5pDVBxDcChOtGagbTd7pwuKWTQn3Vub nXcsrE5HRxjO4Q+NnZkN/Gb6Y2E3uddNEjXq+Oy8cxgdP+avcw/7GsU9KXc8nErIDkSmASjXCgpgxf bs1/QzX8+Bp0c7e6S7iU1g99Ji1OaDAz8wKxkZZ9TiNbwyVakn4TXRQp8MViBUAKQPj0i6EBrr50/l hfLu49cGYMC40JfTfGiA2LhHRNU3Pc6y4KPOK0ELP1EQXTM3wRys8J9axZ1bVOhd3IOJMRITiQSWyP jto7fbaG8fltwSIpO3q1pCQTRjroXNSiNeNhwjlgNI591kEz3JmvSl04qwnwC4pYVCqEPsSfPxUZ7P Wqc/BvKHiiMh350PPaQFHMMhXHEUwKfJ+r5VGXlDDtWf8= X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org The EFI fake memmap support is specific to x86, which manipulates the EFI memory map in various different ways after receiving it from the EFI stub. On other architectures, we have manages to push back on this, and the EFI memory map is kept pristine. So let's move the fake memmap code into the x86 arch tree, where it arguably belongs. Signed-off-by: Ard Biesheuvel --- arch/x86/Kconfig | 20 +++++ arch/x86/include/asm/efi.h | 5 ++ arch/x86/kernel/setup.c | 1 + arch/x86/platform/efi/Makefile | 1 + {drivers/firmware => arch/x86/platform}/efi/fake_mem.c | 79 +++++++++++++++++++- drivers/firmware/efi/Kconfig | 22 ------ drivers/firmware/efi/Makefile | 4 - drivers/firmware/efi/fake_mem.h | 10 --- drivers/firmware/efi/x86_fake_mem.c | 75 ------------------- include/linux/efi.h | 6 -- 10 files changed, 103 insertions(+), 120 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f9920f1341c8..b98941c2fec4 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1978,6 +1978,26 @@ config EFI_MIXED If unsure, say N. +config EFI_FAKE_MEMMAP + bool "Enable EFI fake memory map" + depends on EFI + help + Saying Y here will enable "efi_fake_mem" boot option. By specifying + this parameter, you can add arbitrary attribute to specific memory + range by updating original (firmware provided) EFI memmap. This is + useful for debugging of EFI memmap related feature, e.g., Address + Range Mirroring feature. + +config EFI_MAX_FAKE_MEM + int "maximum allowable number of ranges in efi_fake_mem boot option" + depends on EFI_FAKE_MEMMAP + range 1 128 + default 8 + help + Maximum allowable number of ranges in efi_fake_mem boot option. + Ranges can be set up to this value using comma-separated list. + The default value is 8. + source "kernel/Kconfig.hz" config KEXEC diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 897ea4aec16e..68414d924332 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -404,10 +404,15 @@ static inline void efi_reserve_boot_services(void) #ifdef CONFIG_EFI_FAKE_MEMMAP extern void __init efi_fake_memmap_early(void); +extern void __init efi_fake_memmap(void); #else static inline void efi_fake_memmap_early(void) { } + +static inline void efi_fake_memmap(void) +{ +} #endif #define arch_ima_efi_boot_mode \ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 216fee7144ee..41ec3a69f3c7 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile index a50245157685..b481719b16cc 100644 --- a/arch/x86/platform/efi/Makefile +++ b/arch/x86/platform/efi/Makefile @@ -4,3 +4,4 @@ GCOV_PROFILE := n obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o +obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o diff --git a/drivers/firmware/efi/fake_mem.c b/arch/x86/platform/efi/fake_mem.c similarity index 58% rename from drivers/firmware/efi/fake_mem.c rename to arch/x86/platform/efi/fake_mem.c index 6e0f34a38171..41d57cad3d84 100644 --- a/drivers/firmware/efi/fake_mem.c +++ b/arch/x86/platform/efi/fake_mem.c @@ -17,10 +17,13 @@ #include #include #include -#include "fake_mem.h" +#include +#include -struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM]; -int nr_fake_mem; +#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM + +static struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM]; +static int nr_fake_mem; static int __init cmp_fake_mem(const void *x1, const void *x2) { @@ -122,3 +125,73 @@ static int __init setup_fake_mem(char *p) } early_param("efi_fake_mem", setup_fake_mem); + +void __init efi_fake_memmap_early(void) +{ + int i; + + /* + * The late efi_fake_mem() call can handle all requests if + * EFI_MEMORY_SP support is disabled. + */ + if (!efi_soft_reserve_enabled()) + return; + + if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem) + return; + + /* + * Given that efi_fake_memmap() needs to perform memblock + * allocations it needs to run after e820__memblock_setup(). + * However, if efi_fake_mem specifies EFI_MEMORY_SP for a given + * address range that potentially needs to mark the memory as + * reserved prior to e820__memblock_setup(). Update e820 + * directly if EFI_MEMORY_SP is specified for an + * EFI_CONVENTIONAL_MEMORY descriptor. + */ + for (i = 0; i < nr_fake_mem; i++) { + struct efi_mem_range *mem = &efi_fake_mems[i]; + efi_memory_desc_t *md; + u64 m_start, m_end; + + if ((mem->attribute & EFI_MEMORY_SP) == 0) + continue; + + m_start = mem->range.start; + m_end = mem->range.end; + for_each_efi_memory_desc(md) { + u64 start, end, size; + + if (md->type != EFI_CONVENTIONAL_MEMORY) + continue; + + start = md->phys_addr; + end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; + + if (m_start <= end && m_end >= start) + /* fake range overlaps descriptor */; + else + continue; + + /* + * Trim the boundary of the e820 update to the + * descriptor in case the fake range overlaps + * !EFI_CONVENTIONAL_MEMORY + */ + start = max(start, m_start); + end = min(end, m_end); + size = end - start + 1; + + if (end <= start) + continue; + + /* + * Ensure each efi_fake_mem instance results in + * a unique e820 resource + */ + e820__range_remove(start, size, E820_TYPE_RAM, 1); + e820__range_add(start, size, E820_TYPE_SOFT_RESERVED); + e820__update_table(e820_table); + } + } +} diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 4f7e65293297..fceeea74522e 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -37,28 +37,6 @@ config EFI_RUNTIME_MAP See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map. -config EFI_FAKE_MEMMAP - bool "Enable EFI fake memory map" - depends on EFI && X86 - default n - help - Saying Y here will enable "efi_fake_mem" boot option. - By specifying this parameter, you can add arbitrary attribute - to specific memory range by updating original (firmware provided) - EFI memmap. - This is useful for debugging of EFI memmap related feature. - e.g. Address Range Mirroring feature. - -config EFI_MAX_FAKE_MEM - int "maximum allowable number of ranges in efi_fake_mem boot option" - depends on EFI_FAKE_MEMMAP - range 1 128 - default 8 - help - Maximum allowable number of ranges in efi_fake_mem boot option. - Ranges can be set up to this value using comma-separated list. - The default value is 8. - config EFI_SOFT_RESERVE bool "Reserve EFI Specific Purpose Memory" depends on EFI && EFI_STUB && ACPI_HMAT diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 8d151e332584..8e4f0d5b26e5 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_UEFI_CPER) += cper.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o subdir-$(CONFIG_EFI_STUB) += libstub -obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_map.o obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o obj-$(CONFIG_EFI_TEST) += test/ obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o @@ -32,9 +31,6 @@ obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += embedded-firmware.o obj-$(CONFIG_LOAD_UEFI_KEYS) += mokvar-table.o -fake_map-y += fake_mem.o -fake_map-$(CONFIG_X86) += x86_fake_mem.o - obj-$(CONFIG_SYSFB) += sysfb_efi.o arm-obj-$(CONFIG_EFI) := efi-init.o arm-runtime.o diff --git a/drivers/firmware/efi/fake_mem.h b/drivers/firmware/efi/fake_mem.h deleted file mode 100644 index d52791af4b18..000000000000 --- a/drivers/firmware/efi/fake_mem.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __EFI_FAKE_MEM_H__ -#define __EFI_FAKE_MEM_H__ -#include - -#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM - -extern struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM]; -extern int nr_fake_mem; -#endif /* __EFI_FAKE_MEM_H__ */ diff --git a/drivers/firmware/efi/x86_fake_mem.c b/drivers/firmware/efi/x86_fake_mem.c deleted file mode 100644 index 0bafcc1bb0f6..000000000000 --- a/drivers/firmware/efi/x86_fake_mem.c +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright(c) 2019 Intel Corporation. All rights reserved. */ -#include -#include -#include "fake_mem.h" - -void __init efi_fake_memmap_early(void) -{ - int i; - - /* - * The late efi_fake_mem() call can handle all requests if - * EFI_MEMORY_SP support is disabled. - */ - if (!efi_soft_reserve_enabled()) - return; - - if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem) - return; - - /* - * Given that efi_fake_memmap() needs to perform memblock - * allocations it needs to run after e820__memblock_setup(). - * However, if efi_fake_mem specifies EFI_MEMORY_SP for a given - * address range that potentially needs to mark the memory as - * reserved prior to e820__memblock_setup(). Update e820 - * directly if EFI_MEMORY_SP is specified for an - * EFI_CONVENTIONAL_MEMORY descriptor. - */ - for (i = 0; i < nr_fake_mem; i++) { - struct efi_mem_range *mem = &efi_fake_mems[i]; - efi_memory_desc_t *md; - u64 m_start, m_end; - - if ((mem->attribute & EFI_MEMORY_SP) == 0) - continue; - - m_start = mem->range.start; - m_end = mem->range.end; - for_each_efi_memory_desc(md) { - u64 start, end, size; - - if (md->type != EFI_CONVENTIONAL_MEMORY) - continue; - - start = md->phys_addr; - end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; - - if (m_start <= end && m_end >= start) - /* fake range overlaps descriptor */; - else - continue; - - /* - * Trim the boundary of the e820 update to the - * descriptor in case the fake range overlaps - * !EFI_CONVENTIONAL_MEMORY - */ - start = max(start, m_start); - end = min(end, m_end); - size = end - start + 1; - - if (end <= start) - continue; - - /* - * Ensure each efi_fake_mem instance results in - * a unique e820 resource - */ - e820__range_remove(start, size, E820_TYPE_RAM, 1); - e820__range_add(start, size, E820_TYPE_SOFT_RESERVED); - e820__update_table(e820_table); - } - } -} diff --git a/include/linux/efi.h b/include/linux/efi.h index e739196ce9b2..a6dbf354d2c3 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -749,12 +749,6 @@ extern struct kobject *efi_kobj; extern int efi_reboot_quirk_mode; extern bool efi_poweroff_required(void); -#ifdef CONFIG_EFI_FAKE_MEMMAP -extern void __init efi_fake_memmap(void); -#else -static inline void efi_fake_memmap(void) { } -#endif - extern unsigned long efi_mem_attr_table; /* From patchwork Sun Oct 2 09:56:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 612411 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4445CC433FE for ; Sun, 2 Oct 2022 09:56:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229458AbiJBJ4r (ORCPT ); Sun, 2 Oct 2022 05:56:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49002 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229482AbiJBJ4q (ORCPT ); Sun, 2 Oct 2022 05:56:46 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 38D3223161 for ; Sun, 2 Oct 2022 02:56:45 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id C5DEFB80C02 for ; Sun, 2 Oct 2022 09:56:43 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5F739C43470; Sun, 2 Oct 2022 09:56:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1664704602; bh=ZjDr14OxWTrew0/fwyFI+XUBboCoGDstHicLfif2Djw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SYAbnexg2vVB1Ubx7iKWwvKipe8jqzlVNJ59mTk5OZatQLacV3nQAPuUtC3nOR8V4 lhVyVnKERtFuuR/QgAHyPQFv2prWZCGYPy/aW3ThLPGroBdPEV516wv0chfYbcL+9T 3uMAyrpHceKOBPN7vQnetNsCyf0xRXCQjghdCzcKIbtwAba3HDxFX4JoXxYSr4t6uS PTzNhrkeiDP0/naziDCGJY/igr9pBlEqHrsg25jpVzlDszKtQBn3M4pTBzhc0DzQMb tMBCz4HvJVm3wKhYCJjAVoFsK5v+lCrcvaEJFPGUuVIw2LBZ4KWk363H3t8rS4WKJt CZ5cIx7kRubOg== From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: xen-devel@lists.xenproject.org, Ard Biesheuvel , Demi Marie Obenour , Peter Jones , Juergen Gross , Stefano Stabellini , Oleksandr Tyshchenko , Kees Cook , Anton Vorontsov , Colin Cross , Tony Luck , =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= Subject: [RFC PATCH 2/5] efi: memmap: Move manipulation routines into x86 arch tree Date: Sun, 2 Oct 2022 11:56:23 +0200 Message-Id: <20221002095626.484279-3-ardb@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221002095626.484279-1-ardb@kernel.org> References: <20221002095626.484279-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=17368; i=ardb@kernel.org; h=from:subject; bh=ZjDr14OxWTrew0/fwyFI+XUBboCoGDstHicLfif2Djw=; b=owEB7QES/pANAwAKAcNPIjmS2Y8kAcsmYgBjOWA/g6dqX0FgOlAp0B3+vbe93/8K1X6EJXBcxSer Yrj6+geJAbMEAAEKAB0WIQT72WJ8QGnJQhU3VynDTyI5ktmPJAUCYzlgPwAKCRDDTyI5ktmPJJnxC/ 0aACTxYmvHXRsjsJaqZYZRSmDe67wHbWOwyECaskr/J9cKGuY17WqaCXdDQoQI2Nsx1aZrjDp9rTXt ZFWlax5/HUP4ux2eN+zaqI+fW6SLYFHS4T29ql7PxKsEmd7QE31YwtvyXuV8JPj/awOGjNerkNFZu+ 4A0bq0Ya6LOJ14dO38rHyCl4qJlXkbprtM5D+yJEPYFf4oIRmpad2mVjpVfO6IA7FdYegXzG09APsI oKxZIX9HSKDmOMBdf4hlecFu+GXONuyFvNdxckwgoTesiyhs4jWLApd5iNCtf63di381AWtNEraHTJ h/TPAF692y5o/m5l8MFTXqXxFY1sYTmXkcFmil/3iE1tauQlQIBPjy0GWLMFw1BJb8R+1oUJgoE/oz ZT1JIElQYeGTlJEdKj+LGPv7sOsrz071FJRSgAIIEayMEv88BbZ3/TY2VsYtQibH1LAeYJ9me3vZU5 ZbI8zMyeOJ6UZzCn1KozadsjsJrWaTX1XaAL2zJifvhhA= X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org The EFI memory map is a description of the memory layout as provided by the firmware, and only x86 manipulates it in various different ways for its own memory bookkeeping. So let's move the memmap routines that are only used by x86 into the x86 arch tree. Signed-off-by: Ard Biesheuvel --- arch/x86/include/asm/efi.h | 11 + arch/x86/platform/efi/Makefile | 3 +- arch/x86/platform/efi/memmap.c | 235 ++++++++++++++++++++ drivers/firmware/efi/memmap.c | 221 +----------------- include/linux/efi.h | 10 +- 5 files changed, 251 insertions(+), 229 deletions(-) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 68414d924332..1fb4686f3d12 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -415,6 +415,17 @@ static inline void efi_fake_memmap(void) } #endif +extern int __init efi_memmap_alloc(unsigned int num_entries, + struct efi_memory_map_data *data); +extern void __efi_memmap_free(u64 phys, unsigned long size, + unsigned long flags); + +extern int __init efi_memmap_install(struct efi_memory_map_data *data); +extern int __init efi_memmap_split_count(efi_memory_desc_t *md, + struct range *range); +extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap, + void *buf, struct efi_mem_range *mem); + #define arch_ima_efi_boot_mode \ ({ extern struct boot_params boot_params; boot_params.secure_boot; }) diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile index b481719b16cc..ed5502a5185d 100644 --- a/arch/x86/platform/efi/Makefile +++ b/arch/x86/platform/efi/Makefile @@ -2,6 +2,7 @@ KASAN_SANITIZE := n GCOV_PROFILE := n -obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o +obj-$(CONFIG_EFI) += memmap.o quirks.o efi.o efi_$(BITS).o \ + efi_stub_$(BITS).o obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o diff --git a/arch/x86/platform/efi/memmap.c b/arch/x86/platform/efi/memmap.c new file mode 100644 index 000000000000..44b886acf301 --- /dev/null +++ b/arch/x86/platform/efi/memmap.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Common EFI memory map functions. + */ + +#define pr_fmt(fmt) "efi: " fmt + +#include +#include +#include +#include +#include +#include +#include + +static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size) +{ + return memblock_phys_alloc(size, SMP_CACHE_BYTES); +} + +static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size) +{ + unsigned int order = get_order(size); + struct page *p = alloc_pages(GFP_KERNEL, order); + + if (!p) + return 0; + + return PFN_PHYS(page_to_pfn(p)); +} + +void __init __efi_memmap_free(u64 phys, unsigned long size, unsigned long flags) +{ + if (flags & EFI_MEMMAP_MEMBLOCK) { + if (slab_is_available()) + memblock_free_late(phys, size); + else + memblock_phys_free(phys, size); + } else if (flags & EFI_MEMMAP_SLAB) { + struct page *p = pfn_to_page(PHYS_PFN(phys)); + unsigned int order = get_order(size); + + free_pages((unsigned long) page_address(p), order); + } +} + +/** + * efi_memmap_alloc - Allocate memory for the EFI memory map + * @num_entries: Number of entries in the allocated map. + * @data: efi memmap installation parameters + * + * Depending on whether mm_init() has already been invoked or not, + * either memblock or "normal" page allocation is used. + * + * Returns zero on success, a negative error code on failure. + */ +int __init efi_memmap_alloc(unsigned int num_entries, + struct efi_memory_map_data *data) +{ + /* Expect allocation parameters are zero initialized */ + WARN_ON(data->phys_map || data->size); + + data->size = num_entries * efi.memmap.desc_size; + data->desc_version = efi.memmap.desc_version; + data->desc_size = efi.memmap.desc_size; + data->flags &= ~(EFI_MEMMAP_SLAB | EFI_MEMMAP_MEMBLOCK); + data->flags |= efi.memmap.flags & EFI_MEMMAP_LATE; + + if (slab_is_available()) { + data->flags |= EFI_MEMMAP_SLAB; + data->phys_map = __efi_memmap_alloc_late(data->size); + } else { + data->flags |= EFI_MEMMAP_MEMBLOCK; + data->phys_map = __efi_memmap_alloc_early(data->size); + } + + if (!data->phys_map) + return -ENOMEM; + return 0; +} + +/** + * efi_memmap_install - Install a new EFI memory map in efi.memmap + * @ctx: map allocation parameters (address, size, flags) + * + * Unlike efi_memmap_init_*(), this function does not allow the caller + * to switch from early to late mappings. It simply uses the existing + * mapping function and installs the new memmap. + * + * Returns zero on success, a negative error code on failure. + */ +int __init efi_memmap_install(struct efi_memory_map_data *data) +{ + efi_memmap_unmap(); + + return __efi_memmap_init(data); +} + +/** + * efi_memmap_split_count - Count number of additional EFI memmap entries + * @md: EFI memory descriptor to split + * @range: Address range (start, end) to split around + * + * Returns the number of additional EFI memmap entries required to + * accommodate @range. + */ +int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range) +{ + u64 m_start, m_end; + u64 start, end; + int count = 0; + + start = md->phys_addr; + end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1; + + /* modifying range */ + m_start = range->start; + m_end = range->end; + + if (m_start <= start) { + /* split into 2 parts */ + if (start < m_end && m_end < end) + count++; + } + + if (start < m_start && m_start < end) { + /* split into 3 parts */ + if (m_end < end) + count += 2; + /* split into 2 parts */ + if (end <= m_end) + count++; + } + + return count; +} + +/** + * efi_memmap_insert - Insert a memory region in an EFI memmap + * @old_memmap: The existing EFI memory map structure + * @buf: Address of buffer to store new map + * @mem: Memory map entry to insert + * + * It is suggested that you call efi_memmap_split_count() first + * to see how large @buf needs to be. + */ +void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf, + struct efi_mem_range *mem) +{ + u64 m_start, m_end, m_attr; + efi_memory_desc_t *md; + u64 start, end; + void *old, *new; + + /* modifying range */ + m_start = mem->range.start; + m_end = mem->range.end; + m_attr = mem->attribute; + + /* + * The EFI memory map deals with regions in EFI_PAGE_SIZE + * units. Ensure that the region described by 'mem' is aligned + * correctly. + */ + if (!IS_ALIGNED(m_start, EFI_PAGE_SIZE) || + !IS_ALIGNED(m_end + 1, EFI_PAGE_SIZE)) { + WARN_ON(1); + return; + } + + for (old = old_memmap->map, new = buf; + old < old_memmap->map_end; + old += old_memmap->desc_size, new += old_memmap->desc_size) { + + /* copy original EFI memory descriptor */ + memcpy(new, old, old_memmap->desc_size); + md = new; + start = md->phys_addr; + end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; + + if (m_start <= start && end <= m_end) + md->attribute |= m_attr; + + if (m_start <= start && + (start < m_end && m_end < end)) { + /* first part */ + md->attribute |= m_attr; + md->num_pages = (m_end - md->phys_addr + 1) >> + EFI_PAGE_SHIFT; + /* latter part */ + new += old_memmap->desc_size; + memcpy(new, old, old_memmap->desc_size); + md = new; + md->phys_addr = m_end + 1; + md->num_pages = (end - md->phys_addr + 1) >> + EFI_PAGE_SHIFT; + } + + if ((start < m_start && m_start < end) && m_end < end) { + /* first part */ + md->num_pages = (m_start - md->phys_addr) >> + EFI_PAGE_SHIFT; + /* middle part */ + new += old_memmap->desc_size; + memcpy(new, old, old_memmap->desc_size); + md = new; + md->attribute |= m_attr; + md->phys_addr = m_start; + md->num_pages = (m_end - m_start + 1) >> + EFI_PAGE_SHIFT; + /* last part */ + new += old_memmap->desc_size; + memcpy(new, old, old_memmap->desc_size); + md = new; + md->phys_addr = m_end + 1; + md->num_pages = (end - m_end) >> + EFI_PAGE_SHIFT; + } + + if ((start < m_start && m_start < end) && + (end <= m_end)) { + /* first part */ + md->num_pages = (m_start - md->phys_addr) >> + EFI_PAGE_SHIFT; + /* latter part */ + new += old_memmap->desc_size; + memcpy(new, old, old_memmap->desc_size); + md = new; + md->phys_addr = m_start; + md->num_pages = (end - md->phys_addr + 1) >> + EFI_PAGE_SHIFT; + md->attribute |= m_attr; + } + } +} diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c index 6ec7970dbd40..3501d3814f22 100644 --- a/drivers/firmware/efi/memmap.c +++ b/drivers/firmware/efi/memmap.c @@ -13,35 +13,8 @@ #include #include -static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size) +void __weak __efi_memmap_free(u64 phys, unsigned long size, unsigned long flags) { - return memblock_phys_alloc(size, SMP_CACHE_BYTES); -} - -static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size) -{ - unsigned int order = get_order(size); - struct page *p = alloc_pages(GFP_KERNEL, order); - - if (!p) - return 0; - - return PFN_PHYS(page_to_pfn(p)); -} - -void __init __efi_memmap_free(u64 phys, unsigned long size, unsigned long flags) -{ - if (flags & EFI_MEMMAP_MEMBLOCK) { - if (slab_is_available()) - memblock_free_late(phys, size); - else - memblock_phys_free(phys, size); - } else if (flags & EFI_MEMMAP_SLAB) { - struct page *p = pfn_to_page(PHYS_PFN(phys)); - unsigned int order = get_order(size); - - free_pages((unsigned long) page_address(p), order); - } } static void __init efi_memmap_free(void) @@ -51,41 +24,6 @@ static void __init efi_memmap_free(void) efi.memmap.flags); } -/** - * efi_memmap_alloc - Allocate memory for the EFI memory map - * @num_entries: Number of entries in the allocated map. - * @data: efi memmap installation parameters - * - * Depending on whether mm_init() has already been invoked or not, - * either memblock or "normal" page allocation is used. - * - * Returns zero on success, a negative error code on failure. - */ -int __init efi_memmap_alloc(unsigned int num_entries, - struct efi_memory_map_data *data) -{ - /* Expect allocation parameters are zero initialized */ - WARN_ON(data->phys_map || data->size); - - data->size = num_entries * efi.memmap.desc_size; - data->desc_version = efi.memmap.desc_version; - data->desc_size = efi.memmap.desc_size; - data->flags &= ~(EFI_MEMMAP_SLAB | EFI_MEMMAP_MEMBLOCK); - data->flags |= efi.memmap.flags & EFI_MEMMAP_LATE; - - if (slab_is_available()) { - data->flags |= EFI_MEMMAP_SLAB; - data->phys_map = __efi_memmap_alloc_late(data->size); - } else { - data->flags |= EFI_MEMMAP_MEMBLOCK; - data->phys_map = __efi_memmap_alloc_early(data->size); - } - - if (!data->phys_map) - return -ENOMEM; - return 0; -} - /** * __efi_memmap_init - Common code for mapping the EFI memory map * @data: EFI memory map data @@ -101,7 +39,7 @@ int __init efi_memmap_alloc(unsigned int num_entries, * * Returns zero on success, a negative error code on failure. */ -static int __init __efi_memmap_init(struct efi_memory_map_data *data) +int __init __efi_memmap_init(struct efi_memory_map_data *data) { struct efi_memory_map map; phys_addr_t phys_map; @@ -220,158 +158,3 @@ int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size) return __efi_memmap_init(&data); } - -/** - * efi_memmap_install - Install a new EFI memory map in efi.memmap - * @ctx: map allocation parameters (address, size, flags) - * - * Unlike efi_memmap_init_*(), this function does not allow the caller - * to switch from early to late mappings. It simply uses the existing - * mapping function and installs the new memmap. - * - * Returns zero on success, a negative error code on failure. - */ -int __init efi_memmap_install(struct efi_memory_map_data *data) -{ - efi_memmap_unmap(); - - return __efi_memmap_init(data); -} - -/** - * efi_memmap_split_count - Count number of additional EFI memmap entries - * @md: EFI memory descriptor to split - * @range: Address range (start, end) to split around - * - * Returns the number of additional EFI memmap entries required to - * accommodate @range. - */ -int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range) -{ - u64 m_start, m_end; - u64 start, end; - int count = 0; - - start = md->phys_addr; - end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1; - - /* modifying range */ - m_start = range->start; - m_end = range->end; - - if (m_start <= start) { - /* split into 2 parts */ - if (start < m_end && m_end < end) - count++; - } - - if (start < m_start && m_start < end) { - /* split into 3 parts */ - if (m_end < end) - count += 2; - /* split into 2 parts */ - if (end <= m_end) - count++; - } - - return count; -} - -/** - * efi_memmap_insert - Insert a memory region in an EFI memmap - * @old_memmap: The existing EFI memory map structure - * @buf: Address of buffer to store new map - * @mem: Memory map entry to insert - * - * It is suggested that you call efi_memmap_split_count() first - * to see how large @buf needs to be. - */ -void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf, - struct efi_mem_range *mem) -{ - u64 m_start, m_end, m_attr; - efi_memory_desc_t *md; - u64 start, end; - void *old, *new; - - /* modifying range */ - m_start = mem->range.start; - m_end = mem->range.end; - m_attr = mem->attribute; - - /* - * The EFI memory map deals with regions in EFI_PAGE_SIZE - * units. Ensure that the region described by 'mem' is aligned - * correctly. - */ - if (!IS_ALIGNED(m_start, EFI_PAGE_SIZE) || - !IS_ALIGNED(m_end + 1, EFI_PAGE_SIZE)) { - WARN_ON(1); - return; - } - - for (old = old_memmap->map, new = buf; - old < old_memmap->map_end; - old += old_memmap->desc_size, new += old_memmap->desc_size) { - - /* copy original EFI memory descriptor */ - memcpy(new, old, old_memmap->desc_size); - md = new; - start = md->phys_addr; - end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; - - if (m_start <= start && end <= m_end) - md->attribute |= m_attr; - - if (m_start <= start && - (start < m_end && m_end < end)) { - /* first part */ - md->attribute |= m_attr; - md->num_pages = (m_end - md->phys_addr + 1) >> - EFI_PAGE_SHIFT; - /* latter part */ - new += old_memmap->desc_size; - memcpy(new, old, old_memmap->desc_size); - md = new; - md->phys_addr = m_end + 1; - md->num_pages = (end - md->phys_addr + 1) >> - EFI_PAGE_SHIFT; - } - - if ((start < m_start && m_start < end) && m_end < end) { - /* first part */ - md->num_pages = (m_start - md->phys_addr) >> - EFI_PAGE_SHIFT; - /* middle part */ - new += old_memmap->desc_size; - memcpy(new, old, old_memmap->desc_size); - md = new; - md->attribute |= m_attr; - md->phys_addr = m_start; - md->num_pages = (m_end - m_start + 1) >> - EFI_PAGE_SHIFT; - /* last part */ - new += old_memmap->desc_size; - memcpy(new, old, old_memmap->desc_size); - md = new; - md->phys_addr = m_end + 1; - md->num_pages = (end - m_end) >> - EFI_PAGE_SHIFT; - } - - if ((start < m_start && m_start < end) && - (end <= m_end)) { - /* first part */ - md->num_pages = (m_start - md->phys_addr) >> - EFI_PAGE_SHIFT; - /* latter part */ - new += old_memmap->desc_size; - memcpy(new, old, old_memmap->desc_size); - md = new; - md->phys_addr = m_start; - md->num_pages = (end - md->phys_addr + 1) >> - EFI_PAGE_SHIFT; - md->attribute |= m_attr; - } - } -} diff --git a/include/linux/efi.h b/include/linux/efi.h index a6dbf354d2c3..256e70e42114 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -707,18 +707,10 @@ static inline efi_status_t efi_query_variable_store(u32 attributes, #endif extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr); -extern int __init efi_memmap_alloc(unsigned int num_entries, - struct efi_memory_map_data *data); -extern void __efi_memmap_free(u64 phys, unsigned long size, - unsigned long flags); +extern int __init __efi_memmap_init(struct efi_memory_map_data *data); extern int __init efi_memmap_init_early(struct efi_memory_map_data *data); extern int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size); extern void __init efi_memmap_unmap(void); -extern int __init efi_memmap_install(struct efi_memory_map_data *data); -extern int __init efi_memmap_split_count(efi_memory_desc_t *md, - struct range *range); -extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap, - void *buf, struct efi_mem_range *mem); #ifdef CONFIG_EFI_ESRT extern void __init efi_esrt_init(void); From patchwork Sun Oct 2 09:56:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 611927 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AE292C433F5 for ; Sun, 2 Oct 2022 09:56:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229592AbiJBJ4s (ORCPT ); Sun, 2 Oct 2022 05:56:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49036 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229517AbiJBJ4r (ORCPT ); Sun, 2 Oct 2022 05:56:47 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 09FCE36858 for ; Sun, 2 Oct 2022 02:56:47 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 9DB0E60EA2 for ; Sun, 2 Oct 2022 09:56:46 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 15F90C433D6; Sun, 2 Oct 2022 09:56:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1664704606; bh=naWVhxVJzgFHTYyzbP8aferDZudNO8L5WZJcvq28kz8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HJMy/vz6C1WPkgKcpbpoO/EQRrz6yAjgPpzrVFvMZ+walD/yM0Y0/LdUToEzYOP3e wUcz8Fmrta2nkGJSkkaAMVqgSnRvfmZmPgOh64OvJXPY22FVdCh2GBjdhDG4v1U+V+ TaUklRaC8k0+i0H9PXGPupfBhktKg1OYLU/ocnnKIjMY9R8buaQcGOij3ETjE9/2Qt oY5U6tIueXURJFbXveR38cWmsqyll1PJbi+gTNKBGbJahbxp1vFmCekLGFIeShpnXs 8e6DpsKFM2Oa/iyyEWtIilU9DcihAXqFelN6xor9DoI0MdNoHBhhhwi5wcZdRq3AZU 1VazOsR6kr94g== From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: xen-devel@lists.xenproject.org, Ard Biesheuvel , Demi Marie Obenour , Peter Jones , Juergen Gross , Stefano Stabellini , Oleksandr Tyshchenko , Kees Cook , Anton Vorontsov , Colin Cross , Tony Luck , =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= Subject: [RFC PATCH 3/5] efi: xen: Set EFI_PARAVIRT for Xen dom0 boot on all architectures Date: Sun, 2 Oct 2022 11:56:24 +0200 Message-Id: <20221002095626.484279-4-ardb@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221002095626.484279-1-ardb@kernel.org> References: <20221002095626.484279-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3190; i=ardb@kernel.org; h=from:subject; bh=naWVhxVJzgFHTYyzbP8aferDZudNO8L5WZJcvq28kz8=; b=owEB7QES/pANAwAKAcNPIjmS2Y8kAcsmYgBjOWBBUImNh+oNISz7kaell7P1ADDK/YsLUV10IJbU Cm3Ms7iJAbMEAAEKAB0WIQT72WJ8QGnJQhU3VynDTyI5ktmPJAUCYzlgQQAKCRDDTyI5ktmPJL+CDA CI6goexpgFxPze+H/P1pGk+2TCSeapYidebHraqvYuivMVNgqTUEXJD0MTuefrzj2RYWLr8Z8Nl5F/ NW37j0Kc7I7UDApHt22+UHn2mgOpMu69tN7r+1EKj5j1AH7GTJ8RfzfLxMrKqPkr9JP4TAlfMSq6wr 2H4u2aITOj9clf0ga9hYyBm3uEKdK9sPATjTKKCKtknjUMPT5fp6mmrNw1qR2ZnWh/sAUexJ/eRIeH QlUEGEHPOPeWmBtJQC+QkGKRNKPT5186B/uDeeHtlgPnKDvLlKZF99n8nyHceFjUn6T8s/S7CFJUQ3 vQz7ohfix1KUdhAZ+b7u+2BJ11t4BiTfRE84Mrq9+xxPvMVwTBfEdkrc1qGDRIaHbQCkVSZOCKhYPo 5UvNVhJFzkfY/qc+sCyiEjw3IIkG2fYKSZyzeuDaM0lR1ukIud+LEqEodpxUEcEs+cEQcW2XGgl9yB nqsQmxUsIhyvMWKdmMgVeTi9+JDpm2Qczoo9bNk+ZQh4Y= X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org Currently, the EFI_PARAVIRT flag is only used by x86, even though other architectures also support pseudo-EFI boot, where the core kernel is invoked directly and provided with a set of data tables that resemble the ones constructed by the EFI stub, which never actually runs in that case. Let's fix this inconsistency, and always set this flag when booting dom0 via the EFI boot path. Note that Xen on x86 does not provide the EFI memory map in this case, whereas other architectures do, so move the associated EFI_PARAVIRT check into the x86 platform code. Signed-off-by: Ard Biesheuvel --- arch/x86/platform/efi/efi.c | 8 +++++--- arch/x86/platform/efi/memmap.c | 3 +++ drivers/firmware/efi/fdtparams.c | 4 ++++ drivers/firmware/efi/memmap.c | 3 --- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 6e598bd78eef..6a6f2a585a3d 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -214,9 +214,11 @@ int __init efi_memblock_x86_reserve_range(void) data.desc_size = e->efi_memdesc_size; data.desc_version = e->efi_memdesc_version; - rv = efi_memmap_init_early(&data); - if (rv) - return rv; + if (!efi_enabled(EFI_PARAVIRT)) { + rv = efi_memmap_init_early(&data); + if (rv) + return rv; + } if (add_efi_memmap || do_efi_soft_reserve()) do_add_efi_memmap(); diff --git a/arch/x86/platform/efi/memmap.c b/arch/x86/platform/efi/memmap.c index 44b886acf301..18e14ec16720 100644 --- a/arch/x86/platform/efi/memmap.c +++ b/arch/x86/platform/efi/memmap.c @@ -93,6 +93,9 @@ int __init efi_memmap_install(struct efi_memory_map_data *data) { efi_memmap_unmap(); + if (efi_enabled(EFI_PARAVIRT)) + return 0; + return __efi_memmap_init(data); } diff --git a/drivers/firmware/efi/fdtparams.c b/drivers/firmware/efi/fdtparams.c index e901f8564ca0..0ec83ba58097 100644 --- a/drivers/firmware/efi/fdtparams.c +++ b/drivers/firmware/efi/fdtparams.c @@ -30,11 +30,13 @@ static __initconst const char name[][22] = { static __initconst const struct { const char path[17]; + u8 paravirt; const char params[PARAMCOUNT][26]; } dt_params[] = { { #ifdef CONFIG_XEN // <-------17------> .path = "/hypervisor/uefi", + .paravirt = 1, .params = { [SYSTAB] = "xen,uefi-system-table", [MMBASE] = "xen,uefi-mmap-start", @@ -121,6 +123,8 @@ u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm) pr_err("Can't find property '%s' in DT!\n", pname); return 0; } + if (dt_params[i].paravirt) + set_bit(EFI_PARAVIRT, &efi.flags); return systab; } notfound: diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c index 3501d3814f22..9508082af907 100644 --- a/drivers/firmware/efi/memmap.c +++ b/drivers/firmware/efi/memmap.c @@ -44,9 +44,6 @@ int __init __efi_memmap_init(struct efi_memory_map_data *data) struct efi_memory_map map; phys_addr_t phys_map; - if (efi_enabled(EFI_PARAVIRT)) - return 0; - phys_map = data->phys_map; if (data->flags & EFI_MEMMAP_LATE) From patchwork Sun Oct 2 09:56:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 612410 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8987C433FE for ; Sun, 2 Oct 2022 09:56:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229482AbiJBJ4v (ORCPT ); Sun, 2 Oct 2022 05:56:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49132 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229517AbiJBJ4v (ORCPT ); Sun, 2 Oct 2022 05:56:51 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 70A032409F for ; Sun, 2 Oct 2022 02:56:50 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 1197F60EA7 for ; Sun, 2 Oct 2022 09:56:50 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 832B8C4347C; Sun, 2 Oct 2022 09:56:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1664704609; bh=kklnL55pKWR1vQ/19hTjFP18KyqfhrdVX1+/k9SG5KE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=u30qGzyh+tD3uTA+5MwooaeSIG3R7K46GLISQHthQk0IPFp6wFEREKYfV4cAwZH4l 29tBU8c+/EzhtdSavIkJUuL0yjTYoXoUcSIu11EcnRwAN2YvaCI+Q9KN9yPubwXNVc hH/2WplQPMDx8Kv6+oWcSd8JH3LbkW0DGUiiiicysD15n2DWcO4YnBcL9oGqGqot3j 5SkWHBdHp1RWCWp+6O5NeWcP4KAIJiTffms0EEkZ/LLK9ZF+4SeWW0GpXzszzSMt4E n95nzqAy4sZimgR0qgb/cOd/54zjc2W5Gx209+l6ID9r+QsAhyawmZNFhDrHUqL/PC 7UA5fBTSYWyJg== From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: xen-devel@lists.xenproject.org, Ard Biesheuvel , Demi Marie Obenour , Peter Jones , Juergen Gross , Stefano Stabellini , Oleksandr Tyshchenko , Kees Cook , Anton Vorontsov , Colin Cross , Tony Luck , =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= Subject: [RFC PATCH 4/5] efi: Apply allowlist to EFI configuration tables when running under Xen Date: Sun, 2 Oct 2022 11:56:25 +0200 Message-Id: <20221002095626.484279-5-ardb@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221002095626.484279-1-ardb@kernel.org> References: <20221002095626.484279-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=4992; i=ardb@kernel.org; h=from:subject; bh=kklnL55pKWR1vQ/19hTjFP18KyqfhrdVX1+/k9SG5KE=; b=owEB7QES/pANAwAKAcNPIjmS2Y8kAcsmYgBjOWBDcjLC/XtL6TWD7SlqFc53BFZWSGH0tWLY5HiL Of+IqTeJAbMEAAEKAB0WIQT72WJ8QGnJQhU3VynDTyI5ktmPJAUCYzlgQwAKCRDDTyI5ktmPJBG+C/ 9n9inwyfpMFqxsvtl0IevAjclopZMTaAwU+rafEbqvQ2K9fxsY6k4Tuzs9y0I6HVaTCKQ+/e83E8Ut oQkrveg0sb6Etbd7qZ98homL8bG2F3tJcTXv/BXpl2FIhx2E7vgjTbYE5ixklJl/55Ix+0YyrwzOmj lms21xFGzlJqVG6QHauTZwp/lUHBFtsm/xApqCGl1U67X6M2WQayQ32iAGd2FKTcUjNpPmJ7dgUgV8 nQhD7d3tfyIUbyVlaXXdhwDbTqcFQFBC+8/IiO3y+PHfRtNlO2ow6r5l0YanlRBGTGSpDIpJNRcxuH +SXQs51/NIH8jSMDlx22/tQfTnUDh70rVwpuE0ymR4Hwydyh6Jt44AdNAK/ydXbAiPx22IwrigbRQG EDzCdjUdg5RvyYLAiSuqmNyxdAtslbqqiFHmEUNQXvFvtsDsUu2r+6Jn96kUMuCcYe94+YOgRUqE5c 8VancdiCM4aEwcFqGq9gsv/K8byblK2VJNzOvn19NodFQ= X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org As it turns out, Xen does not guarantee that EFI bootservices data regions in memory are preserved, which means that EFI configuration tables pointing into such memory regions may be corrupted before the dom0 OS has had a chance to inspect them. Demi Marie reports that this is causing problems for Qubes OS when it attempts to perform system firmware updates, which requires that the contents of the ESRT configuration table are valid when the fwupd user space program runs. However, other configuration tables such as the memory attributes table or the runtime properties table are equally affected, and so we need a comprehensive workaround that works for any table type. So let's first disregard all EFI configuration tables except the ones that are known (or can be expected) to reside in memory regions of a type that Xen preserves, i.e., ACPI tables (which are passed in EfiAcpiReclaimMemory regions) and SMBIOS tables (which are usually passed in EfiRuntimeServicesData regions, even though the UEFI spec only mentions this as a recommendation). Then, cross reference unknown tables against either the EFI memory map (if available) or do a Xen hypercall to determine the memory type, and allow the config table if the type is one that is guaranteed to be preserved. Future patches can augment the logic in this routine to allow other table types based on the size of the allocation, or based on a table specific header size field. Co-developed-by: Demi Marie Obenour Signed-off-by: Demi Marie Obenour Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/efi.c | 7 ++ drivers/xen/efi.c | 69 ++++++++++++++++++++ include/linux/efi.h | 2 + 3 files changed, 78 insertions(+) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 11857af72859..e8c0747011d7 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -556,6 +556,13 @@ static __init int match_config_table(const efi_guid_t *guid, for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) { if (!efi_guidcmp(*guid, table_types[i].guid)) { + if (IS_ENABLED(CONFIG_XEN_EFI) && + !xen_efi_config_table_is_usable(guid, table)) { + if (table_types[i].name[0]) + pr_cont("(%s=0x%lx) ", + table_types[i].name, table); + return 1; + } *(table_types[i].ptr) = table; if (table_types[i].name[0]) pr_cont("%s=0x%lx ", diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c index d1ff2186ebb4..3f1f365b37d0 100644 --- a/drivers/xen/efi.c +++ b/drivers/xen/efi.c @@ -292,3 +292,72 @@ void __init xen_efi_runtime_setup(void) efi.get_next_high_mono_count = xen_efi_get_next_high_mono_count; efi.reset_system = xen_efi_reset_system; } + +static const efi_guid_t cfg_table_allow_list[] __initconst = { + ACPI_20_TABLE_GUID, + ACPI_TABLE_GUID, + SMBIOS_TABLE_GUID, + SMBIOS3_TABLE_GUID, +}; + +bool __init xen_efi_config_table_is_usable(const efi_guid_t *guid, + unsigned long table) +{ + u32 memtype; + int i, rc; + + if (!efi_enabled(EFI_PARAVIRT)) + return true; + + for (i = 0; i < ARRAY_SIZE(cfg_table_allow_list); i++) { + if (!efi_guidcmp(*guid, cfg_table_allow_list[i])) + return true; + } + + if (efi_enabled(EFI_MEMMAP)) { + /* check against the EFI memory map */ + efi_memory_desc_t md; + + rc = efi_mem_desc_lookup(table, &md); + if (rc) { + pr_warn("Failed to lookup header 0x%lx in EFI memory map (%d)\n", + table, rc); + return false; + } + memtype = md.type; + } else { + /* check against the Xen hypercall */ + struct xen_platform_op op = { + .cmd = XENPF_firmware_info, + .u.firmware_info = { + .type = XEN_FW_EFI_INFO, + .index = XEN_FW_EFI_MEM_INFO, + .u.efi_info.mem.addr = table, + .u.efi_info.mem.size = U64_MAX - table, + } + }; + union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info; + + rc = HYPERVISOR_platform_op(&op); + if (rc) { + pr_warn("Failed to lookup header 0x%lx in Xen memory map (%d)\n", + table, rc); + return false; + } + memtype = info->mem.type; + } + + switch (memtype) { + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_ACPI_RECLAIM_MEMORY: + case EFI_RESERVED_TYPE: + return true; + case EFI_BOOT_SERVICES_DATA: + break; + default: + return false; + } + + return false; +} diff --git a/include/linux/efi.h b/include/linux/efi.h index 256e70e42114..6edc627798b6 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1351,4 +1351,6 @@ struct linux_efi_initrd { /* Header of a populated EFI secret area */ #define EFI_SECRET_TABLE_HEADER_GUID EFI_GUID(0x1e74f542, 0x71dd, 0x4d66, 0x96, 0x3e, 0xef, 0x42, 0x87, 0xff, 0x17, 0x3b) +bool xen_efi_config_table_is_usable(const efi_guid_t *, unsigned long table); + #endif /* _LINUX_EFI_H */ From patchwork Sun Oct 2 09:56:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 611926 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 72FA4C43219 for ; Sun, 2 Oct 2022 09:56:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229594AbiJBJ45 (ORCPT ); Sun, 2 Oct 2022 05:56:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49162 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229517AbiJBJ44 (ORCPT ); Sun, 2 Oct 2022 05:56:56 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8EA222409F for ; Sun, 2 Oct 2022 02:56:55 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 4D1BBB80D1A for ; Sun, 2 Oct 2022 09:56:54 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 030F7C433D6; Sun, 2 Oct 2022 09:56:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1664704613; bh=i9J/bhcOyc3uNnBq9NxPgkx0ZJaejS+t55ZIN9kwhto=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lZZQATYJk3ivDIqSahLAWOXxDG540XSQg4SOZtKoDcInYHh5WAIvtQ708cDyde62y qFcJoIpjQKJhjdEr2eKLrqneN9dxTRKeluZC1+osIcRdGYu6bpOar8CPXS63b7QZ0I +t3NvNXP6iJNDe9PTzQMhuatCVpMQNvX0WmZcZiifFHPenOOUfGYFr5Pm4vaJE5xaX tiqgBusQE4dcXX+IK74AtS1ovjH6syVgbox8r0Aoh44N36UvpuyCEsT0/GwjDuaTsg hoAxaFqgIJOVnDfMXTxZWzPMVwxzpsrzfQg5J17/FA+QnqhkMIYJmMJlEuemLiYTU/ sTEBGyK60tsYg== From: Ard Biesheuvel To: linux-efi@vger.kernel.org Cc: xen-devel@lists.xenproject.org, Ard Biesheuvel , Demi Marie Obenour , Peter Jones , Juergen Gross , Stefano Stabellini , Oleksandr Tyshchenko , Kees Cook , Anton Vorontsov , Colin Cross , Tony Luck , =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= Subject: [RFC PATCH 5/5] efi: esrt: Omit region sanity check when no memory map is available Date: Sun, 2 Oct 2022 11:56:26 +0200 Message-Id: <20221002095626.484279-6-ardb@kernel.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221002095626.484279-1-ardb@kernel.org> References: <20221002095626.484279-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3849; i=ardb@kernel.org; h=from:subject; bh=i9J/bhcOyc3uNnBq9NxPgkx0ZJaejS+t55ZIN9kwhto=; b=owEB7QES/pANAwAKAcNPIjmS2Y8kAcsmYgBjOWBG4cz437cHlvB5hCAVDNcjf0OGuWo2clK4E5EB xJGhzOeJAbMEAAEKAB0WIQT72WJ8QGnJQhU3VynDTyI5ktmPJAUCYzlgRgAKCRDDTyI5ktmPJGICDA CiILORMzCoGuRyx58JurLNRhBnK5oQH+9xzw8gRRd+Vz3g6c3EKvPNk1k5x/NyZiqptY5b/6kkST0z L3hL8qwjhwFvSm+hK8lb11IHTiOu5W3BLWF4tN3i1+n/y4mJo0NtJUAFwMt1dVCJH31hZFqNAJ8NQ/ svEJL86U6S+8AQbXU/v1TMcjV7C4Bf3uPyjg7L6HaCBwiREnJ8QlZ06QYWieJ4VZQUnS2l7eV6Z30f dlpPBhWgtaarwosLJ8Hd/FOw0nudZB3/c0Pma8xBvF58WeRddf/URLRL/KZ3OEwWcwddlmZdz4jHZa 6SI8cTLmCQpjeEvYZ8FJVyTQoI6El+Pt94uuWwnQIcpQjqeQD4/20RKdAxmOseZfoWRajOLTBeJgdH ppCdmUvll+/kB0Kl2bY+2FWH8d2E1jcLHeqXrFGUFZeP1eNzkJsiGE7f3iF2vXdIq5T65oGQGMTU+Q YCpsZXqv93o6Ztb2Cid6MB1cAtrtmds7CWvHCe2Je4z1k= X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org In order to permit the ESRT to be used when doing pseudo-EFI boot without a EFI memory map, e.g., when booting inside a Xen dom0 on x86, make the sanity checks optional based on whether the memory map is available. If additional validation is needed, it is up to the Xen EFI glue code to implement this in its xen_efi_config_table_is_valid() helper, or provide a EFI memory map like it does on other architectures. Co-developed-by: Demi Marie Obenour Signed-off-by: Demi Marie Obenour Signed-off-by: Ard Biesheuvel --- arch/x86/platform/efi/quirks.c | 3 + drivers/firmware/efi/esrt.c | 61 +++++++++++--------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index b0b848d6933a..9307be2f4afa 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -250,6 +250,9 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) int num_entries; void *new; + if (!efi_enabled(EFI_MEMMAP)) + return; + if (efi_mem_desc_lookup(addr, &md) || md.type != EFI_BOOT_SERVICES_DATA) { pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr); diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index 2a2f52b017e7..adb31fba45ae 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -243,40 +243,45 @@ void __init efi_esrt_init(void) void *va; struct efi_system_resource_table tmpesrt; size_t size, max, entry_size, entries_size; - efi_memory_desc_t md; - int rc; + bool reserve_esrt; phys_addr_t end; - if (!efi_enabled(EFI_MEMMAP)) - return; - pr_debug("esrt-init: loading.\n"); if (!esrt_table_exists()) return; - rc = efi_mem_desc_lookup(efi.esrt, &md); - if (rc < 0 || - (!(md.attribute & EFI_MEMORY_RUNTIME) && - md.type != EFI_BOOT_SERVICES_DATA && - md.type != EFI_RUNTIME_SERVICES_DATA)) { - pr_warn("ESRT header is not in the memory map.\n"); - return; - } + size = sizeof(*esrt); + if (efi_enabled(EFI_MEMMAP)) { + efi_memory_desc_t md; + int rc; + + rc = efi_mem_desc_lookup(efi.esrt, &md); + if (rc < 0 || + (!(md.attribute & EFI_MEMORY_RUNTIME) && + md.type != EFI_BOOT_SERVICES_DATA && + md.type != EFI_RUNTIME_SERVICES_DATA)) { + pr_warn("ESRT header is not in the memory map.\n"); + return; + } - max = efi_mem_desc_end(&md); - if (max < efi.esrt) { - pr_err("EFI memory descriptor is invalid. (esrt: %p max: %p)\n", - (void *)efi.esrt, (void *)max); - return; - } + reserve_esrt = (md.type == EFI_BOOT_SERVICES_DATA); + max = efi_mem_desc_end(&md); + if (max < efi.esrt) { + pr_err("EFI memory descriptor is invalid. (esrt: %p max: %p)\n", + (void *)efi.esrt, (void *)max); + return; + } - size = sizeof(*esrt); - max -= efi.esrt; + max -= efi.esrt; - if (max < size) { - pr_err("ESRT header doesn't fit on single memory map entry. (size: %zu max: %zu)\n", - size, max); - return; + if (max < size) { + pr_err("ESRT header doesn't fit on single memory map entry. (size: %zu max: %zu)\n", + size, max); + return; + } + } else { + reserve_esrt = true; + max = SIZE_MAX; } va = early_memremap(efi.esrt, size); @@ -332,9 +337,11 @@ void __init efi_esrt_init(void) esrt_data_size = size; end = esrt_data + size; - pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end); - if (md.type == EFI_BOOT_SERVICES_DATA) + if (reserve_esrt) { + pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, + &end); efi_mem_reserve(esrt_data, esrt_data_size); + } pr_debug("esrt-init: loaded.\n"); }