efi: memmap: Move EFI fake memmap support into x86 arch tree
authorArd Biesheuvel <ardb@kernel.org>
Sat, 1 Oct 2022 16:38:15 +0000 (18:38 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Fri, 18 Nov 2022 08:14:09 +0000 (09:14 +0100)
The EFI fake memmap support is specific to x86, which manipulates the
EFI memory map in various different ways after receiving it from the EFI
stub. On other architectures, we have managed to push back on this, and
the EFI memory map is kept pristine.

So let's move the fake memmap code into the x86 arch tree, where it
arguably belongs.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
arch/x86/Kconfig
arch/x86/include/asm/efi.h
arch/x86/kernel/setup.c
arch/x86/platform/efi/Makefile
arch/x86/platform/efi/fake_mem.c [new file with mode: 0644]
drivers/firmware/efi/Kconfig
drivers/firmware/efi/Makefile
drivers/firmware/efi/fake_mem.c [deleted file]
drivers/firmware/efi/fake_mem.h [deleted file]
drivers/firmware/efi/x86_fake_mem.c [deleted file]
include/linux/efi.h

index 67745ceab0dbc64cbca3e63e94ab92dbf976d571..e2f89a7495d28fdf240edcede692fe2133f42471 100644 (file)
@@ -1994,6 +1994,26 @@ config EFI_MIXED
 
          If unsure, say N.
 
+config EFI_FAKE_MEMMAP
+       bool "Enable EFI fake memory map"
+       depends on EFI
+       help
+         Saying Y here will enable "efi_fake_mem" boot option.  By specifying
+         this parameter, you can add arbitrary attribute to specific memory
+         range by updating original (firmware provided) EFI memmap.  This is
+         useful for debugging of EFI memmap related feature, e.g., Address
+         Range Mirroring feature.
+
+config EFI_MAX_FAKE_MEM
+       int "maximum allowable number of ranges in efi_fake_mem boot option"
+       depends on EFI_FAKE_MEMMAP
+       range 1 128
+       default 8
+       help
+         Maximum allowable number of ranges in efi_fake_mem boot option.
+         Ranges can be set up to this value using comma-separated list.
+         The default value is 8.
+
 source "kernel/Kconfig.hz"
 
 config KEXEC
index aaed31e640e5646e414f31734271dfb76f3f8c92..981eaf535703167335b24467dcbf321159af011a 100644 (file)
@@ -406,10 +406,15 @@ static inline void efi_reserve_boot_services(void)
 
 #ifdef CONFIG_EFI_FAKE_MEMMAP
 extern void __init efi_fake_memmap_early(void);
+extern void __init efi_fake_memmap(void);
 #else
 static inline void efi_fake_memmap_early(void)
 {
 }
+
+static inline void efi_fake_memmap(void)
+{
+}
 #endif
 
 #define arch_ima_efi_boot_mode \
index 216fee7144eefd4f76eca0d34df9bc84c2754bbc..41ec3a69f3c78f514b10c9b86fbe52779437ebe9 100644 (file)
@@ -31,6 +31,7 @@
 #include <xen/xen.h>
 
 #include <asm/apic.h>
+#include <asm/efi.h>
 #include <asm/numa.h>
 #include <asm/bios_ebda.h>
 #include <asm/bugs.h>
index a502451576859569628eb37c96a16374c6203ed8..b481719b16ccaf6b997972705d3b6118c47cadc8 100644 (file)
@@ -4,3 +4,4 @@ GCOV_PROFILE := n
 
 obj-$(CONFIG_EFI)              += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o
 obj-$(CONFIG_EFI_MIXED)                += efi_thunk_$(BITS).o
+obj-$(CONFIG_EFI_FAKE_MEMMAP)  += fake_mem.o
diff --git a/arch/x86/platform/efi/fake_mem.c b/arch/x86/platform/efi/fake_mem.c
new file mode 100644 (file)
index 0000000..41d57ca
--- /dev/null
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fake_mem.c
+ *
+ * Copyright (C) 2015 FUJITSU LIMITED
+ * Author: Taku Izumi <izumi.taku@jp.fujitsu.com>
+ *
+ * This code introduces new boot option named "efi_fake_mem"
+ * By specifying this parameter, you can add arbitrary attribute to
+ * specific memory range by updating original (firmware provided) EFI
+ * memmap.
+ */
+
+#include <linux/kernel.h>
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/memblock.h>
+#include <linux/types.h>
+#include <linux/sort.h>
+#include <asm/e820/api.h>
+#include <asm/efi.h>
+
+#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
+
+static struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
+static int nr_fake_mem;
+
+static int __init cmp_fake_mem(const void *x1, const void *x2)
+{
+       const struct efi_mem_range *m1 = x1;
+       const struct efi_mem_range *m2 = x2;
+
+       if (m1->range.start < m2->range.start)
+               return -1;
+       if (m1->range.start > m2->range.start)
+               return 1;
+       return 0;
+}
+
+static void __init efi_fake_range(struct efi_mem_range *efi_range)
+{
+       struct efi_memory_map_data data = { 0 };
+       int new_nr_map = efi.memmap.nr_map;
+       efi_memory_desc_t *md;
+       void *new_memmap;
+
+       /* count up the number of EFI memory descriptor */
+       for_each_efi_memory_desc(md)
+               new_nr_map += efi_memmap_split_count(md, &efi_range->range);
+
+       /* allocate memory for new EFI memmap */
+       if (efi_memmap_alloc(new_nr_map, &data) != 0)
+               return;
+
+       /* create new EFI memmap */
+       new_memmap = early_memremap(data.phys_map, data.size);
+       if (!new_memmap) {
+               __efi_memmap_free(data.phys_map, data.size, data.flags);
+               return;
+       }
+
+       efi_memmap_insert(&efi.memmap, new_memmap, efi_range);
+
+       /* swap into new EFI memmap */
+       early_memunmap(new_memmap, data.size);
+
+       efi_memmap_install(&data);
+}
+
+void __init efi_fake_memmap(void)
+{
+       int i;
+
+       if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
+               return;
+
+       for (i = 0; i < nr_fake_mem; i++)
+               efi_fake_range(&efi_fake_mems[i]);
+
+       /* print new EFI memmap */
+       efi_print_memmap();
+}
+
+static int __init setup_fake_mem(char *p)
+{
+       u64 start = 0, mem_size = 0, attribute = 0;
+       int i;
+
+       if (!p)
+               return -EINVAL;
+
+       while (*p != '\0') {
+               mem_size = memparse(p, &p);
+               if (*p == '@')
+                       start = memparse(p+1, &p);
+               else
+                       break;
+
+               if (*p == ':')
+                       attribute = simple_strtoull(p+1, &p, 0);
+               else
+                       break;
+
+               if (nr_fake_mem >= EFI_MAX_FAKEMEM)
+                       break;
+
+               efi_fake_mems[nr_fake_mem].range.start = start;
+               efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
+               efi_fake_mems[nr_fake_mem].attribute = attribute;
+               nr_fake_mem++;
+
+               if (*p == ',')
+                       p++;
+       }
+
+       sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
+            cmp_fake_mem, NULL);
+
+       for (i = 0; i < nr_fake_mem; i++)
+               pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
+                       efi_fake_mems[i].attribute, efi_fake_mems[i].range.start,
+                       efi_fake_mems[i].range.end);
+
+       return *p == '\0' ? 0 : -EINVAL;
+}
+
+early_param("efi_fake_mem", setup_fake_mem);
+
+void __init efi_fake_memmap_early(void)
+{
+       int i;
+
+       /*
+        * The late efi_fake_mem() call can handle all requests if
+        * EFI_MEMORY_SP support is disabled.
+        */
+       if (!efi_soft_reserve_enabled())
+               return;
+
+       if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
+               return;
+
+       /*
+        * Given that efi_fake_memmap() needs to perform memblock
+        * allocations it needs to run after e820__memblock_setup().
+        * However, if efi_fake_mem specifies EFI_MEMORY_SP for a given
+        * address range that potentially needs to mark the memory as
+        * reserved prior to e820__memblock_setup(). Update e820
+        * directly if EFI_MEMORY_SP is specified for an
+        * EFI_CONVENTIONAL_MEMORY descriptor.
+        */
+       for (i = 0; i < nr_fake_mem; i++) {
+               struct efi_mem_range *mem = &efi_fake_mems[i];
+               efi_memory_desc_t *md;
+               u64 m_start, m_end;
+
+               if ((mem->attribute & EFI_MEMORY_SP) == 0)
+                       continue;
+
+               m_start = mem->range.start;
+               m_end = mem->range.end;
+               for_each_efi_memory_desc(md) {
+                       u64 start, end, size;
+
+                       if (md->type != EFI_CONVENTIONAL_MEMORY)
+                               continue;
+
+                       start = md->phys_addr;
+                       end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
+
+                       if (m_start <= end && m_end >= start)
+                               /* fake range overlaps descriptor */;
+                       else
+                               continue;
+
+                       /*
+                        * Trim the boundary of the e820 update to the
+                        * descriptor in case the fake range overlaps
+                        * !EFI_CONVENTIONAL_MEMORY
+                        */
+                       start = max(start, m_start);
+                       end = min(end, m_end);
+                       size = end - start + 1;
+
+                       if (end <= start)
+                               continue;
+
+                       /*
+                        * Ensure each efi_fake_mem instance results in
+                        * a unique e820 resource
+                        */
+                       e820__range_remove(start, size, E820_TYPE_RAM, 1);
+                       e820__range_add(start, size, E820_TYPE_SOFT_RESERVED);
+                       e820__update_table(e820_table);
+               }
+       }
+}
index c666ea4f125298d0f37c70db5f936ec735876d9c..0d5201e4984189bca7933efdd4bd1e960614109d 100644 (file)
@@ -37,28 +37,6 @@ config EFI_RUNTIME_MAP
 
          See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
 
