All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] efi: Permanent runtime EFI memmap support
@ 2016-06-23 11:34 Matt Fleming
  2016-06-23 11:34 ` [PATCH 01/11] x86/efi: Test for EFI_MEMMAP functionality when iterating EFI memmap Matt Fleming
                   ` (11 more replies)
  0 siblings, 12 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Andy Lutomirski,
	Borislav Petkov, Josh Boyer, Josh Triplett, Kamezawa Hiroyuki,
	Leif Lindholm, Mark Rutland, Môshe van der Sterre,
	Peter Jones, Taku Izumi, Tony Luck, Xishi Qiu

This series adds support for keeping the EFI memory map around at
runtime for x86 (ARM and arm64 already have this support).

Additionally, drivers can now reserve EFI boot services regions such
that they are not released back to the kernel during
efi_free_boot_services().

With these two features it becomes possible to pass things like the
EFI System Resource Table data structures across kexec reboot.

This series also includes a whole bunch of refactoring and cleanups to
move code out of arch or driver-specific files into generic places.

I've given these patches some light testing, but it would be good if
others could provide more given that this series touches so many
different code paths.

ARM/arm64 folks, you're going to want to pay particular attention to
PATCH 3 where I drop the read-only mapping of the EFI memory map since
it causes problems for x86.

I am aware that we leak memory maps when new ones get installed, e.g.
during __efi_enter_virtual_mode(), but that's an existing bug that
requires everyone to allocate memory maps the same way before it can
be fixed.

 arch/x86/include/asm/efi.h         |   1 -
 arch/x86/kernel/setup.c            |  13 +-
 arch/x86/platform/efi/efi-bgrt.c   |  13 +-
 arch/x86/platform/efi/efi.c        | 198 ++++++++++++-------------
 arch/x86/platform/efi/efi_64.c     |  20 ---
 arch/x86/platform/efi/quirks.c     | 123 ++++++++++++++--
 drivers/firmware/efi/Makefile      |   2 +-
 drivers/firmware/efi/arm-init.c    |  17 +--
 drivers/firmware/efi/arm-runtime.c |   4 +-
 drivers/firmware/efi/efi.c         |  64 ++++----
 drivers/firmware/efi/esrt.c        |  20 +--
 drivers/firmware/efi/fake_mem.c    | 125 ++--------------
 drivers/firmware/efi/memmap.c      | 292 +++++++++++++++++++++++++++++++++++++
 drivers/firmware/efi/runtime-map.c |  35 ++---
 include/linux/efi.h                |  34 ++++-
 15 files changed, 605 insertions(+), 356 deletions(-)
 create mode 100644 drivers/firmware/efi/memmap.c

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 01/11] x86/efi: Test for EFI_MEMMAP functionality when iterating EFI memmap
  2016-06-23 11:34 [PATCH 00/11] efi: Permanent runtime EFI memmap support Matt Fleming
@ 2016-06-23 11:34 ` Matt Fleming
  2016-06-23 11:34 ` [PATCH 02/11] x86/efi: Consolidate region mapping logic Matt Fleming
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Taku Izumi, Tony Luck,
	Xishi Qiu, Kamezawa Hiroyuki

Both efi_find_mirror() and efi_fake_memmap() really want to know
whether the EFI memory map is available, not just whether the machine
was booted using EFI. efi_fake_memmap() even has a check for
EFI_MEMMAP at the start of the function.

Since we've already got other code that has this dependency, merge
everything under one if() conditional, and remove the now superfluous
check from efi_fake_memmap().

Cc: Taku Izumi <izumi.taku@jp.fujitsu.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Xishi Qiu <qiuxishi@huawei.com>
Cc: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 arch/x86/kernel/setup.c         | 13 ++++++-------
 drivers/firmware/efi/fake_mem.c |  2 +-
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index c4e7b3991b60..1867fa8ff75e 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1096,17 +1096,16 @@ void __init setup_arch(char **cmdline_p)
 	memblock_set_current_limit(ISA_END_ADDRESS);
 	memblock_x86_fill();
 
-	if (efi_enabled(EFI_BOOT)) {
+	if (efi_enabled(EFI_MEMMAP)) {
 		efi_fake_memmap();
 		efi_find_mirror();
-	}
 
-	/*
-	 * The EFI specification says that boot service code won't be called
-	 * after ExitBootServices(). This is, in fact, a lie.
-	 */
-	if (efi_enabled(EFI_MEMMAP))
+		/*
+		 * The EFI specification says that boot service code won't be
+		 * called after ExitBootServices(). This is, in fact, a lie.
+		 */
 		efi_reserve_boot_services();
+	}
 
 	/* preallocate 4k for mptable mpc */
 	early_reserve_e820_mpc_new();
diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index 48430aba13c1..c437388a7b85 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -64,7 +64,7 @@ void __init efi_fake_memmap(void)
 	void *old, *new;
 	int i;
 
-	if (!nr_fake_mem || !efi_enabled(EFI_MEMMAP))
+	if (!nr_fake_mem)
 		return;
 
 	/* count up the number of EFI memory descriptor */
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 02/11] x86/efi: Consolidate region mapping logic
  2016-06-23 11:34 [PATCH 00/11] efi: Permanent runtime EFI memmap support Matt Fleming
  2016-06-23 11:34 ` [PATCH 01/11] x86/efi: Test for EFI_MEMMAP functionality when iterating EFI memmap Matt Fleming
@ 2016-06-23 11:34 ` Matt Fleming
  2016-06-23 14:00   ` Borislav Petkov
  2016-06-23 11:34   ` Matt Fleming
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Borislav Petkov

EFI regions are currently mapped in two separate places. The bulk of
the work is done in efi_map_regions() but when CONFIG_EFI_MIXED is
enabled the additional regions that are required when operating in
mixed mode are mapping in efi_setup_page_tables().

Pull everything into efi_map_regions() and refactor the test for
which regions should be mapped into a should_map_region() function.
Generously sprinkle comments to clarify the different cases.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Borislav Petkov <bp@alien8.de>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 arch/x86/platform/efi/efi.c    | 50 ++++++++++++++++++++++++++++++++++++------
 arch/x86/platform/efi/efi_64.c | 20 -----------------
 2 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index f93545e7dc54..7c3d9092c668 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -761,6 +761,46 @@ static void *efi_map_next_entry(void *entry)
 	return entry;
 }
 
+static bool should_map_region(efi_memory_desc_t *md)
+{
+	/*
+	 * Runtime regions always require runtime mappings (obviously).
+	 */
+	if (md->attribute & EFI_MEMORY_RUNTIME)
+		return true;
+
+	/*
+	 * 32-bit EFI doesn't suffer from the bug that requires us to
+	 * reserve boot services regions, and mixed mode support
+	 * doesn't exist for 32-bit kernels.
+	 */
+	if (IS_ENABLED(CONFIG_X86_32))
+		return false;
+
+	/*
+	 * Map all of RAM so that we can access arguments in the 1:1
+	 * mapping when making EFI runtime calls.
+	 */
+	if (IS_ENABLED(CONFIG_EFI_MIXED) && !efi_is_native()) {
+		if (md->type == EFI_CONVENTIONAL_MEMORY ||
+		    md->type == EFI_LOADER_DATA ||
+		    md->type == EFI_LOADER_CODE)
+			return true;
+	}
+
+	/*
+	 * Map boot services regions as a workaround for buggy
+	 * firmware that accesses them even when they shouldn't.
+	 *
+	 * See efi_{reserve,free}_boot_services().
+	 */
+	if (md->type == EFI_BOOT_SERVICES_CODE ||
+	    md->type == EFI_BOOT_SERVICES_DATA)
+		return true;
+
+	return false;
+}
+
 /*
  * Map the efi memory ranges of the runtime services and update new_mmap with
  * virtual addresses.
@@ -777,13 +817,9 @@ static void * __init efi_map_regions(int *count, int *pg_shift)
 	p = NULL;
 	while ((p = efi_map_next_entry(p))) {
 		md = p;
-		if (!(md->attribute & EFI_MEMORY_RUNTIME)) {
-#ifdef CONFIG_X86_64
-			if (md->type != EFI_BOOT_SERVICES_CODE &&
-			    md->type != EFI_BOOT_SERVICES_DATA)
-#endif
-				continue;
-		}
+
+		if (!should_map_region(md))
+			continue;
 
 		efi_map_region(md);
 		get_systab_virt_addr(md);
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 6e7242be1c87..3fcdfc93991e 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -213,7 +213,6 @@ void efi_sync_low_kernel_mappings(void)
 int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
 {
 	unsigned long pfn, text;
-	efi_memory_desc_t *md;
 	struct page *page;
 	unsigned npages;
 	pgd_t *pgd;
@@ -247,25 +246,6 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
 	if (!IS_ENABLED(CONFIG_EFI_MIXED))
 		return 0;
 
-	/*
-	 * Map all of RAM so that we can access arguments in the 1:1
-	 * mapping when making EFI runtime calls.
-	 */
-	for_each_efi_memory_desc(md) {
-		if (md->type != EFI_CONVENTIONAL_MEMORY &&
-		    md->type != EFI_LOADER_DATA &&
-		    md->type != EFI_LOADER_CODE)
-			continue;
-
-		pfn = md->phys_addr >> PAGE_SHIFT;
-		npages = md->num_pages;
-
-		if (kernel_map_pages_in_pgd(pgd, pfn, md->phys_addr, npages, _PAGE_RW)) {
-			pr_err("Failed to map 1:1 memory\n");
-			return 1;
-		}
-	}
-
 	page = alloc_page(GFP_KERNEL|__GFP_DMA32);
 	if (!page)
 		panic("Unable to allocate EFI runtime stack < 4GB\n");
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code
@ 2016-06-23 11:34   ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland

Every EFI architecture apart from ia64 needs to setup the EFI memory
map at efi.memmap, and the code for doing that is essentially the same
across all implementations. Therefore, it makes sense to factor this
out into the common code under drivers/firmware/efi/.

The only slight variation is the data structure out of which we pull
the initial memory map information, such as physical address, memory
descriptor size and version, etc. We can address this by passing a
generic data structure (struct efi_memory_map_data) as the argument to
efi_memmap_init_early() which contains the minimum info required for
initialising the memory map.

In the process, this patch also fixes a few undesirable implementation
differences:

 - ARM and arm64 were failing to clear the EFI_MEMMAP bit when
   unmapping the early EFI memory map. EFI_MEMMAP indicates whether
   the EFI memory map is mapped (not the regions contained within) and
   can be traversed.  It's more correct to set the bit as soon as we
   memremap() the passed in EFI memmap.

 - Rename efi_unmmap_memmap() to efi_memmap_unmap() to adhere to the
   regular naming scheme.

This patch also uses a read-write mapping for the memory map instead
of the read-only mapping currently used on ARM and arm64. x86 needs
the ability to update the memory map in-place when assigning virtual
addresses to regions (efi_map_region()) and tagging regions when
reserving boot services (efi_reserve_boot_services()).

There's no way for the generic fake_mem code to know which mapping to
use without introducing some arch-specific constant/hook, so just use
read-write since read-only is of dubious value for the EFI memory map.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 arch/x86/include/asm/efi.h      |  1 -
 arch/x86/platform/efi/efi.c     | 66 +++++++++++------------------------------
 arch/x86/platform/efi/quirks.c  |  4 +--
 drivers/firmware/efi/arm-init.c | 17 +++++------
 drivers/firmware/efi/efi.c      | 46 ++++++++++++++++++++++++++++
 drivers/firmware/efi/fake_mem.c | 15 ++++++----
 include/linux/efi.h             | 16 ++++++++++
 7 files changed, 98 insertions(+), 67 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 78d1e7467eae..67983035bd7b 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -118,7 +118,6 @@ extern int __init efi_memblock_x86_reserve_range(void);
 extern pgd_t * __init efi_call_phys_prolog(void);
 extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
 extern void __init efi_print_memmap(void);
-extern void __init efi_unmap_memmap(void);
 extern void __init efi_memory_uc(u64 addr, unsigned long size);
 extern void __init efi_map_region(efi_memory_desc_t *md);
 extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 7c3d9092c668..b434c887229c 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -188,7 +188,9 @@ static void __init do_add_efi_memmap(void)
 int __init efi_memblock_x86_reserve_range(void)
 {
 	struct efi_info *e = &boot_params.efi_info;
+	struct efi_memory_map_data data;
 	phys_addr_t pmap;
+	int rv;
 
 	if (efi_enabled(EFI_PARAVIRT))
 		return 0;
@@ -203,11 +205,17 @@ int __init efi_memblock_x86_reserve_range(void)
 #else
 	pmap = (e->efi_memmap |	((__u64)e->efi_memmap_hi << 32));
 #endif
-	efi.memmap.phys_map	= pmap;
-	efi.memmap.nr_map	= e->efi_memmap_size /
-				  e->efi_memdesc_size;
-	efi.memmap.desc_size	= e->efi_memdesc_size;
-	efi.memmap.desc_version	= e->efi_memdesc_version;
+	data.phys_map		= pmap;
+	data.size 		= e->efi_memmap_size;
+	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 (add_efi_memmap)
+		do_add_efi_memmap();
 
 	WARN(efi.memmap.desc_version != 1,
 	     "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
@@ -234,19 +242,6 @@ void __init efi_print_memmap(void)
 	}
 }
 
-void __init efi_unmap_memmap(void)
-{
-	unsigned long size;
-
-	clear_bit(EFI_MEMMAP, &efi.flags);
-
-	size = efi.memmap.nr_map * efi.memmap.desc_size;
-	if (efi.memmap.map) {
-		early_memunmap(efi.memmap.map, size);
-		efi.memmap.map = NULL;
-	}
-}
-
 static int __init efi_systab_init(void *phys)
 {
 	if (efi_enabled(EFI_64BIT)) {
@@ -430,33 +425,6 @@ static int __init efi_runtime_init(void)
 	return 0;
 }
 
-static int __init efi_memmap_init(void)
-{
-	unsigned long addr, size;
-
-	if (efi_enabled(EFI_PARAVIRT))
-		return 0;
-
-	/* Map the EFI memory map */
-	size = efi.memmap.nr_map * efi.memmap.desc_size;
-	addr = (unsigned long)efi.memmap.phys_map;
-
-	efi.memmap.map = early_memremap(addr, size);
-	if (efi.memmap.map == NULL) {
-		pr_err("Could not map the memory map!\n");
-		return -ENOMEM;
-	}
-
-	efi.memmap.map_end = efi.memmap.map + size;
-
-	if (add_efi_memmap)
-		do_add_efi_memmap();
-
-	set_bit(EFI_MEMMAP, &efi.flags);
-
-	return 0;
-}
-
 void __init efi_init(void)
 {
 	efi_char16_t *c16;
@@ -514,11 +482,11 @@ void __init efi_init(void)
 	if (!efi_runtime_supported())
 		pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
 	else {
-		if (efi_runtime_disabled() || efi_runtime_init())
+		if (efi_runtime_disabled() || efi_runtime_init()) {
+			efi_memmap_unmap();
 			return;
+		}
 	}
-	if (efi_memmap_init())
-		return;
 
 	if (efi_enabled(EFI_DBG))
 		efi_print_memmap();
@@ -855,7 +823,7 @@ static void __init kexec_enter_virtual_mode(void)
 	 * non-native EFI
 	 */
 	if (!efi_is_native()) {
-		efi_unmap_memmap();
+		efi_memmap_unmap();
 		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 		return;
 	}
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 4480c06cade7..0af180004e74 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -266,7 +266,7 @@ void __init efi_free_boot_services(void)
 		free_bootmem_late(start, size);
 	}
 
-	efi_unmap_memmap();
+	efi_memmap_unmap();
 }
 
 /*
@@ -344,7 +344,7 @@ void __init efi_apply_memmap_quirks(void)
 	 */
 	if (!efi_runtime_supported()) {
 		pr_info("Setup done, disabling due to 32/64-bit mismatch\n");
-		efi_unmap_memmap();
+		efi_memmap_unmap();
 	}
 
 	/* UV2+ BIOS has a fix for this issue.  UV1 still needs the quirk. */
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
index c49d50e68aee..5a2df3fefccc 100644
--- a/drivers/firmware/efi/arm-init.c
+++ b/drivers/firmware/efi/arm-init.c
@@ -211,12 +211,11 @@ static __init void reserve_regions(void)
 			memblock_mark_nomap(paddr, size);
 
 	}