-config EFI_FAKE_MEMMAP
-       bool "Enable EFI fake memory map"
-       depends on EFI && X86
-       default n
-       help
-         Saying Y here will enable "efi_fake_mem" boot option.
-         By specifying this parameter, you can add arbitrary attribute
-         to specific memory range by updating original (firmware provided)
-         EFI memmap.
-         This is useful for debugging of EFI memmap related feature.
-         e.g. Address Range Mirroring feature.
-
-config EFI_MAX_FAKE_MEM
-       int "maximum allowable number of ranges in efi_fake_mem boot option"
-       depends on EFI_FAKE_MEMMAP
-       range 1 128
-       default 8
-       help
-         Maximum allowable number of ranges in efi_fake_mem boot option.
-         Ranges can be set up to this value using comma-separated list.
-         The default value is 8.
-
 config EFI_SOFT_RESERVE
        bool "Reserve EFI Specific Purpose Memory"
        depends on EFI && EFI_STUB && ACPI_HMAT
index 8d151e332584d0fd52cb4ed8a83373e01aac66b8..8e4f0d5b26e542c36819c1cf69c63597183abcea 100644 (file)
@@ -23,7 +23,6 @@ obj-$(CONFIG_UEFI_CPER)                       += cper.o
 obj-$(CONFIG_EFI_RUNTIME_MAP)          += runtime-map.o
 obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)     += runtime-wrappers.o
 subdir-$(CONFIG_EFI_STUB)              += libstub