-
-	set_bit(EFI_MEMMAP, &efi.flags);
 }
 
 void __init efi_init(void)
 {
+	struct efi_memory_map_data data;
 	struct efi_fdt_params params;
 
 	/* Grab UEFI information placed in FDT by stub */
@@ -225,9 +224,12 @@ void __init efi_init(void)
 
 	efi_system_table = params.system_table;
 
-	efi.memmap.phys_map = params.mmap;
-	efi.memmap.map = early_memremap_ro(params.mmap, params.mmap_size);
-	if (efi.memmap.map == NULL) {
+	data.desc_version = params.desc_ver;
+	data.desc_size = params.desc_size;
+	data.size = params.mmap_size;
+	data.phys_map = params.mmap;
+
+	if (efi_memmap_init_early(&data) < 0) {
 		/*
 		* If we are booting via UEFI, the UEFI memory map is the only
 		* description of memory we have, so there is little point in
@@ -235,9 +237,6 @@ void __init efi_init(void)
 		*/
 		panic("Unable to map EFI memory map.\n");
 	}
-	efi.memmap.map_end = efi.memmap.map + params.mmap_size;
-	efi.memmap.desc_size = params.desc_size;
-	efi.memmap.desc_version = params.desc_ver;
 
 	WARN(efi.memmap.desc_version != 1,
 	     "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
@@ -248,7 +247,7 @@ void __init efi_init(void)
 
 	reserve_regions();
 	efi_memattr_init();
-	early_memunmap(efi.memmap.map, params.mmap_size);
+	efi_memmap_unmap();
 
 	memblock_reserve(params.mmap & PAGE_MASK,
 			 PAGE_ALIGN(params.mmap_size +
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 05509f3aaee8..3e6dce71f54d 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -448,6 +448,52 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
 	return ret;
 }
 
+/**
+ * efi_memmap_init_early - Map the EFI memory map data structure
+ * @data: EFI memory map data
+ *
+ * Use early_memremap() to map the passed in EFI memory map and assign
+ * it to efi.memmap.
+ */
+int __init efi_memmap_init_early(struct efi_memory_map_data *data)
+{
+	struct efi_memory_map map;
+
+	if (efi_enabled(EFI_PARAVIRT))
+		return 0;
+
+	map.phys_map = data->phys_map;
+
+	map.map = early_memremap(data->phys_map, data->size);
+	if (!map.map) {
+		pr_err("Could not map the memory map!\n");
+		return -ENOMEM;
+	}
+
+	map.nr_map = data->size / data->desc_size;
+	map.map_end = map.map + data->size;
+
+	map.desc_version = data->desc_version;
+	map.desc_size = data->desc_size;
+
+	set_bit(EFI_MEMMAP, &efi.flags);
+
+	efi.memmap = map;
+
+	return 0;
+}
+
+void __init efi_memmap_unmap(void)
+{
+	unsigned long size;
+
+	size = efi.memmap.desc_size * efi.memmap.nr_map;
+
+	early_memunmap(efi.memmap.map, size);
+	efi.memmap.map = NULL;
+	clear_bit(EFI_MEMMAP, &efi.flags);
+}
+
 #ifdef CONFIG_EFI_VARS_MODULE
 static int __init efi_load_efivars(void)
 {
diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index c437388a7b85..939eec47139f 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -57,6 +57,7 @@ static int __init cmp_fake_mem(const void *x1, const void *x2)
 void __init efi_fake_memmap(void)
 {
 	u64 start, end, m_start, m_end, m_attr;
+	struct efi_memory_map_data data;
 	int new_nr_map = efi.memmap.nr_map;
 	efi_memory_desc_t *md;
 	phys_addr_t new_memmap_phy;
@@ -180,12 +181,14 @@ void __init efi_fake_memmap(void)
 	}
 
 	/* swap into new EFI memmap */
-	efi_unmap_memmap();
-	efi.memmap.map = new_memmap;
-	efi.memmap.phys_map = new_memmap_phy;
-	efi.memmap.nr_map = new_nr_map;
-	efi.memmap.map_end = efi.memmap.map + efi.memmap.nr_map * efi.memmap.desc_size;
-	set_bit(EFI_MEMMAP, &efi.flags);
+	early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
+	efi_memmap_unmap();
+
+	data.phys_map = new_memmap_phy;
+	data.size = efi.memmap.desc_size * new_nr_map;
+	data.desc_version = efi.memmap.desc_version;
+	data.desc_size = efi.memmap.desc_size;
+	efi_memmap_init_early(&data);
 
 	/* print new EFI memmap */
 	efi_print_memmap();
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 03009695760d..055fbecd3156 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -742,6 +742,18 @@ typedef struct {
 	unsigned long tables;
 } efi_system_table_t;
 
+/*
+ * Architecture independent structure for describing a memory map for the
+ * benefit of efi_memmap_init_early(), saving us the need to pass four
+ * parameters.
+ */
+struct efi_memory_map_data {
+	phys_addr_t phys_map;
+	unsigned long size;
+	unsigned long desc_version;
+	unsigned long desc_size;
+};
+
 struct efi_memory_map {
 	phys_addr_t phys_map;
 	void *map;
@@ -973,6 +985,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_init_early(struct efi_memory_map_data *data);
+extern void __init efi_memmap_unmap(void);
+
 extern int efi_config_init(efi_config_table_type_t *arch_tables);
 #ifdef CONFIG_EFI_ESRT
 extern void __init efi_esrt_init(void);
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code
@ 2016-06-23 11:34   ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland

Every EFI architecture apart from ia64 needs to setup the EFI memory
map at efi.memmap, and the code for doing that is essentially the same
across all implementations. Therefore, it makes sense to factor this
out into the common code under drivers/firmware/efi/.

The only slight variation is the data structure out of which we pull
the initial memory map information, such as physical address, memory
descriptor size and version, etc. We can address this by passing a
generic data structure (struct efi_memory_map_data) as the argument to
efi_memmap_init_early() which contains the minimum info required for
initialising the memory map.

In the process, this patch also fixes a few undesirable implementation
differences:

 - ARM and arm64 were failing to clear the EFI_MEMMAP bit when
   unmapping the early EFI memory map. EFI_MEMMAP indicates whether
   the EFI memory map is mapped (not the regions contained within) and
   can be traversed.  It's more correct to set the bit as soon as we
   memremap() the passed in EFI memmap.

 - Rename efi_unmmap_memmap() to efi_memmap_unmap() to adhere to the
   regular naming scheme.

This patch also uses a read-write mapping for the memory map instead
of the read-only mapping currently used on ARM and arm64. x86 needs
the ability to update the memory map in-place when assigning virtual
addresses to regions (efi_map_region()) and tagging regions when
reserving boot services (efi_reserve_boot_services()).

There's no way for the generic fake_mem code to know which mapping to
use without introducing some arch-specific constant/hook, so just use
read-write since read-only is of dubious value for the EFI memory map.

Cc: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Leif Lindholm <leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Borislav Petkov <bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
---
 arch/x86/include/asm/efi.h      |  1 -
 arch/x86/platform/efi/efi.c     | 66 +++++++++++------------------------------
 arch/x86/platform/efi/quirks.c  |  4 +--
 drivers/firmware/efi/arm-init.c | 17 +++++------
 drivers/firmware/efi/efi.c      | 46 ++++++++++++++++++++++++++++
 drivers/firmware/efi/fake_mem.c | 15 ++++++----
 include/linux/efi.h             | 16 ++++++++++
 7 files changed, 98 insertions(+), 67 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 78d1e7467eae..67983035bd7b 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -118,7 +118,6 @@ extern int __init efi_memblock_x86_reserve_range(void);
 extern pgd_t * __init efi_call_phys_prolog(void);
 extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
 extern void __init efi_print_memmap(void);
-extern void __init efi_unmap_memmap(void);
 extern void __init efi_memory_uc(u64 addr, unsigned long size);
 extern void __init efi_map_region(efi_memory_desc_t *md);
 extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 7c3d9092c668..b434c887229c 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -188,7 +188,9 @@ static void __init do_add_efi_memmap(void)
 int __init efi_memblock_x86_reserve_range(void)
 {
 	struct efi_info *e = &boot_params.efi_info;
+	struct efi_memory_map_data data;
 	phys_addr_t pmap;
+	int rv;
 
 	if (efi_enabled(EFI_PARAVIRT))
 		return 0;
@@ -203,11 +205,17 @@ int __init efi_memblock_x86_reserve_range(void)
 #else
 	pmap = (e->efi_memmap |	((__u64)e->efi_memmap_hi << 32));
 #endif
-	efi.memmap.phys_map	= pmap;
-	efi.memmap.nr_map	= e->efi_memmap_size /
-				  e->efi_memdesc_size;
-	efi.memmap.desc_size	= e->efi_memdesc_size;
-	efi.memmap.desc_version	= e->efi_memdesc_version;
+	data.phys_map		= pmap;
+	data.size 		= e->efi_memmap_size;
+	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 (add_efi_memmap)
+		do_add_efi_memmap();
 
 	WARN(efi.memmap.desc_version != 1,
 	     "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
@@ -234,19 +242,6 @@ void __init efi_print_memmap(void)
 	}
 }
 
-void __init efi_unmap_memmap(void)
-{
-	unsigned long size;
-
-	clear_bit(EFI_MEMMAP, &efi.flags);
-
-	size = efi.memmap.nr_map * efi.memmap.desc_size;
-	if (efi.memmap.map) {
-		early_memunmap(efi.memmap.map, size);
-		efi.memmap.map = NULL;
-	}
-}
-
 static int __init efi_systab_init(void *phys)
 {
 	if (efi_enabled(EFI_64BIT)) {
@@ -430,33 +425,6 @@ static int __init efi_runtime_init(void)
 	return 0;
 }
 
-static int __init efi_memmap_init(void)
-{
-	unsigned long addr, size;
-
-	if (efi_enabled(EFI_PARAVIRT))
-		return 0;
-
-	/* Map the EFI memory map */
-	size = efi.memmap.nr_map * efi.memmap.desc_size;
-	addr = (unsigned long)efi.memmap.phys_map;
-
-	efi.memmap.map = early_memremap(addr, size);
-	if (efi.memmap.map == NULL) {
-		pr_err("Could not map the memory map!\n");
-		return -ENOMEM;
-	}
-
-	efi.memmap.map_end = efi.memmap.map + size;
-
-	if (add_efi_memmap)
-		do_add_efi_memmap();
-
-	set_bit(EFI_MEMMAP, &efi.flags);
-
-	return 0;
-}
-
 void __init efi_init(void)
 {
 	efi_char16_t *c16;
@@ -514,11 +482,11 @@ void __init efi_init(void)
 	if (!efi_runtime_supported())
 		pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
 	else {
-		if (efi_runtime_disabled() || efi_runtime_init())
+		if (efi_runtime_disabled() || efi_runtime_init()) {
+			efi_memmap_unmap();
 			return;
+		}
 	}
-	if (efi_memmap_init())
-		return;
 
 	if (efi_enabled(EFI_DBG))
 		efi_print_memmap();
@@ -855,7 +823,7 @@ static void __init kexec_enter_virtual_mode(void)
 	 * non-native EFI
 	 */
 	if (!efi_is_native()) {
-		efi_unmap_memmap();
+		efi_memmap_unmap();
 		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 		return;
 	}
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 4480c06cade7..0af180004e74 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -266,7 +266,7 @@ void __init efi_free_boot_services(void)
 		free_bootmem_late(start, size);
 	}
 
-	efi_unmap_memmap();
+	efi_memmap_unmap();
 }
 
 /*
@@ -344,7 +344,7 @@ void __init efi_apply_memmap_quirks(void)
 	 */
 	if (!efi_runtime_supported()) {
 		pr_info("Setup done, disabling due to 32/64-bit mismatch\n");
-		efi_unmap_memmap();
+		efi_memmap_unmap();
 	}
 
 	/* UV2+ BIOS has a fix for this issue.  UV1 still needs the quirk. */
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
index c49d50e68aee..5a2df3fefccc 100644
--- a/drivers/firmware/efi/arm-init.c
+++ b/drivers/firmware/efi/arm-init.c
@@ -211,12 +211,11 @@ static __init void reserve_regions(void)
 			memblock_mark_nomap(paddr, size);
 
 	}
-
-	set_bit(EFI_MEMMAP, &efi.flags);
 }
 
 void __init efi_init(void)
 {
+	struct efi_memory_map_data data;
 	struct efi_fdt_params params;
 
 	/* Grab UEFI information placed in FDT by stub */
@@ -225,9 +224,12 @@ void __init efi_init(void)
 
 	efi_system_table = params.system_table;
 
-	efi.memmap.phys_map = params.mmap;
-	efi.memmap.map = early_memremap_ro(params.mmap, params.mmap_size);
-	if (efi.memmap.map == NULL) {
+	data.desc_version = params.desc_ver;
+	data.desc_size = params.desc_size;
+	data.size = params.mmap_size;
+	data.phys_map = params.mmap;
+
+	if (efi_memmap_init_early(&data) < 0) {
 		/*
 		* If we are booting via UEFI, the UEFI memory map is the only
 		* description of memory we have, so there is little point in
@@ -235,9 +237,6 @@ void __init efi_init(void)
 		*/
 		panic("Unable to map EFI memory map.\n");
 	}
-	efi.memmap.map_end = efi.memmap.map + params.mmap_size;
-	efi.memmap.desc_size = params.desc_size;
-	efi.memmap.desc_version = params.desc_ver;
 
 	WARN(efi.memmap.desc_version != 1,
 	     "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
@@ -248,7 +247,7 @@ void __init efi_init(void)
 
 	reserve_regions();
 	efi_memattr_init();
-	early_memunmap(efi.memmap.map, params.mmap_size);
+	efi_memmap_unmap();
 
 	memblock_reserve(params.mmap & PAGE_MASK,
 			 PAGE_ALIGN(params.mmap_size +
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 05509f3aaee8..3e6dce71f54d 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -448,6 +448,52 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
 	return ret;
 }
 
+/**
+ * efi_memmap_init_early - Map the EFI memory map data structure
+ * @data: EFI memory map data
+ *
+ * Use early_memremap() to map the passed in EFI memory map and assign
+ * it to efi.memmap.
+ */
+int __init efi_memmap_init_early(struct efi_memory_map_data *data)
+{
+	struct efi_memory_map map;
+
+	if (efi_enabled(EFI_PARAVIRT))
+		return 0;
+
+	map.phys_map = data->phys_map;
+
+	map.map = early_memremap(data->phys_map, data->size);
+	if (!map.map) {
+		pr_err("Could not map the memory map!\n");
+		return -ENOMEM;
+	}
+
+	map.nr_map = data->size / data->desc_size;
+	map.map_end = map.map + data->size;
+
+	map.desc_version = data->desc_version;
+	map.desc_size = data->desc_size;
+
+	set_bit(EFI_MEMMAP, &efi.flags);
+
+	efi.memmap = map;
+
+	return 0;
+}
+
+void __init efi_memmap_unmap(void)
+{
+	unsigned long size;
+
+	size = efi.memmap.desc_size * efi.memmap.nr_map;
+
+	early_memunmap(efi.memmap.map, size);
+	efi.memmap.map = NULL;
+	clear_bit(EFI_MEMMAP, &efi.flags);
+}
+
 #ifdef CONFIG_EFI_VARS_MODULE
 static int __init efi_load_efivars(void)
 {
diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index c437388a7b85..939eec47139f 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -57,6 +57,7 @@ static int __init cmp_fake_mem(const void *x1, const void *x2)
 void __init efi_fake_memmap(void)
 {
 	u64 start, end, m_start, m_end, m_attr;
+	struct efi_memory_map_data data;
 	int new_nr_map = efi.memmap.nr_map;
 	efi_memory_desc_t *md;
 	phys_addr_t new_memmap_phy;
@@ -180,12 +181,14 @@ void __init efi_fake_memmap(void)
 	}
 
 	/* swap into new EFI memmap */
-	efi_unmap_memmap();
-	efi.memmap.map = new_memmap;
-	efi.memmap.phys_map = new_memmap_phy;
-	efi.memmap.nr_map = new_nr_map;
-	efi.memmap.map_end = efi.memmap.map + efi.memmap.nr_map * efi.memmap.desc_size;
-	set_bit(EFI_MEMMAP, &efi.flags);
+	early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
+	efi_memmap_unmap();
+
+	data.phys_map = new_memmap_phy;
+	data.size = efi.memmap.desc_size * new_nr_map;
+	data.desc_version = efi.memmap.desc_version;
+	data.desc_size = efi.memmap.desc_size;
+	efi_memmap_init_early(&data);
 
 	/* print new EFI memmap */
 	efi_print_memmap();
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 03009695760d..055fbecd3156 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -742,6 +742,18 @@ typedef struct {
 	unsigned long tables;
 } efi_system_table_t;
 
+/*
+ * Architecture independent structure for describing a memory map for the
+ * benefit of efi_memmap_init_early(), saving us the need to pass four
+ * parameters.
+ */
+struct efi_memory_map_data {
+	phys_addr_t phys_map;
+	unsigned long size;
+	unsigned long desc_version;
+	unsigned long desc_size;
+};
+
 struct efi_memory_map {
 	phys_addr_t phys_map;
 	void *map;
@@ -973,6 +985,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_init_early(struct efi_memory_map_data *data);
+extern void __init efi_memmap_unmap(void);
+
 extern int efi_config_init(efi_config_table_type_t *arch_tables);
 #ifdef CONFIG_EFI_ESRT
 extern void __init efi_esrt_init(void);
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 04/11] efi: Add efi_memmap_init_late() for permanent EFI memmap
  2016-06-23 11:34 [PATCH 00/11] efi: Permanent runtime EFI memmap support Matt Fleming
                   ` (2 preceding siblings ...)
  2016-06-23 11:34   ` Matt Fleming
@ 2016-06-23 11:34 ` Matt Fleming
  2016-06-23 11:34 ` [PATCH 05/11] efi/fake_mem: Refactor main two code chunks into functions Matt Fleming
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland

Drivers need a way to access the EFI memory map at runtime. ARM and
arm64 currently provide this by remapping the EFI memory map into the
vmalloc space before setting up the EFI virtual mappings.

x86 does not provide this functionality which has resulted in the code
in efi_mem_desc_lookup() where it will manually map individual EFI
memmap entries if the memmap has already been torn down on x86,

  /*
   * If a driver calls this after efi_free_boot_services,
   * ->map will be NULL, and the target may also not be mapped.
   * So just always get our own virtual map on the CPU.
   *
   */
  md = early_memremap(p, sizeof (*md));

There isn't a good reason for not providing a permanent EFI memory map
for runtime queries, especially since the EFI regions are not mapped
into the standard kernel page tables.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 arch/x86/platform/efi/efi.c        |  46 +++++++++----
 arch/x86/platform/efi/quirks.c     |   2 -
 drivers/firmware/efi/arm-runtime.c |   4 +-
 drivers/firmware/efi/efi.c         | 135 ++++++++++++++++++++++++++-----------
 include/linux/efi.h                |   2 +
 5 files changed, 130 insertions(+), 59 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index b434c887229c..33bc6c12702c 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -843,6 +843,19 @@ static void __init kexec_enter_virtual_mode(void)
 		get_systab_virt_addr(md);
 	}
 
+	/*
+	 * Unregister the early EFI memmap from efi_init() and install
+	 * the new EFI memory map.
+	 */
+	efi_memmap_unmap();
+
+	if (efi_memmap_init_late(efi.memmap.phys_map,
+				 efi.memmap.desc_size * efi.memmap.nr_map)) {
+		pr_err("Failed to remap late EFI memory map\n");
+		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+		return;
+	}
+
 	save_runtime_map();
 
 	BUG_ON(!efi.systab);
@@ -904,6 +917,7 @@ static void __init __efi_enter_virtual_mode(void)
 	int count = 0, pg_shift = 0;
 	void *new_memmap = NULL;
 	efi_status_t status;
+	phys_addr_t pa;
 
 	efi.systab = NULL;
 
@@ -921,11 +935,26 @@ static void __init __efi_enter_virtual_mode(void)
 		return;
 	}
 
+	pa = __pa(new_memmap);
+
+	/*
+	 * Unregister the early EFI memmap from efi_init() and install
+	 * the new EFI memory map that we are about to pass to the
+	 * firmware via SetVirtualAddressMap().
+	 */
+	efi_memmap_unmap();
+
+	if (efi_memmap_init_late(pa, efi.memmap.desc_size * count)) {
+		pr_err("Failed to remap late EFI memory map\n");
+		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+		return;
+	}
+
 	save_runtime_map();
 
 	BUG_ON(!efi.systab);
 
-	if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift)) {
+	if (efi_setup_page_tables(pa, 1 << pg_shift)) {
 		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 		return;
 	}
@@ -937,14 +966,14 @@ static void __init __efi_enter_virtual_mode(void)
 				efi.memmap.desc_size * count,
 				efi.memmap.desc_size,
 				efi.memmap.desc_version,
-				(efi_memory_desc_t *)__pa(new_memmap));
+				(efi_memory_desc_t *)pa);
 	} else {
 		status = efi_thunk_set_virtual_address_map(
 				efi_phys.set_virtual_address_map,
 				efi.memmap.desc_size * count,
 				efi.memmap.desc_size,
 				efi.memmap.desc_version,
-				(efi_memory_desc_t *)__pa(new_memmap));
+				(efi_memory_desc_t *)pa);
 	}
 
 	if (status != EFI_SUCCESS) {
@@ -976,17 +1005,6 @@ static void __init __efi_enter_virtual_mode(void)
 	efi_runtime_update_mappings();
 	efi_dump_pagetable();
 
-	/*
-	 * We mapped the descriptor array into the EFI pagetable above
-	 * but we're not unmapping it here because if we're running in
-	 * EFI mixed mode we need all of memory to be accessible when
-	 * we pass parameters to the EFI runtime services in the
-	 * thunking code.
-	 *
-	 * efi_cleanup_page_tables(__pa(new_memmap), 1 << pg_shift);
-	 */
-	free_pages((unsigned long)new_memmap, pg_shift);
-
 	/* clean DUMMY object */
 	efi_delete_dummy_variable();
 }
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 0af180004e74..570c33683a26 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -265,8 +265,6 @@ void __init efi_free_boot_services(void)
 
 		free_bootmem_late(start, size);
 	}
-
-	efi_memmap_unmap();
 }
 
 /*
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
index 17ccf0a8787a..ce1424672d89 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -111,12 +111,10 @@ static int __init arm_enable_runtime_services(void)
 
 	mapsize = efi.memmap.map_end - efi.memmap.map;
 
-	efi.memmap.map = memremap(efi.memmap.phys_map, mapsize, MEMREMAP_WB);
-	if (!efi.memmap.map) {
+	if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
 		pr_err("Failed to remap EFI memory map\n");
 		return -ENOMEM;
 	}
-	efi.memmap.map_end = efi.memmap.map + mapsize;
 
 	if (!efi_virtmap_init()) {
 		pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 3e6dce71f54d..50eda492d0bb 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -251,56 +251,31 @@ subsys_initcall(efisubsys_init);
 
 /*
  * Find the efi memory descriptor for a given physical address.  Given a
- * physicall address, determine if it exists within an EFI Memory Map entry,
+ * physical address, determine if it exists within an EFI Memory Map entry,
  * and if so, populate the supplied memory descriptor with the appropriate
  * data.
  */
 int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
 {
-	struct efi_memory_map *map = &efi.memmap;
-	phys_addr_t p, e;
+	efi_memory_desc_t *md;
 
 	if (!efi_enabled(EFI_MEMMAP)) {
 		pr_err_once("EFI_MEMMAP is not enabled.\n");
 		return -EINVAL;
 	}
 
-	if (!map) {
-		pr_err_once("efi.memmap is not set.\n");
-		return -EINVAL;
-	}
 	if (!out_md) {
 		pr_err_once("out_md is null.\n");
 		return -EINVAL;
         }
-	if (WARN_ON_ONCE(!map->phys_map))
-		return -EINVAL;
-	if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0))
-		return -EINVAL;
 
-	e = map->phys_map + map->nr_map * map->desc_size;
-	for (p = map->phys_map; p < e; p += map->desc_size) {
-		efi_memory_desc_t *md;
+	for_each_efi_memory_desc(md) {
 		u64 size;
 		u64 end;
 
-		/*
-		 * If a driver calls this after efi_free_boot_services,
-		 * ->map will be NULL, and the target may also not be mapped.
-		 * So just always get our own virtual map on the CPU.
-		 *
-		 */
-		md = early_memremap(p, sizeof (*md));
-		if (!md) {
-			pr_err_once("early_memremap(%pa, %zu) failed.\n",
-				    &p, sizeof (*md));
-			return -ENOMEM;
-		}
-
 		if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
 		    md->type != EFI_BOOT_SERVICES_DATA &&
 		    md->type != EFI_RUNTIME_SERVICES_DATA) {
-			early_memunmap(md, sizeof (*md));
 			continue;
 		}
 
@@ -308,11 +283,8 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
 		end = md->phys_addr + size;
 		if (phys_addr >= md->phys_addr && phys_addr < end) {
 			memcpy(out_md, md, sizeof(*out_md));
-			early_memunmap(md, sizeof (*md));
 			return 0;
 		}
-
-		early_memunmap(md, sizeof (*md));
 	}
 	pr_err_once("requested map not found.\n");
 	return -ENOENT;
@@ -449,32 +421,49 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
 }
 
 /**
- * efi_memmap_init_early - Map the EFI memory map data structure
+ * __efi_memmap_init - Common code for mapping the EFI memory map
  * @data: EFI memory map data
+ * @late: Use early or late mapping function?
  *
- * Use early_memremap() to map the passed in EFI memory map and assign
- * it to efi.memmap.
+ * This function takes care of figuring out which function to use to
+ * map the EFI memory map in efi.memmap based on how far into the boot
+ * we are.
+ *
+ * During bootup @late should be %false since we only have access to
+ * the early_memremap*() functions as the vmalloc space isn't setup.
+ * Once the kernel is fully booted we can fallback to the more robust
+ * memremap*() API.
+ *
+ * Returns zero on success, a negative error code on failure.
  */
-int __init efi_memmap_init_early(struct efi_memory_map_data *data)
+static int __init
+__efi_memmap_init(struct efi_memory_map_data *data, bool late)
 {
 	struct efi_memory_map map;
+	phys_addr_t phys_map;
 
 	if (efi_enabled(EFI_PARAVIRT))
 		return 0;
 
-	map.phys_map = data->phys_map;
+	phys_map = data->phys_map;
+
+	if (late)
+		map.map = memremap(phys_map, data->size, MEMREMAP_WB);
+	else
+		map.map = early_memremap(phys_map, data->size);
 
-	map.map = early_memremap(data->phys_map, data->size);
 	if (!map.map) {
 		pr_err("Could not map the memory map!\n");
 		return -ENOMEM;
 	}
 
+	map.phys_map = data->phys_map;
 	map.nr_map = data->size / data->desc_size;
 	map.map_end = map.map + data->size;
 
 	map.desc_version = data->desc_version;
 	map.desc_size = data->desc_size;
+	map.late = late;
 
 	set_bit(EFI_MEMMAP, &efi.flags);
 
@@ -483,17 +472,83 @@ int __init efi_memmap_init_early(struct efi_memory_map_data *data)
 	return 0;
 }
 
+/**
+ * efi_memmap_init_early - Map the EFI memory map data structure
+ * @data: EFI memory map data
+ *
+ * Use early_memremap() to map the passed in EFI memory map and assign
+ * it to efi.memmap.
+ */
+int __init efi_memmap_init_early(struct efi_memory_map_data *data)
+{
+	/* Cannot go backwards */
+	WARN_ON(efi.memmap.late);
+
+	return __efi_memmap_init(data, false);
+}
+
 void __init efi_memmap_unmap(void)
 {
-	unsigned long size;
+	if (!efi.memmap.late) {
+		unsigned long size;
 
-	size = efi.memmap.desc_size * efi.memmap.nr_map;
+		size = efi.memmap.desc_size * efi.memmap.nr_map;
+		early_memunmap(efi.memmap.map, size);
+	} else {
+		memunmap(efi.memmap.map);
+	}
 
-	early_memunmap(efi.memmap.map, size);
 	efi.memmap.map = NULL;
 	clear_bit(EFI_MEMMAP, &efi.flags);
 }
 
+/**
+ * efi_memmap_init_late - Map efi.memmap with memremap()
+ * @phys_addr: Physical address of the new EFI memory map
+ * @size: Size in bytes of the new EFI memory map
+ *
+ * Setup a mapping of the EFI memory map using ioremap_cache(). This
+ * function should only be called once the vmalloc space has been
+ * setup and is therefore not suitable for calling during early EFI
+ * initialise, e.g. in efi_init(). Additionally, it expects
+ * efi_memmap_init_early() to have already been called.
+ *
+ * The reason there are two EFI memmap initialisation
+ * (efi_memmap_init_early() and this late version) is because the
+ * early EFI memmap should be explicitly unmapped once EFI
+ * initialisation is complete as the fixmap space used to map the EFI
+ * memmap (via early_memremap()) is a scarce resource.
+ *
+ * This late mapping is intended to persist for the duration of
+ * runtime so that things like efi_mem_desc_lookup() and
+ * efi_mem_attributes() always work.
+ *
+ * Returns zero on success, a negative error code on failure.
+ */
+int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
+{
+	struct efi_memory_map_data data = {
+		.phys_map = addr,
+		.size = size,
+	};
+
+	/* Did we forget to unmap the early EFI memmap? */
+	WARN_ON(efi.memmap.map);
+
+	/* Were we already called? */
+	WARN_ON(efi.memmap.late);
+
+	/*
+	 * It makes no sense to allow callers to register different
+	 * values for the following fields. Copy them out of the
+	 * existing early EFI memmap.
+	 */
+	data.desc_version = efi.memmap.desc_version;
+	data.desc_size = efi.memmap.desc_size;
+
+	return __efi_memmap_init(&data, true);
+}
+
 #ifdef CONFIG_EFI_VARS_MODULE
 static int __init efi_load_efivars(void)
 {
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 055fbecd3156..deb9d1c79bbf 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -761,6 +761,7 @@ struct efi_memory_map {
 	int nr_map;
 	unsigned long desc_version;
 	unsigned long desc_size;
+	bool late;
 };
 
 struct efi_fdt_params {
@@ -987,6 +988,7 @@ static inline efi_status_t efi_query_variable_store(u32 attributes,
 extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
 
 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 efi_config_init(efi_config_table_type_t *arch_tables);
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 05/11] efi/fake_mem: Refactor main two code chunks into functions
  2016-06-23 11:34 [PATCH 00/11] efi: Permanent runtime EFI memmap support Matt Fleming
                   ` (3 preceding siblings ...)
  2016-06-23 11:34 ` [PATCH 04/11] efi: Add efi_memmap_init_late() for permanent EFI memmap Matt Fleming
@ 2016-06-23 11:34 ` Matt Fleming
  2016-06-23 11:34   ` Matt Fleming
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland, Taku Izumi

There is a whole load of generic EFI memory map code inside of the
fake_mem driver which is better suited to being grouped with the rest
of the generic EFI code for manipulating EFI memory maps.

In preparation for that, this patch refactors the core code, so that
it's possible to move entire functions later.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Taku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 drivers/firmware/efi/fake_mem.c | 229 +++++++++++++++++++++++-----------------
 1 file changed, 134 insertions(+), 95 deletions(-)

diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index 939eec47139f..446c669431c0 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -54,43 +54,151 @@ static int __init cmp_fake_mem(const void *x1, const void *x2)
 	return 0;
 }
 
+/**
+ * efi_fake_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
+ * accomodate @range.
+ */
+static int efi_fake_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_fake_memmap_insert - Insert a fake memory region in an EFI memmap
+ * @old_memmap: The existing EFI memory map structure
+ * @buf: Address of buffer to store new map
+ * @mem: Fake memory map entry to insert
+ *
+ * It is suggested that you call efi_fake_memmap_split_count() first
+ * to see how large @buf needs to be.
+ */
+static void efi_fake_memmap_insert(struct efi_memory_map *old_memmap,
+				   void *buf, struct fake_mem *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;
+
+	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;
+		}
+	}
+}
+
 void __init efi_fake_memmap(void)
 {
-	u64 start, end, m_start, m_end, m_attr;
 	struct efi_memory_map_data data;
 	int new_nr_map = efi.memmap.nr_map;
 	efi_memory_desc_t *md;
 	phys_addr_t new_memmap_phy;
 	void *new_memmap;
-	void *old, *new;
 	int i;
 
 	if (!nr_fake_mem)
 		return;
 
 	/* count up the number of EFI memory descriptor */
-	for_each_efi_memory_desc(md) {
-		start = md->phys_addr;
-		end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1;
-
-		for (i = 0; i < nr_fake_mem; i++) {
-			/* modifying range */
-			m_start = fake_mems[i].range.start;
-			m_end = fake_mems[i].range.end;
-
-			if (m_start <= start) {
-				/* split into 2 parts */
-				if (start < m_end && m_end < end)
-					new_nr_map++;
-			}
-			if (start < m_start && m_start < end) {
-				/* split into 3 parts */
-				if (m_end < end)
-					new_nr_map += 2;
-				/* split into 2 parts */
-				if (end <= m_end)
-					new_nr_map++;
-			}
+	for (i = 0; i < nr_fake_mem; i++) {
+		for_each_efi_memory_desc(md) {
+			struct range *r = &fake_mems[i].range;
+
+			new_nr_map += efi_fake_memmap_split_count(md, r);
 		}
 	}
 
@@ -108,77 +216,8 @@ void __init efi_fake_memmap(void)
 		return;
 	}
 
-	for (old = efi.memmap.map, new = new_memmap;
-	     old < efi.memmap.map_end;
-	     old += efi.memmap.desc_size, new += efi.memmap.desc_size) {
-
-		/* copy original EFI memory descriptor */
-		memcpy(new, old, efi.memmap.desc_size);
-		md = new;
-		start = md->phys_addr;
-		end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
-
-		for (i = 0; i < nr_fake_mem; i++) {
-			/* modifying range */
-			m_start = fake_mems[i].range.start;
-			m_end = fake_mems[i].range.end;
-			m_attr = fake_mems[i].attribute;
-
-			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 += efi.memmap.desc_size;
-				memcpy(new, old, efi.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 += efi.memmap.desc_size;
-				memcpy(new, old, efi.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 += efi.memmap.desc_size;
-				memcpy(new, old, efi.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 += efi.memmap.desc_size;
-				memcpy(new, old, efi.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;
-			}
-		}
-	}
+	for (i = 0; i < nr_fake_mem; i++)
+		efi_fake_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]);
 
 	/* swap into new EFI memmap */
 	early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 06/11] efi: Split out EFI memory map functions into new file
@ 2016-06-23 11:34   ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland, Taku Izumi

Also move the functions from the EFI fake mem driver since future
patches will require access to the memmap insertion code even if
CONFIG_EFI_FAKE_MEM isn't enabled.

This will be useful when we need to build custom EFI memory maps to
allow drivers to mark regions as reserved.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Taku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 drivers/firmware/efi/Makefile   |   2 +-
 drivers/firmware/efi/efi.c      | 129 -------------------
 drivers/firmware/efi/fake_mem.c | 143 +--------------------
 drivers/firmware/efi/memmap.c   | 267 ++++++++++++++++++++++++++++++++++++++++
 include/linux/efi.h             |  10 ++
 5 files changed, 284 insertions(+), 267 deletions(-)
 create mode 100644 drivers/firmware/efi/memmap.c

diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index a219640f881f..b3f5e2adc49f 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -10,7 +10,7 @@
 KASAN_SANITIZE_runtime-wrappers.o	:= n
 
 obj-$(CONFIG_EFI)			+= efi.o vars.o reboot.o memattr.o
-obj-$(CONFIG_EFI)			+= capsule.o
+obj-$(CONFIG_EFI)			+= capsule.o memmap.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/efi.c b/drivers/firmware/efi/efi.c
index 50eda492d0bb..d9c41a434462 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -420,135 +420,6 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
 	return ret;
 }
 
-/**
- * __efi_memmap_init - Common code for mapping the EFI memory map
- * @data: EFI memory map data
- * @late: Use early or late mapping function?
- *
- * This function takes care of figuring out which function to use to
- * map the EFI memory map in efi.memmap based on how far into the boot
- * we are.
- *
- * During bootup @late should be %false since we only have access to
- * the early_memremap*() functions as the vmalloc space isn't setup.
- * Once the kernel is fully booted we can fallback to the more robust
- * memremap*() API.
- *
- * Returns zero on success, a negative error code on failure.
- */
-static int __init
-__efi_memmap_init(struct efi_memory_map_data *data, bool late)
-{
-	struct efi_memory_map map;
-	phys_addr_t phys_map;
-
-	if (efi_enabled(EFI_PARAVIRT))
-		return 0;
-
-	phys_map = data->phys_map;
-
-	if (late)
-		map.map = memremap(phys_map, data->size, MEMREMAP_WB);
-	else
-		map.map = early_memremap(phys_map, data->size);
-
-	if (!map.map) {
-		pr_err("Could not map the memory map!\n");
-		return -ENOMEM;
-	}
-
-	map.phys_map = data->phys_map;
-	map.nr_map = data->size / data->desc_size;
-	map.map_end = map.map + data->size;
-
-	map.desc_version = data->desc_version;
-	map.desc_size = data->desc_size;
-	map.late = late;
-
-	set_bit(EFI_MEMMAP, &efi.flags);
-
-	efi.memmap = map;
-
-	return 0;
-}
-
-/**
- * efi_memmap_init_early - Map the EFI memory map data structure
- * @data: EFI memory map data
- *
- * Use early_memremap() to map the passed in EFI memory map and assign
- * it to efi.memmap.
- */
-int __init efi_memmap_init_early(struct efi_memory_map_data *data)
-{
-	/* Cannot go backwards */
-	WARN_ON(efi.memmap.late);
-
-	return __efi_memmap_init(data, false);
-}
-
-void __init efi_memmap_unmap(void)
-{
-	if (!efi.memmap.late) {
-		unsigned long size;
-
-		size = efi.memmap.desc_size * efi.memmap.nr_map;
-		early_memunmap(efi.memmap.map, size);
-	} else {
-		memunmap(efi.memmap.map);
-	}
-
-	efi.memmap.map = NULL;
-	clear_bit(EFI_MEMMAP, &efi.flags);
-}
-
-/**
- * efi_memmap_init_late - Map efi.memmap with memremap()
- * @phys_addr: Physical address of the new EFI memory map
- * @size: Size in bytes of the new EFI memory map
- *
- * Setup a mapping of the EFI memory map using ioremap_cache(). This
- * function should only be called once the vmalloc space has been
- * setup and is therefore not suitable for calling during early EFI
- * initialise, e.g. in efi_init(). Additionally, it expects
- * efi_memmap_init_early() to have already been called.
- *
- * The reason there are two EFI memmap initialisation
- * (efi_memmap_init_early() and this late version) is because the
- * early EFI memmap should be explicitly unmapped once EFI
- * initialisation is complete as the fixmap space used to map the EFI
- * memmap (via early_memremap()) is a scarce resource.
- *
- * This late mapping is intended to persist for the duration of
- * runtime so that things like efi_mem_desc_lookup() and
- * efi_mem_attributes() always work.
- *
- * Returns zero on success, a negative error code on failure.
- */
-int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
-{
-	struct efi_memory_map_data data = {
-		.phys_map = addr,
-		.size = size,
-	};
-
-	/* Did we forget to unmap the early EFI memmap? */
-	WARN_ON(efi.memmap.map);
-
-	/* Were we already called? */
-	WARN_ON(efi.memmap.late);
-
-	/*
-	 * It makes no sense to allow callers to register different
-	 * values for the following fields. Copy them out of the
-	 * existing early EFI memmap.
-	 */
-	data.desc_version = efi.memmap.desc_version;
-	data.desc_size = efi.memmap.desc_size;
-
-	return __efi_memmap_init(&data, true);
-}
-
 #ifdef CONFIG_EFI_VARS_MODULE
 static int __init efi_load_efivars(void)
 {
diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index 446c669431c0..0054730f9bae 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -35,17 +35,13 @@
 
 #define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
 
-struct fake_mem {
-	struct range range;
-	u64 attribute;
-};
-static struct fake_mem fake_mems[EFI_MAX_FAKEMEM];
+static struct efi_mem_range fake_mems[EFI_MAX_FAKEMEM];
 static int nr_fake_mem;
 
 static int __init cmp_fake_mem(const void *x1, const void *x2)
 {
-	const struct fake_mem *m1 = x1;
-	const struct fake_mem *m2 = x2;
+	const struct efi_mem_range *m1 = x1;
+	const struct efi_mem_range *m2 = x2;
 
 	if (m1->range.start < m2->range.start)
 		return -1;
@@ -54,133 +50,6 @@ static int __init cmp_fake_mem(const void *x1, const void *x2)
 	return 0;
 }
 
-/**
- * efi_fake_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
- * accomodate @range.
- */
-static int efi_fake_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_fake_memmap_insert - Insert a fake memory region in an EFI memmap
- * @old_memmap: The existing EFI memory map structure
- * @buf: Address of buffer to store new map
- * @mem: Fake memory map entry to insert
- *
- * It is suggested that you call efi_fake_memmap_split_count() first
- * to see how large @buf needs to be.
- */
-static void efi_fake_memmap_insert(struct efi_memory_map *old_memmap,
-				   void *buf, struct fake_mem *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;
-
-	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;
-		}
-	}
-}
-
 void __init efi_fake_memmap(void)
 {
 	struct efi_memory_map_data data;
@@ -198,7 +67,7 @@ void __init efi_fake_memmap(void)
 		for_each_efi_memory_desc(md) {
 			struct range *r = &fake_mems[i].range;
 
-			new_nr_map += efi_fake_memmap_split_count(md, r);
+			new_nr_map += efi_memmap_split_count(md, r);
 		}
 	}
 