-obj-$(CONFIG_EFI_FAKE_MEMMAP)          += fake_map.o
 obj-$(CONFIG_EFI_BOOTLOADER_CONTROL)   += efibc.o
 obj-$(CONFIG_EFI_TEST)                 += test/
 obj-$(CONFIG_EFI_DEV_PATH_PARSER)      += dev-path-parser.o
@@ -32,9 +31,6 @@ obj-$(CONFIG_EFI_RCI2_TABLE)          += rci2-table.o
 obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE)    += embedded-firmware.o
 obj-$(CONFIG_LOAD_UEFI_KEYS)           += mokvar-table.o
 
-fake_map-y                             += fake_mem.o
-fake_map-$(CONFIG_X86)                 += x86_fake_mem.o
-
 obj-$(CONFIG_SYSFB)                    += sysfb_efi.o
 
 arm-obj-$(CONFIG_EFI)                  := efi-init.o arm-runtime.o
diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c
deleted file mode 100644 (file)
index 6e0f34a..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * fake_mem.c
- *
- * Copyright (C) 2015 FUJITSU LIMITED
- * Author: Taku Izumi <izumi.taku@jp.fujitsu.com>
- *
- * This code introduces new boot option named "efi_fake_mem"
- * By specifying this parameter, you can add arbitrary attribute to
- * specific memory range by updating original (firmware provided) EFI
- * memmap.
- */
-
-#include <linux/kernel.h>
-#include <linux/efi.h>
-#include <linux/init.h>
-#include <linux/memblock.h>
-#include <linux/types.h>
-#include <linux/sort.h>
-#include "fake_mem.h"
-
-struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
-int nr_fake_mem;
-
-static int __init cmp_fake_mem(const void *x1, const void *x2)
-{
-       const struct efi_mem_range *m1 = x1;
-       const struct efi_mem_range *m2 = x2;
-
-       if (m1->range.start < m2->range.start)
-               return -1;
-       if (m1->range.start > m2->range.start)
-               return 1;
-       return 0;
-}
-
-static void __init efi_fake_range(struct efi_mem_range *efi_range)
-{
-       struct efi_memory_map_data data = { 0 };
-       int new_nr_map = efi.memmap.nr_map;
-       efi_memory_desc_t *md;
-       void *new_memmap;
-
-       /* count up the number of EFI memory descriptor */
-       for_each_efi_memory_desc(md)
-               new_nr_map += efi_memmap_split_count(md, &efi_range->range);
-
-       /* allocate memory for new EFI memmap */
-       if (efi_memmap_alloc(new_nr_map, &data) != 0)
-               return;
-
-       /* create new EFI memmap */
-       new_memmap = early_memremap(data.phys_map, data.size);
-       if (!new_memmap) {
-               __efi_memmap_free(data.phys_map, data.size, data.flags);
-               return;
-       }
-
-       efi_memmap_insert(&efi.memmap, new_memmap, efi_range);
-
-       /* swap into new EFI memmap */
-       early_memunmap(new_memmap, data.size);
-
-       efi_memmap_install(&data);
-}
-
-void __init efi_fake_memmap(void)
-{
-       int i;
-
-       if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
-               return;
-
-       for (i = 0; i < nr_fake_mem; i++)
-               efi_fake_range(&efi_fake_mems[i]);
-
-       /* print new EFI memmap */
-       efi_print_memmap();
-}
-
-static int __init setup_fake_mem(char *p)
-{
-       u64 start = 0, mem_size = 0, attribute = 0;
-       int i;
-
-       if (!p)
-               return -EINVAL;
-
-       while (*p != '\0') {
-               mem_size = memparse(p, &p);
-               if (*p == '@')
-                       start = memparse(p+1, &p);
-               else
-                       break;
-
-               if (*p == ':')
-                       attribute = simple_strtoull(p+1, &p, 0);
-               else
-                       break;
-
-               if (nr_fake_mem >= EFI_MAX_FAKEMEM)
-                       break;
-
-               efi_fake_mems[nr_fake_mem].range.start = start;
-               efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
-               efi_fake_mems[nr_fake_mem].attribute = attribute;
-               nr_fake_mem++;
-
-               if (*p == ',')
-                       p++;
-       }
-
-       sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
-            cmp_fake_mem, NULL);
-
-       for (i = 0; i < nr_fake_mem; i++)
-               pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
-                       efi_fake_mems[i].attribute, efi_fake_mems[i].range.start,
-                       efi_fake_mems[i].range.end);
-
-       return *p == '\0' ? 0 : -EINVAL;
-}
-
-early_param("efi_fake_mem", setup_fake_mem);
diff --git a/drivers/firmware/efi/fake_mem.h b/drivers/firmware/efi/fake_mem.h
deleted file mode 100644 (file)
index d52791a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __EFI_FAKE_MEM_H__
-#define __EFI_FAKE_MEM_H__
-#include <asm/efi.h>
-
-#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
-
-extern struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
-extern int nr_fake_mem;
-#endif /* __EFI_FAKE_MEM_H__ */
diff --git a/drivers/firmware/efi/x86_fake_mem.c b/drivers/firmware/efi/x86_fake_mem.c
deleted file mode 100644 (file)
index 0bafcc1..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 2019 Intel Corporation. All rights reserved. */
-#include <linux/efi.h>
-#include <asm/e820/api.h>
-#include "fake_mem.h"
-
-void __init efi_fake_memmap_early(void)
-{
-       int i;
-
-       /*
-        * The late efi_fake_mem() call can handle all requests if
-        * EFI_MEMORY_SP support is disabled.
-        */
-       if (!efi_soft_reserve_enabled())
-               return;
-
-       if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
-               return;
-
-       /*
-        * Given that efi_fake_memmap() needs to perform memblock
-        * allocations it needs to run after e820__memblock_setup().
-        * However, if efi_fake_mem specifies EFI_MEMORY_SP for a given
-        * address range that potentially needs to mark the memory as
-        * reserved prior to e820__memblock_setup(). Update e820
-        * directly if EFI_MEMORY_SP is specified for an
-        * EFI_CONVENTIONAL_MEMORY descriptor.
-        */
-       for (i = 0; i < nr_fake_mem; i++) {
-               struct efi_mem_range *mem = &efi_fake_mems[i];
-               efi_memory_desc_t *md;
-               u64 m_start, m_end;
-
-               if ((mem->attribute & EFI_MEMORY_SP) == 0)
-                       continue;
-
-               m_start = mem->range.start;
-               m_end = mem->range.end;
-               for_each_efi_memory_desc(md) {
-                       u64 start, end, size;
-
-                       if (md->type != EFI_CONVENTIONAL_MEMORY)
-                               continue;
-
-                       start = md->phys_addr;
-                       end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
-
-                       if (m_start <= end && m_end >= start)
-                               /* fake range overlaps descriptor */;
-                       else
-                               continue;
-
-                       /*
-                        * Trim the boundary of the e820 update to the
-                        * descriptor in case the fake range overlaps
-                        * !EFI_CONVENTIONAL_MEMORY
-                        */
-                       start = max(start, m_start);
-                       end = min(end, m_end);
-                       size = end - start + 1;
-
-                       if (end <= start)
-                               continue;
-
-                       /*
-                        * Ensure each efi_fake_mem instance results in
-                        * a unique e820 resource
-                        */
-                       e820__range_remove(start, size, E820_TYPE_RAM, 1);
-                       e820__range_add(start, size, E820_TYPE_SOFT_RESERVED);
-                       e820__update_table(e820_table);
-               }
-       }
-}
index ee034f0c5cc250b1522eda9865ebc3968c3a4b80..43146530374e7240b77dd375426f0db614dac0bf 100644 (file)
@@ -749,12 +749,6 @@ extern struct kobject *efi_kobj;
 extern int efi_reboot_quirk_mode;
 extern bool efi_poweroff_required(void);
 
-#ifdef CONFIG_EFI_FAKE_MEMMAP
-extern void __init efi_fake_memmap(void);
-#else
-static inline void efi_fake_memmap(void) { }
-#endif
-
 extern unsigned long efi_mem_attr_table;
 
 /*