@@ -217,7 +86,7 @@ void __init efi_fake_memmap(void)
 	}
 
 	for (i = 0; i < nr_fake_mem; i++)
-		efi_fake_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]);
+		efi_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]);
 
 	/* swap into new EFI memmap */
 	early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
@@ -265,7 +134,7 @@ static int __init setup_fake_mem(char *p)
 			p++;
 	}
 
-	sort(fake_mems, nr_fake_mem, sizeof(struct fake_mem),
+	sort(fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
 	     cmp_fake_mem, NULL);
 
 	for (i = 0; i < nr_fake_mem; i++)
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
new file mode 100644
index 000000000000..2df7238eb44e
--- /dev/null
+++ b/drivers/firmware/efi/memmap.c
@@ -0,0 +1,267 @@
+/*
+ * Common EFI memory map functions.
+ */
+
+#define pr_fmt(fmt) "efi: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/efi.h>
+#include <linux/io.h>
+#include <asm/early_ioremap.h>
+
+/**
+ * __efi_memmap_init - Common code for mapping the EFI memory map
+ * @data: EFI memory map data
+ * @late: Use early or late mapping function?
+ *
+ * This function takes care of figuring out which function to use to
+ * map the EFI memory map in efi.memmap based on how far into the boot
+ * we are.
+ *
+ * During bootup @late should be %false since we only have access to
+ * the early_memremap*() functions as the vmalloc space isn't setup.
+ * Once the kernel is fully booted we can fallback to the more robust
+ * memremap*() API.
+ *
+ * Returns zero on success, a negative error code on failure.
+ */
+static int __init
+__efi_memmap_init(struct efi_memory_map_data *data, bool late)
+{
+	struct efi_memory_map map;
+	phys_addr_t phys_map;
+
+	if (efi_enabled(EFI_PARAVIRT))
+		return 0;
+
+	phys_map = data->phys_map;
+
+	if (late)
+		map.map = memremap(phys_map, data->size, MEMREMAP_WB);
+	else
+		map.map = early_memremap(phys_map, data->size);
+
+	if (!map.map) {
+		pr_err("Could not map the memory map!\n");
+		return -ENOMEM;
+	}
+
+	map.phys_map = data->phys_map;
+	map.nr_map = data->size / data->desc_size;
+	map.map_end = map.map + data->size;
+
+	map.desc_version = data->desc_version;
+	map.desc_size = data->desc_size;
+	map.late = late;
+
+	set_bit(EFI_MEMMAP, &efi.flags);
+
+	efi.memmap = map;
+
+	return 0;
+}
+
+/**
+ * efi_memmap_init_early - Map the EFI memory map data structure
+ * @data: EFI memory map data
+ *
+ * Use early_memremap() to map the passed in EFI memory map and assign
+ * it to efi.memmap.
+ */
+int __init efi_memmap_init_early(struct efi_memory_map_data *data)
+{
+	/* Cannot go backwards */
+	WARN_ON(efi.memmap.late);
+
+	return __efi_memmap_init(data, false);
+}
+
+void __init efi_memmap_unmap(void)
+{
+	if (!efi.memmap.late) {
+		unsigned long size;
+
+		size = efi.memmap.desc_size * efi.memmap.nr_map;
+		early_memunmap(efi.memmap.map, size);
+	} else {
+		memunmap(efi.memmap.map);
+	}
+
+	efi.memmap.map = NULL;
+	clear_bit(EFI_MEMMAP, &efi.flags);
+}
+
+/**
+ * efi_memmap_init_late - Map efi.memmap with memremap()
+ * @phys_addr: Physical address of the new EFI memory map
+ * @size: Size in bytes of the new EFI memory map
+ *
+ * Setup a mapping of the EFI memory map using ioremap_cache(). This
+ * function should only be called once the vmalloc space has been
+ * setup and is therefore not suitable for calling during early EFI
+ * initialise, e.g. in efi_init(). Additionally, it expects
+ * efi_memmap_init_early() to have already been called.
+ *
+ * The reason there are two EFI memmap initialisation
+ * (efi_memmap_init_early() and this late version) is because the
+ * early EFI memmap should be explicitly unmapped once EFI
+ * initialisation is complete as the fixmap space used to map the EFI
+ * memmap (via early_memremap()) is a scarce resource.
+ *
+ * This late mapping is intended to persist for the duration of
+ * runtime so that things like efi_mem_desc_lookup() and
+ * efi_mem_attributes() always work.
+ *
+ * Returns zero on success, a negative error code on failure.
+ */
+int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
+{
+	struct efi_memory_map_data data = {
+		.phys_map = addr,
+		.size = size,
+	};
+
+	/* Did we forget to unmap the early EFI memmap? */
+	WARN_ON(efi.memmap.map);
+
+	/* Were we already called? */
+	WARN_ON(efi.memmap.late);
+
+	/*
+	 * It makes no sense to allow callers to register different
+	 * values for the following fields. Copy them out of the
+	 * existing early EFI memmap.
+	 */
+	data.desc_version = efi.memmap.desc_version;
+	data.desc_size = efi.memmap.desc_size;
+
+	return __efi_memmap_init(&data, true);
+}
+
+/**
+ * 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
+ * accomodate @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;
+
+	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 deb9d1c79bbf..8fb8b80b86ac 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -20,6 +20,7 @@
 #include <linux/ioport.h>
 #include <linux/pfn.h>
 #include <linux/pstore.h>
+#include <linux/range.h>
 #include <linux/reboot.h>
 #include <linux/uuid.h>
 #include <linux/screen_info.h>
@@ -764,6 +765,11 @@ struct efi_memory_map {
 	bool late;
 };
 
+struct efi_mem_range {
+	struct range range;
+	u64 attribute;
+};
+
 struct efi_fdt_params {
 	u64 system_table;
 	u64 mmap;
@@ -990,6 +996,10 @@ extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
 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_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);
 
 extern int efi_config_init(efi_config_table_type_t *arch_tables);
 #ifdef CONFIG_EFI_ESRT
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 06/11] efi: Split out EFI memory map functions into new file
@ 2016-06-23 11:34   ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland, Taku Izumi

Also move the functions from the EFI fake mem driver since future
patches will require access to the memmap insertion code even if
CONFIG_EFI_FAKE_MEM isn't enabled.

This will be useful when we need to build custom EFI memory maps to
allow drivers to mark regions as reserved.

Cc: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Leif Lindholm <leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Borislav Petkov <bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Taku Izumi <izumi.taku-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
Signed-off-by: Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
---
 drivers/firmware/efi/Makefile   |   2 +-
 drivers/firmware/efi/efi.c      | 129 -------------------
 drivers/firmware/efi/fake_mem.c | 143 +--------------------
 drivers/firmware/efi/memmap.c   | 267 ++++++++++++++++++++++++++++++++++++++++
 include/linux/efi.h             |  10 ++
 5 files changed, 284 insertions(+), 267 deletions(-)
 create mode 100644 drivers/firmware/efi/memmap.c

diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index a219640f881f..b3f5e2adc49f 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -10,7 +10,7 @@
 KASAN_SANITIZE_runtime-wrappers.o	:= n
 
 obj-$(CONFIG_EFI)			+= efi.o vars.o reboot.o memattr.o
-obj-$(CONFIG_EFI)			+= capsule.o
+obj-$(CONFIG_EFI)			+= capsule.o memmap.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/efi.c b/drivers/firmware/efi/efi.c
index 50eda492d0bb..d9c41a434462 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -420,135 +420,6 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
 	return ret;
 }
 
-/**
- * __efi_memmap_init - Common code for mapping the EFI memory map
- * @data: EFI memory map data
- * @late: Use early or late mapping function?
- *
- * This function takes care of figuring out which function to use to
- * map the EFI memory map in efi.memmap based on how far into the boot
- * we are.
- *
- * During bootup @late should be %false since we only have access to
- * the early_memremap*() functions as the vmalloc space isn't setup.
- * Once the kernel is fully booted we can fallback to the more robust
- * memremap*() API.
- *
- * Returns zero on success, a negative error code on failure.
- */
-static int __init
-__efi_memmap_init(struct efi_memory_map_data *data, bool late)
-{
-	struct efi_memory_map map;
-	phys_addr_t phys_map;
-
-	if (efi_enabled(EFI_PARAVIRT))
-		return 0;
-
-	phys_map = data->phys_map;
-
-	if (late)
-		map.map = memremap(phys_map, data->size, MEMREMAP_WB);
-	else
-		map.map = early_memremap(phys_map, data->size);
-
-	if (!map.map) {
-		pr_err("Could not map the memory map!\n");
-		return -ENOMEM;
-	}
-
-	map.phys_map = data->phys_map;
-	map.nr_map = data->size / data->desc_size;
-	map.map_end = map.map + data->size;
-
-	map.desc_version = data->desc_version;
-	map.desc_size = data->desc_size;
-	map.late = late;
-
-	set_bit(EFI_MEMMAP, &efi.flags);
-
-	efi.memmap = map;
-
-	return 0;
-}
-
-/**
- * efi_memmap_init_early - Map the EFI memory map data structure
- * @data: EFI memory map data
- *
- * Use early_memremap() to map the passed in EFI memory map and assign
- * it to efi.memmap.
- */
-int __init efi_memmap_init_early(struct efi_memory_map_data *data)
-{
-	/* Cannot go backwards */
-	WARN_ON(efi.memmap.late);
-
-	return __efi_memmap_init(data, false);
-}
-
-void __init efi_memmap_unmap(void)
-{
-	if (!efi.memmap.late) {
-		unsigned long size;
-
-		size = efi.memmap.desc_size * efi.memmap.nr_map;
-		early_memunmap(efi.memmap.map, size);
-	} else {
-		memunmap(efi.memmap.map);
-	}
-
-	efi.memmap.map = NULL;
-	clear_bit(EFI_MEMMAP, &efi.flags);
-}
-
-/**
- * efi_memmap_init_late - Map efi.memmap with memremap()
- * @phys_addr: Physical address of the new EFI memory map
- * @size: Size in bytes of the new EFI memory map
- *
- * Setup a mapping of the EFI memory map using ioremap_cache(). This
- * function should only be called once the vmalloc space has been
- * setup and is therefore not suitable for calling during early EFI
- * initialise, e.g. in efi_init(). Additionally, it expects
- * efi_memmap_init_early() to have already been called.
- *
- * The reason there are two EFI memmap initialisation
- * (efi_memmap_init_early() and this late version) is because the
- * early EFI memmap should be explicitly unmapped once EFI
- * initialisation is complete as the fixmap space used to map the EFI
- * memmap (via early_memremap()) is a scarce resource.
- *
- * This late mapping is intended to persist for the duration of
- * runtime so that things like efi_mem_desc_lookup() and
- * efi_mem_attributes() always work.
- *
- * Returns zero on success, a negative error code on failure.
- */
-int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
-{
-	struct efi_memory_map_data data = {
-		.phys_map = addr,
-		.size = size,
-	};
-
-	/* Did we forget to unmap the early EFI memmap? */
-	WARN_ON(efi.memmap.map);
-
-	/* Were we already called? */
-	WARN_ON(efi.memmap.late);
-
-	/*
-	 * It makes no sense to allow callers to register different
-	 * values for the following fields. Copy them out of the
-	 * existing early EFI memmap.
-	 */
-	data.desc_version = efi.memmap.desc_version;
-	data.desc_size = efi.memmap.desc_size;
-
-	return __efi_memmap_init(&data, true);
-}
-
 #ifdef CONFIG_EFI_VARS_MODULE
 static int __init efi_load_efivars(void)
 {
diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index 446c669431c0..0054730f9bae 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -35,17 +35,13 @@
 
 #define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
 
-struct fake_mem {
-	struct range range;
-	u64 attribute;
-};
-static struct fake_mem fake_mems[EFI_MAX_FAKEMEM];
+static struct efi_mem_range fake_mems[EFI_MAX_FAKEMEM];
 static int nr_fake_mem;
 
 static int __init cmp_fake_mem(const void *x1, const void *x2)
 {
-	const struct fake_mem *m1 = x1;
-	const struct fake_mem *m2 = x2;
+	const struct efi_mem_range *m1 = x1;
+	const struct efi_mem_range *m2 = x2;
 
 	if (m1->range.start < m2->range.start)
 		return -1;
@@ -54,133 +50,6 @@ static int __init cmp_fake_mem(const void *x1, const void *x2)
 	return 0;
 }
 
-/**
- * efi_fake_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
- * accomodate @range.
- */
-static int efi_fake_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_fake_memmap_insert - Insert a fake memory region in an EFI memmap
- * @old_memmap: The existing EFI memory map structure
- * @buf: Address of buffer to store new map
- * @mem: Fake memory map entry to insert
- *
- * It is suggested that you call efi_fake_memmap_split_count() first
- * to see how large @buf needs to be.
- */
-static void efi_fake_memmap_insert(struct efi_memory_map *old_memmap,
-				   void *buf, struct fake_mem *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;
-
-	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;
-		}
-	}
-}
-
 void __init efi_fake_memmap(void)
 {
 	struct efi_memory_map_data data;
@@ -198,7 +67,7 @@ void __init efi_fake_memmap(void)
 		for_each_efi_memory_desc(md) {
 			struct range *r = &fake_mems[i].range;
 
-			new_nr_map += efi_fake_memmap_split_count(md, r);
+			new_nr_map += efi_memmap_split_count(md, r);
 		}
 	}
 
@@ -217,7 +86,7 @@ void __init efi_fake_memmap(void)
 	}
 
 	for (i = 0; i < nr_fake_mem; i++)
-		efi_fake_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]);
+		efi_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]);
 
 	/* swap into new EFI memmap */
 	early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
@@ -265,7 +134,7 @@ static int __init setup_fake_mem(char *p)
 			p++;
 	}
 
-	sort(fake_mems, nr_fake_mem, sizeof(struct fake_mem),
+	sort(fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
 	     cmp_fake_mem, NULL);
 
 	for (i = 0; i < nr_fake_mem; i++)
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
new file mode 100644
index 000000000000..2df7238eb44e
--- /dev/null
+++ b/drivers/firmware/efi/memmap.c
@@ -0,0 +1,267 @@
+/*
+ * Common EFI memory map functions.
+ */
+
+#define pr_fmt(fmt) "efi: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/efi.h>
+#include <linux/io.h>
+#include <asm/early_ioremap.h>
+
+/**
+ * __efi_memmap_init - Common code for mapping the EFI memory map
+ * @data: EFI memory map data
+ * @late: Use early or late mapping function?
+ *
+ * This function takes care of figuring out which function to use to
+ * map the EFI memory map in efi.memmap based on how far into the boot
+ * we are.
+ *
+ * During bootup @late should be %false since we only have access to
+ * the early_memremap*() functions as the vmalloc space isn't setup.
+ * Once the kernel is fully booted we can fallback to the more robust
+ * memremap*() API.
+ *
+ * Returns zero on success, a negative error code on failure.
+ */
+static int __init
+__efi_memmap_init(struct efi_memory_map_data *data, bool late)
+{
+	struct efi_memory_map map;
+	phys_addr_t phys_map;
+
+	if (efi_enabled(EFI_PARAVIRT))
+		return 0;
+
+	phys_map = data->phys_map;
+
+	if (late)
+		map.map = memremap(phys_map, data->size, MEMREMAP_WB);
+	else
+		map.map = early_memremap(phys_map, data->size);
+
+	if (!map.map) {
+		pr_err("Could not map the memory map!\n");
+		return -ENOMEM;
+	}
+
+	map.phys_map = data->phys_map;
+	map.nr_map = data->size / data->desc_size;
+	map.map_end = map.map + data->size;
+
+	map.desc_version = data->desc_version;
+	map.desc_size = data->desc_size;
+	map.late = late;
+
+	set_bit(EFI_MEMMAP, &efi.flags);
+
+	efi.memmap = map;
+
+	return 0;
+}
+
+/**
+ * efi_memmap_init_early - Map the EFI memory map data structure
+ * @data: EFI memory map data
+ *
+ * Use early_memremap() to map the passed in EFI memory map and assign
+ * it to efi.memmap.
+ */
+int __init efi_memmap_init_early(struct efi_memory_map_data *data)
+{
+	/* Cannot go backwards */
+	WARN_ON(efi.memmap.late);
+
+	return __efi_memmap_init(data, false);
+}
+
+void __init efi_memmap_unmap(void)
+{
+	if (!efi.memmap.late) {
+		unsigned long size;
+
+		size = efi.memmap.desc_size * efi.memmap.nr_map;
+		early_memunmap(efi.memmap.map, size);
+	} else {
+		memunmap(efi.memmap.map);
+	}
+
+	efi.memmap.map = NULL;
+	clear_bit(EFI_MEMMAP, &efi.flags);
+}
+
+/**
+ * efi_memmap_init_late - Map efi.memmap with memremap()
+ * @phys_addr: Physical address of the new EFI memory map
+ * @size: Size in bytes of the new EFI memory map
+ *
+ * Setup a mapping of the EFI memory map using ioremap_cache(). This
+ * function should only be called once the vmalloc space has been
+ * setup and is therefore not suitable for calling during early EFI
+ * initialise, e.g. in efi_init(). Additionally, it expects
+ * efi_memmap_init_early() to have already been called.
+ *
+ * The reason there are two EFI memmap initialisation
+ * (efi_memmap_init_early() and this late version) is because the
+ * early EFI memmap should be explicitly unmapped once EFI
+ * initialisation is complete as the fixmap space used to map the EFI
+ * memmap (via early_memremap()) is a scarce resource.
+ *
+ * This late mapping is intended to persist for the duration of
+ * runtime so that things like efi_mem_desc_lookup() and
+ * efi_mem_attributes() always work.
+ *
+ * Returns zero on success, a negative error code on failure.
+ */
+int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
+{
+	struct efi_memory_map_data data = {
+		.phys_map = addr,
+		.size = size,
+	};
+
+	/* Did we forget to unmap the early EFI memmap? */
+	WARN_ON(efi.memmap.map);
+
+	/* Were we already called? */
+	WARN_ON(efi.memmap.late);
+
+	/*
+	 * It makes no sense to allow callers to register different
+	 * values for the following fields. Copy them out of the
+	 * existing early EFI memmap.
+	 */
+	data.desc_version = efi.memmap.desc_version;
+	data.desc_size = efi.memmap.desc_size;
+
+	return __efi_memmap_init(&data, true);
+}
+
+/**
+ * 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
+ * accomodate @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;
+
+	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 deb9d1c79bbf..8fb8b80b86ac 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -20,6 +20,7 @@
 #include <linux/ioport.h>
 #include <linux/pfn.h>
 #include <linux/pstore.h>
+#include <linux/range.h>
 #include <linux/reboot.h>
 #include <linux/uuid.h>
 #include <linux/screen_info.h>
@@ -764,6 +765,11 @@ struct efi_memory_map {
 	bool late;
 };
 
+struct efi_mem_range {
+	struct range range;
+	u64 attribute;
+};
+
 struct efi_fdt_params {
 	u64 system_table;
 	u64 mmap;
@@ -990,6 +996,10 @@ extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
 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_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);
 
 extern int efi_config_init(efi_config_table_type_t *arch_tables);
 #ifdef CONFIG_EFI_ESRT
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 07/11] efi: Add efi_memmap_install() for installing new EFI memory maps
@ 2016-06-23 11:34   ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland, Taku Izumi

While efi_memmap_init_{early,late}() exist for architecture code to
install memory maps from firmware data and for the virtual memory
regions respectively, drivers don't care which stage of the boot we're
at and just want to swap the existing memmap for a modified one.

efi_memmap_install() abstracts the details of how the new memory map
should be mapped and the existing one unmapped.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Taku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 drivers/firmware/efi/fake_mem.c |  8 +-------
 drivers/firmware/efi/memmap.c   | 25 +++++++++++++++++++++++++
 include/linux/efi.h             |  1 +
 3 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index 0054730f9bae..520a40e5e0e4 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -52,7 +52,6 @@ static int __init cmp_fake_mem(const void *x1, const void *x2)
 
 void __init efi_fake_memmap(void)
 {
-	struct efi_memory_map_data data;
 	int new_nr_map = efi.memmap.nr_map;
 	efi_memory_desc_t *md;
 	phys_addr_t new_memmap_phy;
@@ -90,13 +89,8 @@ void __init efi_fake_memmap(void)
 
 	/* swap into new EFI memmap */
 	early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
-	efi_memmap_unmap();
 
-	data.phys_map = new_memmap_phy;
-	data.size = efi.memmap.desc_size * new_nr_map;
-	data.desc_version = efi.memmap.desc_version;
-	data.desc_size = efi.memmap.desc_size;
-	efi_memmap_init_early(&data);
+	efi_memmap_install(new_memmap_phy, new_nr_map);
 
 	/* print new EFI memmap */
 	efi_print_memmap();
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
index 2df7238eb44e..cd96086fd851 100644
--- a/drivers/firmware/efi/memmap.c
+++ b/drivers/firmware/efi/memmap.c
@@ -140,6 +140,31 @@ int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
 }
 
 /**
+ * efi_memmap_install - Install a new EFI memory map in efi.memmap
+ * @addr: Physical address of the memory map
+ * @nr_map: Number of entries in the memory map
+ *
+ * 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(phys_addr_t addr, unsigned int nr_map)
+{
+	struct efi_memory_map_data data;
+
+	efi_memmap_unmap();
+
+	data.phys_map = addr;
+	data.size = efi.memmap.desc_size * nr_map;
+	data.desc_version = efi.memmap.desc_version;
+	data.desc_size = efi.memmap.desc_size;
+
+	return __efi_memmap_init(&data, efi.memmap.late);
+}
+
+/**
  * 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
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 8fb8b80b86ac..9fb390d56fbe 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -996,6 +996,7 @@ extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
 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(phys_addr_t addr, unsigned int nr_map);
 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,
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 07/11] efi: Add efi_memmap_install() for installing new EFI memory maps
@ 2016-06-23 11:34   ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland, Taku Izumi

While efi_memmap_init_{early,late}() exist for architecture code to
install memory maps from firmware data and for the virtual memory
regions respectively, drivers don't care which stage of the boot we're
at and just want to swap the existing memmap for a modified one.

efi_memmap_install() abstracts the details of how the new memory map
should be mapped and the existing one unmapped.

Cc: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Leif Lindholm <leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Borislav Petkov <bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Taku Izumi <izumi.taku-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
Signed-off-by: Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
---
 drivers/firmware/efi/fake_mem.c |  8 +-------
 drivers/firmware/efi/memmap.c   | 25 +++++++++++++++++++++++++
 include/linux/efi.h             |  1 +
 3 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
index 0054730f9bae..520a40e5e0e4 100644
--- a/drivers/firmware/efi/fake_mem.c
+++ b/drivers/firmware/efi/fake_mem.c
@@ -52,7 +52,6 @@ static int __init cmp_fake_mem(const void *x1, const void *x2)
 
 void __init efi_fake_memmap(void)
 {
-	struct efi_memory_map_data data;
 	int new_nr_map = efi.memmap.nr_map;
 	efi_memory_desc_t *md;
 	phys_addr_t new_memmap_phy;
@@ -90,13 +89,8 @@ void __init efi_fake_memmap(void)
 
 	/* swap into new EFI memmap */
 	early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
-	efi_memmap_unmap();
 
-	data.phys_map = new_memmap_phy;
-	data.size = efi.memmap.desc_size * new_nr_map;
-	data.desc_version = efi.memmap.desc_version;
-	data.desc_size = efi.memmap.desc_size;
-	efi_memmap_init_early(&data);
+	efi_memmap_install(new_memmap_phy, new_nr_map);
 
 	/* print new EFI memmap */
 	efi_print_memmap();
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
index 2df7238eb44e..cd96086fd851 100644
--- a/drivers/firmware/efi/memmap.c
+++ b/drivers/firmware/efi/memmap.c
@@ -140,6 +140,31 @@ int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
 }
 
 /**
+ * efi_memmap_install - Install a new EFI memory map in efi.memmap
+ * @addr: Physical address of the memory map
+ * @nr_map: Number of entries in the memory map
+ *
+ * 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(phys_addr_t addr, unsigned int nr_map)
+{
+	struct efi_memory_map_data data;
+
+	efi_memmap_unmap();
+
+	data.phys_map = addr;
+	data.size = efi.memmap.desc_size * nr_map;
+	data.desc_version = efi.memmap.desc_version;
+	data.desc_size = efi.memmap.desc_size;
+
+	return __efi_memmap_init(&data, efi.memmap.late);
+}
+
+/**
  * 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
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 8fb8b80b86ac..9fb390d56fbe 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -996,6 +996,7 @@ extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
 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(phys_addr_t addr, unsigned int nr_map);
 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,
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 08/11] efi: Allow drivers to reserve boot services forever
  2016-06-23 11:34 [PATCH 00/11] efi: Permanent runtime EFI memmap support Matt Fleming
                   ` (6 preceding siblings ...)
  2016-06-23 11:34   ` Matt Fleming
@ 2016-06-23 11:34 ` Matt Fleming
  2016-06-23 11:34   ` Matt Fleming
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland

Today, it is not possible for drivers to reserve EFI boot services for
access after efi_free_boot_services() has been called on x86. For
ARM/arm64 it can be done simply by calling memblock_reserve().

Having this ability for all three architectures is desirable for a
couple of reasons,

  1) It saves drivers copying data out of those regions
  2) kexec reboot can now make use of things like ESRT

Instead of using the standard memblock_reserve() which is insufficient
to reserve the region on x86 (see efi_reserve_boot_services()), a new
API is introduced in this patch; efi_mem_reserve().

efi.memmap now always represents which EFI memory regions are
available. On x86 the EFI boot services regions that have not been
reserved via efi_mem_reserve() will be removed from efi.memmap during
efi_free_boot_services().

This has implications for kexec, since it is not possible for a newly
kexec'd kernel to access the same boot services regions that the
initial boot kernel had access to unless they are reserved by every
kexec kernel in the chain.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 arch/x86/platform/efi/quirks.c | 121 +++++++++++++++++++++++++++++++++++++----
 drivers/firmware/efi/efi.c     |  30 ++++++++++
 include/linux/efi.h            |   1 +
 3 files changed, 141 insertions(+), 11 deletions(-)

diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 570c33683a26..3dae771266a6 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -164,6 +164,71 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size,
 EXPORT_SYMBOL_GPL(efi_query_variable_store);
 
 /*
+ * The UEFI specification makes it clear that the operating system is
+ * free to do whatever it wants with boot services code after
+ * ExitBootServices() has been called. Ignoring this recommendation a
+ * significant bunch of EFI implementations continue calling into boot
+ * services code (SetVirtualAddressMap). In order to work around such
+ * buggy implementations we reserve boot services region during EFI
+ * init and make sure it stays executable. Then, after
+ * SetVirtualAddressMap(), it is discarded.
+ *
+ * However, some boot services regions contain data that is required
+ * by drivers, so we need to track which memory ranges can never be
+ * freed. This is done by tagging those regions with the
+ * EFI_MEMORY_RUNTIME attribute.
+ *
+ * Any driver that wants to mark a region as reserved must use
+ * efi_mem_reserve() which will insert a new EFI memory descriptor
+ * into efi.memmap (splitting existing regions if necessary) and tag
+ * it with EFI_MEMORY_RUNTIME.
+ */
+void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
+{
+	phys_addr_t new_phys, new_size;
+	struct efi_mem_range mr;
+	efi_memory_desc_t md;
+	int num_entries;
+	void *new;
+
+	if (efi_mem_desc_lookup(addr, &md)) {
+		pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr);
+		return;
+	}
+
+	if (addr + size > md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT)) {
+		pr_err("Region spans EFI memory descriptors, %pa\n", &addr);
+		return;
+	}
+
+	mr.range.start = addr;
+	mr.range.end = addr + size;
+	mr.attribute = md.attribute | EFI_MEMORY_RUNTIME;
+
+	num_entries = efi_memmap_split_count(&md, &mr.range);
+	num_entries += efi.memmap.nr_map;
+
+	new_size = efi.memmap.desc_size * num_entries;
+
+	new_phys = memblock_alloc(new_size, 0);
+	if (!new_phys) {
+		pr_err("Could not allocate boot services memmap\n");
+		return;
+	}
+
+	new = early_memremap(new_phys, new_size);
+	if (!new) {
+		pr_err("Failed to map new boot services memmap\n");
+		return;
+	}
+
+	efi_memmap_insert(&efi.memmap, new, &mr);
+	early_memunmap(new, new_size);
+
+	efi_memmap_install(new_phys, num_entries);
+}
+
+/*
  * Helper function for efi_reserve_boot_services() to figure out if we
  * can free regions in efi_free_boot_services().
  *
@@ -184,15 +249,6 @@ static bool can_free_region(u64 start, u64 size)
 	return true;
 }
 
-/*
- * The UEFI specification makes it clear that the operating system is free to do
- * whatever it wants with boot services code after ExitBootServices() has been
- * called. Ignoring this recommendation a significant bunch of EFI implementations 
- * continue calling into boot services code (SetVirtualAddressMap). In order to 
- * work around such buggy implementations we reserve boot services region during 
- * EFI init and make sure it stays executable. Then, after SetVirtualAddressMap(), it
-* is discarded.
-*/
 void __init efi_reserve_boot_services(void)
 {
 	efi_memory_desc_t *md;
@@ -249,22 +305,65 @@ void __init efi_reserve_boot_services(void)
 
 void __init efi_free_boot_services(void)
 {
+	phys_addr_t new_phys, new_size;
 	efi_memory_desc_t *md;
+	int num_entries = 0;
+	void *new, *new_md;
 
 	for_each_efi_memory_desc(md) {
 		unsigned long long start = md->phys_addr;
 		unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
 
 		if (md->type != EFI_BOOT_SERVICES_CODE &&
-		    md->type != EFI_BOOT_SERVICES_DATA)
+		    md->type != EFI_BOOT_SERVICES_DATA) {
+			num_entries++;
 			continue;
+		}
 
 		/* Do not free, someone else owns it: */
-		if (md->attribute & EFI_MEMORY_RUNTIME)
+		if (md->attribute & EFI_MEMORY_RUNTIME) {
+			num_entries++;
 			continue;
+		}
 
 		free_bootmem_late(start, size);
 	}
+
+	new_size = efi.memmap.desc_size * num_entries;
+	new_phys = memblock_alloc(new_size, 0);
+	if (!new_phys) {
+		pr_err("Failed to allocate new EFI memmap\n");
+		return;
+	}
+
+	new = memremap(new_phys, new_size, MEMREMAP_WB);
+	if (!new) {
+		pr_err("Failed to map new EFI memmap\n");
+		return;
+	}
+
+	/*
+	 * Build a new EFI memmap that excludes any boot services
+	 * regions that are not tagged EFI_MEMORY_RUNTIME, since those
+	 * regions have now been freed.
+	 */
+	new_md = new;
+	for_each_efi_memory_desc(md) {
+		if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
+		    (md->type == EFI_BOOT_SERVICES_CODE ||
+		     md->type == EFI_BOOT_SERVICES_DATA))
+			continue;
+
+		memcpy(new_md, md, efi.memmap.desc_size);
+		new_md += efi.memmap.desc_size;
+	}
+
+	memunmap(new);
+
+	if (efi_memmap_install(new_phys, num_entries)) {
+		pr_err("Could not install new EFI memmap\n");
+		return;
+	}
 }
 
 /*
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index d9c41a434462..ccd0095b91a1 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -24,6 +24,7 @@
 #include <linux/of_fdt.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/memblock.h>
 
 #include <asm/early_ioremap.h>
 
@@ -300,6 +301,35 @@ u64 __init efi_mem_desc_end(efi_memory_desc_t *md)
 	return end;
 }
 
+void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {}
+
+/**
+ * efi_mem_reserve - Reserve an EFI memory region
+ * @addr: Physical address to reserve
+ * @size: Size of reservation
+ *
+ * Mark a region as reserved from general kernel allocation and
+ * prevent it being released by efi_free_boot_services().
+ *
+ * This function should be called drivers once they've parsed EFI
+ * configuration tables to figure out where their data lives, e.g.
+ * efi_esrt_init().
+ */
+void __init efi_mem_reserve(phys_addr_t addr, u64 size)
+{
+	if (!memblock_is_region_reserved(addr, size))
+		memblock_reserve(addr, size);
+
+	/*
+	 * Some architectures (x86) reserve all boot services ranges
+	 * until efi_free_boot_services() because of buggy firmware
+	 * implementations. This means the above memblock_reserve() is
+	 * superfluous on x86 and instead what it needs to do is
+	 * ensure the @start, @size is not freed.
+	 */
+	efi_arch_mem_reserve(addr, size);
+}
+
 static __initdata efi_config_table_type_t common_tables[] = {
 	{ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
 	{ACPI_TABLE_GUID, "ACPI", &efi.acpi},
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 9fb390d56fbe..9f955dab9f77 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1017,6 +1017,7 @@ extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size);
 extern int __init efi_uart_console_only (void);
 extern u64 efi_mem_desc_end(efi_memory_desc_t *md);
 extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md);
+extern void efi_mem_reserve(phys_addr_t addr, u64 size);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
 		struct resource *data_resource, struct resource *bss_resource);
 extern void efi_get_time(struct timespec *now);
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 09/11] efi/runtime-map: Use efi.memmap directly instead of a copy
@ 2016-06-23 11:34   ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland

Now that efi.memmap is available all of the time there's no need to
allocate and build a separate copy of the EFI memory map.

Furthermore, efi.memmap contains boot services regions but only those
regions that have been reserved via efi_mem_reserve(). Using
efi.memmap allows us to pass boot services across kexec reboot so that
the ESRT and BGRT drivers will now work.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 arch/x86/platform/efi/efi.c        | 40 --------------------------------------
 drivers/firmware/efi/runtime-map.c | 35 +++++++++++++--------------------
 include/linux/efi.h                |  4 ----
 3 files changed, 13 insertions(+), 66 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 33bc6c12702c..8ac32128ca94 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -608,42 +608,6 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
 	}
 }
 
-static void __init save_runtime_map(void)
-{
-#ifdef CONFIG_KEXEC_CORE
-	unsigned long desc_size;
-	efi_memory_desc_t *md;
-	void *tmp, *q = NULL;
-	int count = 0;
-
-	if (efi_enabled(EFI_OLD_MEMMAP))
-		return;
-
-	desc_size = efi.memmap.desc_size;
-
-	for_each_efi_memory_desc(md) {
-		if (!(md->attribute & EFI_MEMORY_RUNTIME) ||
-		    (md->type == EFI_BOOT_SERVICES_CODE) ||
-		    (md->type == EFI_BOOT_SERVICES_DATA))
-			continue;
-		tmp = krealloc(q, (count + 1) * desc_size, GFP_KERNEL);
-		if (!tmp)
-			goto out;
-		q = tmp;
-
-		memcpy(q + count * desc_size, md, desc_size);
-		count++;
-	}
-
-	efi_runtime_map_setup(q, count, desc_size);
-	return;
-
-out:
-	kfree(q);
-	pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
-#endif
-}
-
 static void *realloc_pages(void *old_memmap, int old_shift)
 {
 	void *ret;
@@ -856,8 +820,6 @@ static void __init kexec_enter_virtual_mode(void)
 		return;
 	}
 
-	save_runtime_map();
-
 	BUG_ON(!efi.systab);
 
 	num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE);
@@ -950,8 +912,6 @@ static void __init __efi_enter_virtual_mode(void)
 		return;
 	}
 
-	save_runtime_map();
-
 	BUG_ON(!efi.systab);
 
 	if (efi_setup_page_tables(pa, 1 << pg_shift)) {
diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c
index 5c55227a34c8..8e64b77aeac9 100644
--- a/drivers/firmware/efi/runtime-map.c
+++ b/drivers/firmware/efi/runtime-map.c
@@ -14,10 +14,6 @@
 
 #include <asm/setup.h>
 
-static void *efi_runtime_map;
-static int nr_efi_runtime_map;
-static u32 efi_memdesc_size;
-
 struct efi_runtime_map_entry {
 	efi_memory_desc_t md;
 	struct kobject kobj;   /* kobject for each entry */
@@ -106,7 +102,8 @@ static struct kobj_type __refdata map_ktype = {
 static struct kset *map_kset;
 
 static struct efi_runtime_map_entry *
-add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
+add_sysfs_runtime_map_entry(struct kobject *kobj, int nr,
+			    efi_memory_desc_t *md)
 {
 	int ret;
 	struct efi_runtime_map_entry *entry;
@@ -124,8 +121,7 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
 		return ERR_PTR(-ENOMEM);
 	}
 
-	memcpy(&entry->md, efi_runtime_map + nr * efi_memdesc_size,
-	       sizeof(efi_memory_desc_t));
+	memcpy(&entry->md, md, sizeof(efi_memory_desc_t));
 
 	kobject_init(&entry->kobj, &map_ktype);
 	entry->kobj.kset = map_kset;
@@ -142,12 +138,12 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
 
 int efi_get_runtime_map_size(void)
 {
-	return nr_efi_runtime_map * efi_memdesc_size;
+	return efi.memmap.nr_map * efi.memmap.desc_size;
 }
 
 int efi_get_runtime_map_desc_size(void)
 {
-	return efi_memdesc_size;
+	return efi.memmap.desc_size;
 }
 
 int efi_runtime_map_copy(void *buf, size_t bufsz)
@@ -157,38 +153,33 @@ int efi_runtime_map_copy(void *buf, size_t bufsz)
 	if (sz > bufsz)
 		sz = bufsz;
 
-	memcpy(buf, efi_runtime_map, sz);
+	memcpy(buf, efi.memmap.map, sz);
 	return 0;
 }
 
-void efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size)
-{
-	efi_runtime_map = map;
-	nr_efi_runtime_map = nr_entries;
-	efi_memdesc_size = desc_size;
-}
-
 int __init efi_runtime_map_init(struct kobject *efi_kobj)
 {
 	int i, j, ret = 0;
 	struct efi_runtime_map_entry *entry;
+	efi_memory_desc_t *md;
 
-	if (!efi_runtime_map)
+	if (!efi_enabled(EFI_MEMMAP))
 		return 0;
 
-	map_entries = kzalloc(nr_efi_runtime_map * sizeof(entry), GFP_KERNEL);
+	map_entries = kzalloc(efi.memmap.nr_map * sizeof(entry), GFP_KERNEL);
 	if (!map_entries) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	for (i = 0; i < nr_efi_runtime_map; i++) {
-		entry = add_sysfs_runtime_map_entry(efi_kobj, i);
+	i = 0;
+	for_each_efi_memory_desc(md) {
+		entry = add_sysfs_runtime_map_entry(efi_kobj, i, md);
 		if (IS_ERR(entry)) {
 			ret = PTR_ERR(entry);
 			goto out_add_entry;
 		}
-		*(map_entries + i) = entry;
+		*(map_entries + i++) = entry;
 	}
 
 	return 0;
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 9f955dab9f77..729ce6f1af13 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1431,7 +1431,6 @@ extern int efi_capsule_update(efi_capsule_header_t *capsule,
 
 #ifdef CONFIG_EFI_RUNTIME_MAP
 int efi_runtime_map_init(struct kobject *);
-void efi_runtime_map_setup(void *, int, u32);
 int efi_get_runtime_map_size(void);
 int efi_get_runtime_map_desc_size(void);
 int efi_runtime_map_copy(void *buf, size_t bufsz);
@@ -1441,9 +1440,6 @@ static inline int efi_runtime_map_init(struct kobject *kobj)
 	return 0;
 }
 
-static inline void
-efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {}
-
 static inline int efi_get_runtime_map_size(void)
 {
 	return 0;
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 09/11] efi/runtime-map: Use efi.memmap directly instead of a copy
@ 2016-06-23 11:34   ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland

Now that efi.memmap is available all of the time there's no need to
allocate and build a separate copy of the EFI memory map.

Furthermore, efi.memmap contains boot services regions but only those
regions that have been reserved via efi_mem_reserve(). Using
efi.memmap allows us to pass boot services across kexec reboot so that
the ESRT and BGRT drivers will now work.

Cc: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Leif Lindholm <leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Borislav Petkov <bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org>
Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
---
 arch/x86/platform/efi/efi.c        | 40 --------------------------------------
 drivers/firmware/efi/runtime-map.c | 35 +++++++++++++--------------------
 include/linux/efi.h                |  4 ----
 3 files changed, 13 insertions(+), 66 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 33bc6c12702c..8ac32128ca94 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -608,42 +608,6 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
 	}
 }
 
-static void __init save_runtime_map(void)
-{
-#ifdef CONFIG_KEXEC_CORE
-	unsigned long desc_size;
-	efi_memory_desc_t *md;
-	void *tmp, *q = NULL;
-	int count = 0;
-
-	if (efi_enabled(EFI_OLD_MEMMAP))
-		return;
-
-	desc_size = efi.memmap.desc_size;
-
-	for_each_efi_memory_desc(md) {
-		if (!(md->attribute & EFI_MEMORY_RUNTIME) ||
-		    (md->type == EFI_BOOT_SERVICES_CODE) ||
-		    (md->type == EFI_BOOT_SERVICES_DATA))
-			continue;
-		tmp = krealloc(q, (count + 1) * desc_size, GFP_KERNEL);
-		if (!tmp)
-			goto out;
-		q = tmp;
-
-		memcpy(q + count * desc_size, md, desc_size);
-		count++;
-	}
-
-	efi_runtime_map_setup(q, count, desc_size);
-	return;
-
-out:
-	kfree(q);
-	pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
-#endif
-}
-
 static void *realloc_pages(void *old_memmap, int old_shift)
 {
 	void *ret;
@@ -856,8 +820,6 @@ static void __init kexec_enter_virtual_mode(void)
 		return;
 	}
 
-	save_runtime_map();
-
 	BUG_ON(!efi.systab);
 
 	num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE);
@@ -950,8 +912,6 @@ static void __init __efi_enter_virtual_mode(void)
 		return;
 	}
 
-	save_runtime_map();
-
 	BUG_ON(!efi.systab);
 
 	if (efi_setup_page_tables(pa, 1 << pg_shift)) {
diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c
index 5c55227a34c8..8e64b77aeac9 100644
--- a/drivers/firmware/efi/runtime-map.c
+++ b/drivers/firmware/efi/runtime-map.c
@@ -14,10 +14,6 @@
 
 #include <asm/setup.h>
 
-static void *efi_runtime_map;
-static int nr_efi_runtime_map;
-static u32 efi_memdesc_size;
-
 struct efi_runtime_map_entry {
 	efi_memory_desc_t md;
 	struct kobject kobj;   /* kobject for each entry */
@@ -106,7 +102,8 @@ static struct kobj_type __refdata map_ktype = {
 static struct kset *map_kset;
 
 static struct efi_runtime_map_entry *
-add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
+add_sysfs_runtime_map_entry(struct kobject *kobj, int nr,
+			    efi_memory_desc_t *md)
 {
 	int ret;
 	struct efi_runtime_map_entry *entry;
@@ -124,8 +121,7 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
 		return ERR_PTR(-ENOMEM);
 	}
 
-	memcpy(&entry->md, efi_runtime_map + nr * efi_memdesc_size,
-	       sizeof(efi_memory_desc_t));
+	memcpy(&entry->md, md, sizeof(efi_memory_desc_t));
 
 	kobject_init(&entry->kobj, &map_ktype);
 	entry->kobj.kset = map_kset;
@@ -142,12 +138,12 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr)
 
 int efi_get_runtime_map_size(void)
 {
-	return nr_efi_runtime_map * efi_memdesc_size;
+	return efi.memmap.nr_map * efi.memmap.desc_size;
 }
 
 int efi_get_runtime_map_desc_size(void)
 {
-	return efi_memdesc_size;
+	return efi.memmap.desc_size;
 }
 
 int efi_runtime_map_copy(void *buf, size_t bufsz)
@@ -157,38 +153,33 @@ int efi_runtime_map_copy(void *buf, size_t bufsz)
 	if (sz > bufsz)
 		sz = bufsz;
 
-	memcpy(buf, efi_runtime_map, sz);
+	memcpy(buf, efi.memmap.map, sz);
 	return 0;
 }
 
-void efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size)
-{
-	efi_runtime_map = map;
-	nr_efi_runtime_map = nr_entries;
-	efi_memdesc_size = desc_size;
-}
-
 int __init efi_runtime_map_init(struct kobject *efi_kobj)
 {
 	int i, j, ret = 0;
 	struct efi_runtime_map_entry *entry;
+	efi_memory_desc_t *md;
 
-	if (!efi_runtime_map)
+	if (!efi_enabled(EFI_MEMMAP))
 		return 0;
 
-	map_entries = kzalloc(nr_efi_runtime_map * sizeof(entry), GFP_KERNEL);
+	map_entries = kzalloc(efi.memmap.nr_map * sizeof(entry), GFP_KERNEL);
 	if (!map_entries) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	for (i = 0; i < nr_efi_runtime_map; i++) {
-		entry = add_sysfs_runtime_map_entry(efi_kobj, i);
+	i = 0;
+	for_each_efi_memory_desc(md) {
+		entry = add_sysfs_runtime_map_entry(efi_kobj, i, md);
 		if (IS_ERR(entry)) {
 			ret = PTR_ERR(entry);
 			goto out_add_entry;
 		}
-		*(map_entries + i) = entry;
+		*(map_entries + i++) = entry;
 	}
 
 	return 0;
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 9f955dab9f77..729ce6f1af13 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1431,7 +1431,6 @@ extern int efi_capsule_update(efi_capsule_header_t *capsule,
 
 #ifdef CONFIG_EFI_RUNTIME_MAP
 int efi_runtime_map_init(struct kobject *);
-void efi_runtime_map_setup(void *, int, u32);
 int efi_get_runtime_map_size(void);
 int efi_get_runtime_map_desc_size(void);
 int efi_runtime_map_copy(void *buf, size_t bufsz);
@@ -1441,9 +1440,6 @@ static inline int efi_runtime_map_init(struct kobject *kobj)
 	return 0;
 }
 
-static inline void
-efi_runtime_map_setup(void *map, int nr_entries, u32 desc_size) {}
-
 static inline int efi_get_runtime_map_size(void)
 {
 	return 0;
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 10/11] efi/esrt: Use efi_mem_reserve() and avoid a kmalloc()
  2016-06-23 11:34 [PATCH 00/11] efi: Permanent runtime EFI memmap support Matt Fleming
                   ` (8 preceding siblings ...)
  2016-06-23 11:34   ` Matt Fleming
@ 2016-06-23 11:34 ` Matt Fleming
  2016-06-23 11:34 ` [PATCH 11/11] x86/efi-bgrt: Use efi_mem_reserve() to avoid copying image data Matt Fleming
  2016-06-30 14:34   ` Dave Young
  11 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland, Dave Young

We can use the new efi_mem_reserve() API to mark the ESRT table as
reserved forever and save ourselves the trouble of copying the data
out into a kmalloc buffer.

The added advantage is that now the ESRT driver will work across
kexec reboot.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 drivers/firmware/efi/esrt.c | 20 ++++----------------
 1 file changed, 4 insertions(+), 16 deletions(-)

diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c
index 75feb3f5829b..b93cd11f9bcc 100644
--- a/drivers/firmware/efi/esrt.c
+++ b/drivers/firmware/efi/esrt.c
@@ -235,7 +235,7 @@ static struct attribute_group esrt_attr_group = {
 };
 
 /*
- * remap the table, copy it to kmalloced pages, and unmap it.
+ * remap the table, validate it, mark it reserved and unmap it.
  */
 void __init efi_esrt_init(void)
 {
@@ -335,7 +335,7 @@ void __init efi_esrt_init(void)
 
 	end = esrt_data + size;
 	pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end);
-	memblock_reserve(esrt_data, esrt_data_size);
+	efi_mem_reserve(esrt_data, esrt_data_size);
 
 	pr_debug("esrt-init: loaded.\n");
 err_memunmap:
@@ -382,28 +382,18 @@ static void cleanup_entry_list(void)
 static int __init esrt_sysfs_init(void)
 {
 	int error;
-	struct efi_system_resource_table __iomem *ioesrt;
 
 	pr_debug("esrt-sysfs: loading.\n");
 	if (!esrt_data || !esrt_data_size)
 		return -ENOSYS;
 
-	ioesrt = ioremap(esrt_data, esrt_data_size);
-	if (!ioesrt) {
+	esrt = ioremap(esrt_data, esrt_data_size);
+	if (!esrt) {
 		pr_err("ioremap(%pa, %zu) failed.\n", &esrt_data,
 		       esrt_data_size);
 		return -ENOMEM;
 	}
 
-	esrt = kmalloc(esrt_data_size, GFP_KERNEL);
-	if (!esrt) {
-		pr_err("kmalloc failed. (wanted %zu bytes)\n", esrt_data_size);
-		iounmap(ioesrt);
-		return -ENOMEM;
-	}
-
-	memcpy_fromio(esrt, ioesrt, esrt_data_size);
-
 	esrt_kobj = kobject_create_and_add("esrt", efi_kobj);
 	if (!esrt_kobj) {
 		pr_err("Firmware table registration failed.\n");
@@ -429,8 +419,6 @@ static int __init esrt_sysfs_init(void)
 	if (error)
 		goto err_cleanup_list;
 
-	memblock_remove(esrt_data, esrt_data_size);
-
 	pr_debug("esrt-sysfs: loaded.\n");
 
 	return 0;
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 11/11] x86/efi-bgrt: Use efi_mem_reserve() to avoid copying image data
  2016-06-23 11:34 [PATCH 00/11] efi: Permanent runtime EFI memmap support Matt Fleming
                   ` (9 preceding siblings ...)
  2016-06-23 11:34 ` [PATCH 10/11] efi/esrt: Use efi_mem_reserve() and avoid a kmalloc() Matt Fleming
@ 2016-06-23 11:34 ` Matt Fleming
  2016-06-30 14:41     ` Josh Triplett
  2016-06-30 14:34   ` Dave Young
  11 siblings, 1 reply; 27+ messages in thread
From: Matt Fleming @ 2016-06-23 11:34 UTC (permalink / raw)
  To: Ard Biesheuvel, Dave Young
  Cc: Matt Fleming, linux-kernel, linux-efi, Leif Lindholm,
	Peter Jones, Borislav Petkov, Mark Rutland, Josh Boyer,
	Josh Triplett, Andy Lutomirski, Môshe van der Sterre

efi_mem_reserve() allows us to permanently mark EFI boot services
regions as reserved, which means we no longer need to copy the image
data out and into a separate buffer.

Leaving the data in the original boot services region has the added
benefit that BGRT images can now be passed across kexec reboot.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Josh Boyer <jwboyer@fedoraproject.org>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Môshe van der Sterre <me@moshe.nl>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
---
 arch/x86/platform/efi/efi-bgrt.c | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
index 6a2f5691b1ab..6aad870e8962 100644
--- a/arch/x86/platform/efi/efi-bgrt.c
+++ b/arch/x86/platform/efi/efi-bgrt.c
@@ -82,21 +82,12 @@ void __init efi_bgrt_init(void)
 	}
 	bgrt_image_size = bmp_header.size;
 
-	bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL | __GFP_NOWARN);
+	bgrt_image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB);
 	if (!bgrt_image) {
-		pr_notice("Ignoring BGRT: failed to allocate memory for image (wanted %zu bytes)\n",
-		       bgrt_image_size);
-		return;
-	}
-
-	image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB);
-	if (!image) {
 		pr_notice("Ignoring BGRT: failed to map image memory\n");
-		kfree(bgrt_image);
 		bgrt_image = NULL;
 		return;
 	}
 
-	memcpy(bgrt_image, image, bgrt_image_size);
-	memunmap(image);
+	efi_mem_reserve(bgrt_tab->image_address, bgrt_image_size);
 }
-- 
2.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH 02/11] x86/efi: Consolidate region mapping logic
  2016-06-23 11:34 ` [PATCH 02/11] x86/efi: Consolidate region mapping logic Matt Fleming
@ 2016-06-23 14:00   ` Borislav Petkov
  0 siblings, 0 replies; 27+ messages in thread
From: Borislav Petkov @ 2016-06-23 14:00 UTC (permalink / raw)
  To: Matt Fleming; +Cc: Ard Biesheuvel, Dave Young, linux-kernel, linux-efi

On Thu, Jun 23, 2016 at 12:34:41PM +0100, Matt Fleming wrote:
> EFI regions are currently mapped in two separate places. The bulk of
> the work is done in efi_map_regions() but when CONFIG_EFI_MIXED is
> enabled the additional regions that are required when operating in
> mixed mode are mapping in efi_setup_page_tables().
> 
> Pull everything into efi_map_regions() and refactor the test for
> which regions should be mapped into a should_map_region() function.
> Generously sprinkle comments to clarify the different cases.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Borislav Petkov <bp@alien8.de>
> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
> ---
>  arch/x86/platform/efi/efi.c    | 50 ++++++++++++++++++++++++++++++++++++------
>  arch/x86/platform/efi/efi_64.c | 20 -----------------
>  2 files changed, 43 insertions(+), 27 deletions(-)

Looks good.

Acked-by: Borislav Petkov <bp@suse.de>

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
--

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code
@ 2016-06-24 11:44     ` Ard Biesheuvel
  0 siblings, 0 replies; 27+ messages in thread
From: Ard Biesheuvel @ 2016-06-24 11:44 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Dave Young, linux-kernel, linux-efi, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland

Hi Matt,

On 23 June 2016 at 13:34, Matt Fleming <matt@codeblueprint.co.uk> wrote:
> Every EFI architecture apart from ia64 needs to setup the EFI memory
> map at efi.memmap, and the code for doing that is essentially the same
> across all implementations. Therefore, it makes sense to factor this
> out into the common code under drivers/firmware/efi/.
>
> The only slight variation is the data structure out of which we pull
> the initial memory map information, such as physical address, memory
> descriptor size and version, etc. We can address this by passing a
> generic data structure (struct efi_memory_map_data) as the argument to
> efi_memmap_init_early() which contains the minimum info required for
> initialising the memory map.
>
> In the process, this patch also fixes a few undesirable implementation
> differences:
>
>  - ARM and arm64 were failing to clear the EFI_MEMMAP bit when
>    unmapping the early EFI memory map. EFI_MEMMAP indicates whether
>    the EFI memory map is mapped (not the regions contained within) and
>    can be traversed.  It's more correct to set the bit as soon as we
>    memremap() the passed in EFI memmap.
>

This patch (and the series) looks mostly fine to me, but this patch
does break ARM currently, please see below.

>  - Rename efi_unmmap_memmap() to efi_memmap_unmap() to adhere to the
>    regular naming scheme.
>
> This patch also uses a read-write mapping for the memory map instead
> of the read-only mapping currently used on ARM and arm64. x86 needs
> the ability to update the memory map in-place when assigning virtual
> addresses to regions (efi_map_region()) and tagging regions when
> reserving boot services (efi_reserve_boot_services()).
>
> There's no way for the generic fake_mem code to know which mapping to
> use without introducing some arch-specific constant/hook, so just use
> read-write since read-only is of dubious value for the EFI memory map.
>
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Cc: Peter Jones <pjones@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Dave Young <dyoung@redhat.com>
> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
> ---
>  arch/x86/include/asm/efi.h      |  1 -
>  arch/x86/platform/efi/efi.c     | 66 +++++++++++------------------------------
>  arch/x86/platform/efi/quirks.c  |  4 +--
>  drivers/firmware/efi/arm-init.c | 17 +++++------
>  drivers/firmware/efi/efi.c      | 46 ++++++++++++++++++++++++++++
>  drivers/firmware/efi/fake_mem.c | 15 ++++++----
>  include/linux/efi.h             | 16 ++++++++++
>  7 files changed, 98 insertions(+), 67 deletions(-)
>
> diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
> index 78d1e7467eae..67983035bd7b 100644
> --- a/arch/x86/include/asm/efi.h
> +++ b/arch/x86/include/asm/efi.h
> @@ -118,7 +118,6 @@ extern int __init efi_memblock_x86_reserve_range(void);
>  extern pgd_t * __init efi_call_phys_prolog(void);
>  extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
>  extern void __init efi_print_memmap(void);
> -extern void __init efi_unmap_memmap(void);
>  extern void __init efi_memory_uc(u64 addr, unsigned long size);
>  extern void __init efi_map_region(efi_memory_desc_t *md);
>  extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
> diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
> index 7c3d9092c668..b434c887229c 100644
> --- a/arch/x86/platform/efi/efi.c
> +++ b/arch/x86/platform/efi/efi.c
> @@ -188,7 +188,9 @@ static void __init do_add_efi_memmap(void)
>  int __init efi_memblock_x86_reserve_range(void)
>  {
>         struct efi_info *e = &boot_params.efi_info;
> +       struct efi_memory_map_data data;
>         phys_addr_t pmap;
> +       int rv;
>
>         if (efi_enabled(EFI_PARAVIRT))
>                 return 0;
> @@ -203,11 +205,17 @@ int __init efi_memblock_x86_reserve_range(void)
>  #else
>         pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32));
>  #endif
> -       efi.memmap.phys_map     = pmap;
> -       efi.memmap.nr_map       = e->efi_memmap_size /
> -                                 e->efi_memdesc_size;
> -       efi.memmap.desc_size    = e->efi_memdesc_size;
> -       efi.memmap.desc_version = e->efi_memdesc_version;
> +       data.phys_map           = pmap;
> +       data.size               = e->efi_memmap_size;
> +       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 (add_efi_memmap)
> +               do_add_efi_memmap();
>
>         WARN(efi.memmap.desc_version != 1,
>              "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
> @@ -234,19 +242,6 @@ void __init efi_print_memmap(void)
>         }
>  }
>
> -void __init efi_unmap_memmap(void)
> -{
> -       unsigned long size;
> -
> -       clear_bit(EFI_MEMMAP, &efi.flags);
> -
> -       size = efi.memmap.nr_map * efi.memmap.desc_size;
> -       if (efi.memmap.map) {
> -               early_memunmap(efi.memmap.map, size);
> -               efi.memmap.map = NULL;
> -       }
> -}
> -
>  static int __init efi_systab_init(void *phys)
>  {
>         if (efi_enabled(EFI_64BIT)) {
> @@ -430,33 +425,6 @@ static int __init efi_runtime_init(void)
>         return 0;
>  }
>
> -static int __init efi_memmap_init(void)
> -{
> -       unsigned long addr, size;
> -
> -       if (efi_enabled(EFI_PARAVIRT))
> -               return 0;
> -
> -       /* Map the EFI memory map */
> -       size = efi.memmap.nr_map * efi.memmap.desc_size;
> -       addr = (unsigned long)efi.memmap.phys_map;
> -
> -       efi.memmap.map = early_memremap(addr, size);
> -       if (efi.memmap.map == NULL) {
> -               pr_err("Could not map the memory map!\n");
> -               return -ENOMEM;
> -       }
> -
> -       efi.memmap.map_end = efi.memmap.map + size;
> -
> -       if (add_efi_memmap)
> -               do_add_efi_memmap();
> -
> -       set_bit(EFI_MEMMAP, &efi.flags);
> -
> -       return 0;
> -}
> -
>  void __init efi_init(void)
>  {
>         efi_char16_t *c16;
> @@ -514,11 +482,11 @@ void __init efi_init(void)
>         if (!efi_runtime_supported())
>                 pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
>         else {
> -               if (efi_runtime_disabled() || efi_runtime_init())
> +               if (efi_runtime_disabled() || efi_runtime_init()) {
> +                       efi_memmap_unmap();
>                         return;
> +               }
>         }
> -       if (efi_memmap_init())
> -               return;
>
>         if (efi_enabled(EFI_DBG))
>                 efi_print_memmap();
> @@ -855,7 +823,7 @@ static void __init kexec_enter_virtual_mode(void)
>          * non-native EFI
>          */
>         if (!efi_is_native()) {
> -               efi_unmap_memmap();
> +               efi_memmap_unmap();
>                 clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
>                 return;
>         }
> diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
> index 4480c06cade7..0af180004e74 100644
> --- a/arch/x86/platform/efi/quirks.c
> +++ b/arch/x86/platform/efi/quirks.c
> @@ -266,7 +266,7 @@ void __init efi_free_boot_services(void)
>                 free_bootmem_late(start, size);
>         }
>
> -       efi_unmap_memmap();
> +       efi_memmap_unmap();
>  }
>
>  /*
> @@ -344,7 +344,7 @@ void __init efi_apply_memmap_quirks(void)
>          */
>         if (!efi_runtime_supported()) {
>                 pr_info("Setup done, disabling due to 32/64-bit mismatch\n");
> -               efi_unmap_memmap();
> +               efi_memmap_unmap();
>         }
>
>         /* UV2+ BIOS has a fix for this issue.  UV1 still needs the quirk. */
> diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
> index c49d50e68aee..5a2df3fefccc 100644
> --- a/drivers/firmware/efi/arm-init.c
> +++ b/drivers/firmware/efi/arm-init.c
> @@ -211,12 +211,11 @@ static __init void reserve_regions(void)
>                         memblock_mark_nomap(paddr, size);
>
>         }
> -
> -       set_bit(EFI_MEMMAP, &efi.flags);
>  }
>
>  void __init efi_init(void)
>  {
> +       struct efi_memory_map_data data;
>         struct efi_fdt_params params;
>
>         /* Grab UEFI information placed in FDT by stub */
> @@ -225,9 +224,12 @@ void __init efi_init(void)
>
>         efi_system_table = params.system_table;
>
> -       efi.memmap.phys_map = params.mmap;
> -       efi.memmap.map = early_memremap_ro(params.mmap, params.mmap_size);
> -       if (efi.memmap.map == NULL) {
> +       data.desc_version = params.desc_ver;
> +       data.desc_size = params.desc_size;
> +       data.size = params.mmap_size;
> +       data.phys_map = params.mmap;
> +
> +       if (efi_memmap_init_early(&data) < 0) {
>                 /*
>                 * If we are booting via UEFI, the UEFI memory map is the only
>                 * description of memory we have, so there is little point in
> @@ -235,9 +237,6 @@ void __init efi_init(void)
>                 */
>                 panic("Unable to map EFI memory map.\n");
>         }
> -       efi.memmap.map_end = efi.memmap.map + params.mmap_size;
> -       efi.memmap.desc_size = params.desc_size;
> -       efi.memmap.desc_version = params.desc_ver;
>
>         WARN(efi.memmap.desc_version != 1,
>              "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
> @@ -248,7 +247,7 @@ void __init efi_init(void)
>
>         reserve_regions();
>         efi_memattr_init();
> -       early_memunmap(efi.memmap.map, params.mmap_size);
> +       efi_memmap_unmap();
>
>         memblock_reserve(params.mmap & PAGE_MASK,
>                          PAGE_ALIGN(params.mmap_size +
> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index 05509f3aaee8..3e6dce71f54d 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -448,6 +448,52 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
>         return ret;
>  }
>
> +/**
> + * efi_memmap_init_early - Map the EFI memory map data structure
> + * @data: EFI memory map data
> + *
> + * Use early_memremap() to map the passed in EFI memory map and assign
> + * it to efi.memmap.
> + */
> +int __init efi_memmap_init_early(struct efi_memory_map_data *data)
> +{
> +       struct efi_memory_map map;
> +
> +       if (efi_enabled(EFI_PARAVIRT))
> +               return 0;
> +
> +       map.phys_map = data->phys_map;
> +
> +       map.map = early_memremap(data->phys_map, data->size);
> +       if (!map.map) {
> +               pr_err("Could not map the memory map!\n");
> +               return -ENOMEM;
> +       }
> +
> +       map.nr_map = data->size / data->desc_size;
> +       map.map_end = map.map + data->size;
> +
> +       map.desc_version = data->desc_version;
> +       map.desc_size = data->desc_size;
> +
> +       set_bit(EFI_MEMMAP, &efi.flags);
> +
> +       efi.memmap = map;
> +
> +       return 0;
> +}
> +
> +void __init efi_memmap_unmap(void)
> +{
> +       unsigned long size;
> +
> +       size = efi.memmap.desc_size * efi.memmap.nr_map;
> +
> +       early_memunmap(efi.memmap.map, size);
> +       efi.memmap.map = NULL;

This assignment breaks the calculation of mapsize in
arm_enable_runtime_services(), so you should probably fold the
following hunk into this patch.

diff --git a/drivers/firmware/efi/arm-runtime.c
b/drivers/firmware/efi/arm-runtime.c
index ce1424672d89..1884347a3ef6 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -109,7 +109,7 @@ static int __init arm_enable_runtime_services(void)

        pr_info("Remapping and enabling EFI services.\n");

-       mapsize = efi.memmap.map_end - efi.memmap.map;
+       mapsize = efi.memmap.desc_size * efi.memmap.nr_map;

        if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
                pr_err("Failed to remap EFI memory map\n");


With that change (or an equivalent one):

Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code
@ 2016-06-24 11:44     ` Ard Biesheuvel
  0 siblings, 0 replies; 27+ messages in thread
From: Ard Biesheuvel @ 2016-06-24 11:44 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Dave Young, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland

Hi Matt,

On 23 June 2016 at 13:34, Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org> wrote:
> Every EFI architecture apart from ia64 needs to setup the EFI memory
> map at efi.memmap, and the code for doing that is essentially the same
> across all implementations. Therefore, it makes sense to factor this
> out into the common code under drivers/firmware/efi/.
>
> The only slight variation is the data structure out of which we pull
> the initial memory map information, such as physical address, memory
> descriptor size and version, etc. We can address this by passing a
> generic data structure (struct efi_memory_map_data) as the argument to
> efi_memmap_init_early() which contains the minimum info required for
> initialising the memory map.
>
> In the process, this patch also fixes a few undesirable implementation
> differences:
>
>  - ARM and arm64 were failing to clear the EFI_MEMMAP bit when
>    unmapping the early EFI memory map. EFI_MEMMAP indicates whether
>    the EFI memory map is mapped (not the regions contained within) and
>    can be traversed.  It's more correct to set the bit as soon as we
>    memremap() the passed in EFI memmap.
>

This patch (and the series) looks mostly fine to me, but this patch
does break ARM currently, please see below.

>  - Rename efi_unmmap_memmap() to efi_memmap_unmap() to adhere to the
>    regular naming scheme.
>
> This patch also uses a read-write mapping for the memory map instead
> of the read-only mapping currently used on ARM and arm64. x86 needs
> the ability to update the memory map in-place when assigning virtual
> addresses to regions (efi_map_region()) and tagging regions when
> reserving boot services (efi_reserve_boot_services()).
>
> There's no way for the generic fake_mem code to know which mapping to
> use without introducing some arch-specific constant/hook, so just use
> read-write since read-only is of dubious value for the EFI memory map.
>
> Cc: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Leif Lindholm <leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> Cc: Borislav Petkov <bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
> ---
>  arch/x86/include/asm/efi.h      |  1 -
>  arch/x86/platform/efi/efi.c     | 66 +++++++++++------------------------------
>  arch/x86/platform/efi/quirks.c  |  4 +--
>  drivers/firmware/efi/arm-init.c | 17 +++++------
>  drivers/firmware/efi/efi.c      | 46 ++++++++++++++++++++++++++++
>  drivers/firmware/efi/fake_mem.c | 15 ++++++----
>  include/linux/efi.h             | 16 ++++++++++
>  7 files changed, 98 insertions(+), 67 deletions(-)
>
> diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
> index 78d1e7467eae..67983035bd7b 100644
> --- a/arch/x86/include/asm/efi.h
> +++ b/arch/x86/include/asm/efi.h
> @@ -118,7 +118,6 @@ extern int __init efi_memblock_x86_reserve_range(void);
>  extern pgd_t * __init efi_call_phys_prolog(void);
>  extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
>  extern void __init efi_print_memmap(void);
> -extern void __init efi_unmap_memmap(void);
>  extern void __init efi_memory_uc(u64 addr, unsigned long size);
>  extern void __init efi_map_region(efi_memory_desc_t *md);
>  extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
> diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
> index 7c3d9092c668..b434c887229c 100644
> --- a/arch/x86/platform/efi/efi.c
> +++ b/arch/x86/platform/efi/efi.c
> @@ -188,7 +188,9 @@ static void __init do_add_efi_memmap(void)
>  int __init efi_memblock_x86_reserve_range(void)
>  {
>         struct efi_info *e = &boot_params.efi_info;
> +       struct efi_memory_map_data data;
>         phys_addr_t pmap;
> +       int rv;
>
>         if (efi_enabled(EFI_PARAVIRT))
>                 return 0;
> @@ -203,11 +205,17 @@ int __init efi_memblock_x86_reserve_range(void)
>  #else
>         pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32));
>  #endif
> -       efi.memmap.phys_map     = pmap;
> -       efi.memmap.nr_map       = e->efi_memmap_size /
> -                                 e->efi_memdesc_size;
> -       efi.memmap.desc_size    = e->efi_memdesc_size;
> -       efi.memmap.desc_version = e->efi_memdesc_version;
> +       data.phys_map           = pmap;
> +       data.size               = e->efi_memmap_size;
> +       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 (add_efi_memmap)
> +               do_add_efi_memmap();
>
>         WARN(efi.memmap.desc_version != 1,
>              "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
> @@ -234,19 +242,6 @@ void __init efi_print_memmap(void)
>         }
>  }
>
> -void __init efi_unmap_memmap(void)
> -{
> -       unsigned long size;
> -
> -       clear_bit(EFI_MEMMAP, &efi.flags);
> -
> -       size = efi.memmap.nr_map * efi.memmap.desc_size;
> -       if (efi.memmap.map) {
> -               early_memunmap(efi.memmap.map, size);
> -               efi.memmap.map = NULL;
> -       }
> -}
> -
>  static int __init efi_systab_init(void *phys)
>  {
>         if (efi_enabled(EFI_64BIT)) {
> @@ -430,33 +425,6 @@ static int __init efi_runtime_init(void)
>         return 0;
>  }
>
> -static int __init efi_memmap_init(void)
> -{
> -       unsigned long addr, size;
> -
> -       if (efi_enabled(EFI_PARAVIRT))
> -               return 0;
> -
> -       /* Map the EFI memory map */
> -       size = efi.memmap.nr_map * efi.memmap.desc_size;
> -       addr = (unsigned long)efi.memmap.phys_map;
> -
> -       efi.memmap.map = early_memremap(addr, size);
> -       if (efi.memmap.map == NULL) {
> -               pr_err("Could not map the memory map!\n");
> -               return -ENOMEM;
> -       }
> -
> -       efi.memmap.map_end = efi.memmap.map + size;
> -
> -       if (add_efi_memmap)
> -               do_add_efi_memmap();
> -
> -       set_bit(EFI_MEMMAP, &efi.flags);
> -
> -       return 0;
> -}
> -
>  void __init efi_init(void)
>  {
>         efi_char16_t *c16;
> @@ -514,11 +482,11 @@ void __init efi_init(void)
>         if (!efi_runtime_supported())
>                 pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
>         else {
> -               if (efi_runtime_disabled() || efi_runtime_init())
> +               if (efi_runtime_disabled() || efi_runtime_init()) {
> +                       efi_memmap_unmap();
>                         return;
> +               }
>         }
> -       if (efi_memmap_init())
> -               return;
>
>         if (efi_enabled(EFI_DBG))
>                 efi_print_memmap();
> @@ -855,7 +823,7 @@ static void __init kexec_enter_virtual_mode(void)
>          * non-native EFI
>          */
>         if (!efi_is_native()) {
> -               efi_unmap_memmap();
> +               efi_memmap_unmap();
>                 clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
>                 return;
>         }
> diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
> index 4480c06cade7..0af180004e74 100644
> --- a/arch/x86/platform/efi/quirks.c
> +++ b/arch/x86/platform/efi/quirks.c
> @@ -266,7 +266,7 @@ void __init efi_free_boot_services(void)
>                 free_bootmem_late(start, size);
>         }
>
> -       efi_unmap_memmap();
> +       efi_memmap_unmap();
>  }
>
>  /*
> @@ -344,7 +344,7 @@ void __init efi_apply_memmap_quirks(void)
>          */
>         if (!efi_runtime_supported()) {
>                 pr_info("Setup done, disabling due to 32/64-bit mismatch\n");
> -               efi_unmap_memmap();
> +               efi_memmap_unmap();
>         }
>
>         /* UV2+ BIOS has a fix for this issue.  UV1 still needs the quirk. */
> diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
> index c49d50e68aee..5a2df3fefccc 100644
> --- a/drivers/firmware/efi/arm-init.c
> +++ b/drivers/firmware/efi/arm-init.c
> @@ -211,12 +211,11 @@ static __init void reserve_regions(void)
>                         memblock_mark_nomap(paddr, size);
>
>         }
> -
> -       set_bit(EFI_MEMMAP, &efi.flags);
>  }
>
>  void __init efi_init(void)
>  {
> +       struct efi_memory_map_data data;
>         struct efi_fdt_params params;
>
>         /* Grab UEFI information placed in FDT by stub */
> @@ -225,9 +224,12 @@ void __init efi_init(void)
>
>         efi_system_table = params.system_table;
>
> -       efi.memmap.phys_map = params.mmap;
> -       efi.memmap.map = early_memremap_ro(params.mmap, params.mmap_size);
> -       if (efi.memmap.map == NULL) {
> +       data.desc_version = params.desc_ver;
> +       data.desc_size = params.desc_size;
> +       data.size = params.mmap_size;
> +       data.phys_map = params.mmap;
> +
> +       if (efi_memmap_init_early(&data) < 0) {
>                 /*
>                 * If we are booting via UEFI, the UEFI memory map is the only
>                 * description of memory we have, so there is little point in
> @@ -235,9 +237,6 @@ void __init efi_init(void)
>                 */
>                 panic("Unable to map EFI memory map.\n");
>         }
> -       efi.memmap.map_end = efi.memmap.map + params.mmap_size;
> -       efi.memmap.desc_size = params.desc_size;
> -       efi.memmap.desc_version = params.desc_ver;
>
>         WARN(efi.memmap.desc_version != 1,
>              "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
> @@ -248,7 +247,7 @@ void __init efi_init(void)
>
>         reserve_regions();
>         efi_memattr_init();
> -       early_memunmap(efi.memmap.map, params.mmap_size);
> +       efi_memmap_unmap();
>
>         memblock_reserve(params.mmap & PAGE_MASK,
>                          PAGE_ALIGN(params.mmap_size +
> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index 05509f3aaee8..3e6dce71f54d 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -448,6 +448,52 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
>         return ret;
>  }
>
> +/**
> + * efi_memmap_init_early - Map the EFI memory map data structure
> + * @data: EFI memory map data
> + *
> + * Use early_memremap() to map the passed in EFI memory map and assign
> + * it to efi.memmap.
> + */
> +int __init efi_memmap_init_early(struct efi_memory_map_data *data)
> +{
> +       struct efi_memory_map map;
> +
> +       if (efi_enabled(EFI_PARAVIRT))
> +               return 0;
> +
> +       map.phys_map = data->phys_map;
> +
> +       map.map = early_memremap(data->phys_map, data->size);
> +       if (!map.map) {
> +               pr_err("Could not map the memory map!\n");
> +               return -ENOMEM;
> +       }
> +
> +       map.nr_map = data->size / data->desc_size;
> +       map.map_end = map.map + data->size;
> +
> +       map.desc_version = data->desc_version;
> +       map.desc_size = data->desc_size;
> +
> +       set_bit(EFI_MEMMAP, &efi.flags);
> +
> +       efi.memmap = map;
> +
> +       return 0;
> +}
> +
> +void __init efi_memmap_unmap(void)
> +{
> +       unsigned long size;
> +
> +       size = efi.memmap.desc_size * efi.memmap.nr_map;
> +
> +       early_memunmap(efi.memmap.map, size);
> +       efi.memmap.map = NULL;

This assignment breaks the calculation of mapsize in
arm_enable_runtime_services(), so you should probably fold the
following hunk into this patch.

diff --git a/drivers/firmware/efi/arm-runtime.c
b/drivers/firmware/efi/arm-runtime.c
index ce1424672d89..1884347a3ef6 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -109,7 +109,7 @@ static int __init arm_enable_runtime_services(void)

        pr_info("Remapping and enabling EFI services.\n");

-       mapsize = efi.memmap.map_end - efi.memmap.map;
+       mapsize = efi.memmap.desc_size * efi.memmap.nr_map;

        if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
                pr_err("Failed to remap EFI memory map\n");


With that change (or an equivalent one):

Tested-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH 00/11] efi: Permanent runtime EFI memmap support
@ 2016-06-30 14:34   ` Dave Young
  0 siblings, 0 replies; 27+ messages in thread
From: Dave Young @ 2016-06-30 14:34 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Ard Biesheuvel, linux-kernel, linux-efi, Andy Lutomirski,
	Borislav Petkov, Josh Boyer, Josh Triplett, Kamezawa Hiroyuki,
	Leif Lindholm, Mark Rutland, Môshe van der Sterre,
	Peter Jones, Taku Izumi, Tony Luck, Xishi Qiu

Hi, Matt

On 06/23/16 at 12:34pm, Matt Fleming wrote:
> This series adds support for keeping the EFI memory map around at
> runtime for x86 (ARM and arm64 already have this support).
> 
> Additionally, drivers can now reserve EFI boot services regions such
> that they are not released back to the kernel during
> efi_free_boot_services().
> 
> With these two features it becomes possible to pass things like the
> EFI System Resource Table data structures across kexec reboot.
> 
> This series also includes a whole bunch of refactoring and cleanups to
> move code out of arch or driver-specific files into generic places.
> 
> I've given these patches some light testing, but it would be good if
> others could provide more given that this series touches so many
> different code paths.

Tested kexec/kdump and the bgrt reservation with kexec and kexec_file
system call. But due to a crypto issue I can not test signature
verification of kexec_file, but I think that is a separate problem.

For these parts:
Tested-by: Dave Young <dyoung@redhat.com>

Thanks
Dave

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 00/11] efi: Permanent runtime EFI memmap support
@ 2016-06-30 14:34   ` Dave Young
  0 siblings, 0 replies; 27+ messages in thread
From: Dave Young @ 2016-06-30 14:34 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Ard Biesheuvel, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Andy Lutomirski,
	Borislav Petkov, Josh Boyer, Josh Triplett, Kamezawa Hiroyuki,
	Leif Lindholm, Mark Rutland, Môshe van der Sterre,
	Peter Jones, Taku Izumi, Tony Luck, Xishi Qiu

Hi, Matt

On 06/23/16 at 12:34pm, Matt Fleming wrote:
> This series adds support for keeping the EFI memory map around at
> runtime for x86 (ARM and arm64 already have this support).
> 
> Additionally, drivers can now reserve EFI boot services regions such
> that they are not released back to the kernel during
> efi_free_boot_services().
> 
> With these two features it becomes possible to pass things like the
> EFI System Resource Table data structures across kexec reboot.
> 
> This series also includes a whole bunch of refactoring and cleanups to
> move code out of arch or driver-specific files into generic places.
> 
> I've given these patches some light testing, but it would be good if
> others could provide more given that this series touches so many
> different code paths.

Tested kexec/kdump and the bgrt reservation with kexec and kexec_file
system call. But due to a crypto issue I can not test signature
verification of kexec_file, but I think that is a separate problem.

For these parts:
Tested-by: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Thanks
Dave

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/11] x86/efi-bgrt: Use efi_mem_reserve() to avoid copying image data
@ 2016-06-30 14:41     ` Josh Triplett
  0 siblings, 0 replies; 27+ messages in thread
From: Josh Triplett @ 2016-06-30 14:41 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Ard Biesheuvel, Dave Young, linux-kernel, linux-efi,
	Leif Lindholm, Peter Jones, Borislav Petkov, Mark Rutland,
	Josh Boyer, Andy Lutomirski, Môshe van der Sterre

On Thu, Jun 23, 2016 at 12:34:50PM +0100, Matt Fleming wrote:
> efi_mem_reserve() allows us to permanently mark EFI boot services
> regions as reserved, which means we no longer need to copy the image
> data out and into a separate buffer.
> 
> Leaving the data in the original boot services region has the added
> benefit that BGRT images can now be passed across kexec reboot.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Cc: Peter Jones <pjones@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Dave Young <dyoung@redhat.com>
> Cc: Josh Boyer <jwboyer@fedoraproject.org>
> Cc: Josh Triplett <josh@joshtriplett.org>
> Cc: Andy Lutomirski <luto@amacapital.net>
> Cc: Môshe van der Sterre <me@moshe.nl>
> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>

Reviewed-by: Josh Triplett <josh@joshtriplett.org>

This definitely seems like an improvement.

>  arch/x86/platform/efi/efi-bgrt.c | 13 ++-----------
>  1 file changed, 2 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
> index 6a2f5691b1ab..6aad870e8962 100644
> --- a/arch/x86/platform/efi/efi-bgrt.c
> +++ b/arch/x86/platform/efi/efi-bgrt.c
> @@ -82,21 +82,12 @@ void __init efi_bgrt_init(void)
>  	}
>  	bgrt_image_size = bmp_header.size;
>  
> -	bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL | __GFP_NOWARN);
> +	bgrt_image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB);
>  	if (!bgrt_image) {
> -		pr_notice("Ignoring BGRT: failed to allocate memory for image (wanted %zu bytes)\n",
> -		       bgrt_image_size);
> -		return;
> -	}
> -
> -	image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB);
> -	if (!image) {
>  		pr_notice("Ignoring BGRT: failed to map image memory\n");
> -		kfree(bgrt_image);
>  		bgrt_image = NULL;
>  		return;
>  	}
>  
> -	memcpy(bgrt_image, image, bgrt_image_size);
> -	memunmap(image);
> +	efi_mem_reserve(bgrt_tab->image_address, bgrt_image_size);
>  }
> -- 
> 2.7.3
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/11] x86/efi-bgrt: Use efi_mem_reserve() to avoid copying image data
@ 2016-06-30 14:41     ` Josh Triplett
  0 siblings, 0 replies; 27+ messages in thread
From: Josh Triplett @ 2016-06-30 14:41 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Ard Biesheuvel, Dave Young, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland, Josh Boyer, Andy Lutomirski,
	Môshe van der Sterre

On Thu, Jun 23, 2016 at 12:34:50PM +0100, Matt Fleming wrote:
> efi_mem_reserve() allows us to permanently mark EFI boot services
> regions as reserved, which means we no longer need to copy the image
> data out and into a separate buffer.
> 
> Leaving the data in the original boot services region has the added
> benefit that BGRT images can now be passed across kexec reboot.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Leif Lindholm <leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> Cc: Borislav Petkov <bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Dave Young <dyoung-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> Cc: Josh Boyer <jwboyer-rxtnV0ftBwyoClj4AeEUq9i2O/JbrIOy@public.gmane.org>
> Cc: Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org>
> Cc: Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org>
> Cc: Môshe van der Sterre <me-A/3C56C7qwM@public.gmane.org>
> Signed-off-by: Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>

Reviewed-by: Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org>

This definitely seems like an improvement.

>  arch/x86/platform/efi/efi-bgrt.c | 13 ++-----------
>  1 file changed, 2 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
> index 6a2f5691b1ab..6aad870e8962 100644
> --- a/arch/x86/platform/efi/efi-bgrt.c
> +++ b/arch/x86/platform/efi/efi-bgrt.c
> @@ -82,21 +82,12 @@ void __init efi_bgrt_init(void)
>  	}
>  	bgrt_image_size = bmp_header.size;
>  
> -	bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL | __GFP_NOWARN);
> +	bgrt_image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB);
>  	if (!bgrt_image) {
> -		pr_notice("Ignoring BGRT: failed to allocate memory for image (wanted %zu bytes)\n",
> -		       bgrt_image_size);
> -		return;
> -	}
> -
> -	image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB);
> -	if (!image) {
>  		pr_notice("Ignoring BGRT: failed to map image memory\n");
> -		kfree(bgrt_image);
>  		bgrt_image = NULL;
>  		return;
>  	}
>  
> -	memcpy(bgrt_image, image, bgrt_image_size);
> -	memunmap(image);
> +	efi_mem_reserve(bgrt_tab->image_address, bgrt_image_size);
>  }
> -- 
> 2.7.3
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code
@ 2016-07-04 12:19       ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-07-04 12:19 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Dave Young, linux-kernel, linux-efi, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland

On Fri, 24 Jun, at 01:44:48PM, Ard Biesheuvel wrote:
> 
> This assignment breaks the calculation of mapsize in
> arm_enable_runtime_services(), so you should probably fold the
> following hunk into this patch.
> 
> diff --git a/drivers/firmware/efi/arm-runtime.c
> b/drivers/firmware/efi/arm-runtime.c
> index ce1424672d89..1884347a3ef6 100644
> --- a/drivers/firmware/efi/arm-runtime.c
> +++ b/drivers/firmware/efi/arm-runtime.c
> @@ -109,7 +109,7 @@ static int __init arm_enable_runtime_services(void)
> 
>         pr_info("Remapping and enabling EFI services.\n");
> 
> -       mapsize = efi.memmap.map_end - efi.memmap.map;
> +       mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
> 
>         if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
>                 pr_err("Failed to remap EFI memory map\n");
 
Thanks Ard, I folded this in.

> With that change (or an equivalent one):
> 
> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Are those tags for just this patch or the entire series?

FYI, my plan right now is to queue this for v4.9 because it's fairly
invasive and I expect some fallout. If anyone has a problem with that
and knows of a reason it should be queued sooner, please let me know.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code
@ 2016-07-04 12:19       ` Matt Fleming
  0 siblings, 0 replies; 27+ messages in thread
From: Matt Fleming @ 2016-07-04 12:19 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Dave Young, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland

On Fri, 24 Jun, at 01:44:48PM, Ard Biesheuvel wrote:
> 
> This assignment breaks the calculation of mapsize in
> arm_enable_runtime_services(), so you should probably fold the
> following hunk into this patch.
> 
> diff --git a/drivers/firmware/efi/arm-runtime.c
> b/drivers/firmware/efi/arm-runtime.c
> index ce1424672d89..1884347a3ef6 100644
> --- a/drivers/firmware/efi/arm-runtime.c
> +++ b/drivers/firmware/efi/arm-runtime.c
> @@ -109,7 +109,7 @@ static int __init arm_enable_runtime_services(void)
> 
>         pr_info("Remapping and enabling EFI services.\n");
> 
> -       mapsize = efi.memmap.map_end - efi.memmap.map;
> +       mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
> 
>         if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
>                 pr_err("Failed to remap EFI memory map\n");
 
Thanks Ard, I folded this in.

> With that change (or an equivalent one):
> 
> Tested-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Reviewed-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

Are those tags for just this patch or the entire series?

FYI, my plan right now is to queue this for v4.9 because it's fairly
invasive and I expect some fallout. If anyone has a problem with that
and knows of a reason it should be queued sooner, please let me know.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code
@ 2016-07-04 22:24         ` Ard Biesheuvel
  0 siblings, 0 replies; 27+ messages in thread
From: Ard Biesheuvel @ 2016-07-04 22:24 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Dave Young, linux-kernel, linux-efi, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland


> On 4 jul. 2016, at 20:19, Matt Fleming <matt@codeblueprint.co.uk> wrote:
> 
>> On Fri, 24 Jun, at 01:44:48PM, Ard Biesheuvel wrote:
>> 
>> This assignment breaks the calculation of mapsize in
>> arm_enable_runtime_services(), so you should probably fold the
>> following hunk into this patch.
>> 
>> diff --git a/drivers/firmware/efi/arm-runtime.c
>> b/drivers/firmware/efi/arm-runtime.c
>> index ce1424672d89..1884347a3ef6 100644
>> --- a/drivers/firmware/efi/arm-runtime.c
>> +++ b/drivers/firmware/efi/arm-runtime.c
>> @@ -109,7 +109,7 @@ static int __init arm_enable_runtime_services(void)
>> 
>>        pr_info("Remapping and enabling EFI services.\n");
>> 
>> -       mapsize = efi.memmap.map_end - efi.memmap.map;
>> +       mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
>> 
>>        if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
>>                pr_err("Failed to remap EFI memory map\n");
> 
> Thanks Ard, I folded this in.
> 
>> With that change (or an equivalent one):
>> 
>> Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> 
> Are those tags for just this patch or the entire series?
> 

That is for the series (but I only tested arm, so ymmv)

> FYI, my plan right now is to queue this for v4.9 because it's fairly
> invasive and I expect some fallout. If anyone has a problem with that
> and knows of a reason it should be queued sooner, please let me know.

No problem, but once you've queued it i'd like the arm esrt patches to go on top, ideally in the same release. I will dust those off once this series hits your tree

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code
@ 2016-07-04 22:24         ` Ard Biesheuvel
  0 siblings, 0 replies; 27+ messages in thread
From: Ard Biesheuvel @ 2016-07-04 22:24 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Dave Young, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-efi-u79uwXL29TY76Z2rM5mHXA, Leif Lindholm, Peter Jones,
	Borislav Petkov, Mark Rutland


> On 4 jul. 2016, at 20:19, Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org> wrote:
> 
>> On Fri, 24 Jun, at 01:44:48PM, Ard Biesheuvel wrote:
>> 
>> This assignment breaks the calculation of mapsize in
>> arm_enable_runtime_services(), so you should probably fold the
>> following hunk into this patch.
>> 
>> diff --git a/drivers/firmware/efi/arm-runtime.c
>> b/drivers/firmware/efi/arm-runtime.c
>> index ce1424672d89..1884347a3ef6 100644
>> --- a/drivers/firmware/efi/arm-runtime.c
>> +++ b/drivers/firmware/efi/arm-runtime.c
>> @@ -109,7 +109,7 @@ static int __init arm_enable_runtime_services(void)
>> 
>>        pr_info("Remapping and enabling EFI services.\n");
>> 
>> -       mapsize = efi.memmap.map_end - efi.memmap.map;
>> +       mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
>> 
>>        if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
>>                pr_err("Failed to remap EFI memory map\n");
> 
> Thanks Ard, I folded this in.
> 
>> With that change (or an equivalent one):
>> 
>> Tested-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> Reviewed-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> 
> Are those tags for just this patch or the entire series?
> 

That is for the series (but I only tested arm, so ymmv)

> FYI, my plan right now is to queue this for v4.9 because it's fairly
> invasive and I expect some fallout. If anyone has a problem with that
> and knows of a reason it should be queued sooner, please let me know.

No problem, but once you've queued it i'd like the arm esrt patches to go on top, ideally in the same release. I will dust those off once this series hits your tree--
To unsubscribe from this list: send the line "unsubscribe linux-efi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2016-07-04 22:24 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-23 11:34 [PATCH 00/11] efi: Permanent runtime EFI memmap support Matt Fleming
2016-06-23 11:34 ` [PATCH 01/11] x86/efi: Test for EFI_MEMMAP functionality when iterating EFI memmap Matt Fleming
2016-06-23 11:34 ` [PATCH 02/11] x86/efi: Consolidate region mapping logic Matt Fleming
2016-06-23 14:00   ` Borislav Petkov
2016-06-23 11:34 ` [PATCH 03/11] efi: Refactor efi_memmap_init_early() into arch-neutral code Matt Fleming
2016-06-23 11:34   ` Matt Fleming
2016-06-24 11:44   ` Ard Biesheuvel
2016-06-24 11:44     ` Ard Biesheuvel
2016-07-04 12:19     ` Matt Fleming
2016-07-04 12:19       ` Matt Fleming
2016-07-04 22:24       ` Ard Biesheuvel
2016-07-04 22:24         ` Ard Biesheuvel
2016-06-23 11:34 ` [PATCH 04/11] efi: Add efi_memmap_init_late() for permanent EFI memmap Matt Fleming
2016-06-23 11:34 ` [PATCH 05/11] efi/fake_mem: Refactor main two code chunks into functions Matt Fleming
2016-06-23 11:34 ` [PATCH 06/11] efi: Split out EFI memory map functions into new file Matt Fleming
2016-06-23 11:34   ` Matt Fleming
2016-06-23 11:34 ` [PATCH 07/11] efi: Add efi_memmap_install() for installing new EFI memory maps Matt Fleming
2016-06-23 11:34   ` Matt Fleming
2016-06-23 11:34 ` [PATCH 08/11] efi: Allow drivers to reserve boot services forever Matt Fleming
2016-06-23 11:34 ` [PATCH 09/11] efi/runtime-map: Use efi.memmap directly instead of a copy Matt Fleming
2016-06-23 11:34   ` Matt Fleming
2016-06-23 11:34 ` [PATCH 10/11] efi/esrt: Use efi_mem_reserve() and avoid a kmalloc() Matt Fleming
2016-06-23 11:34 ` [PATCH 11/11] x86/efi-bgrt: Use efi_mem_reserve() to avoid copying image data Matt Fleming
2016-06-30 14:41   ` Josh Triplett
2016-06-30 14:41     ` Josh Triplett
2016-06-30 14:34 ` [PATCH 00/11] efi: Permanent runtime EFI memmap support Dave Young
2016-06-30 14:34   ` Dave Young

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.