Commit 4059ba65 authored by Ard Biesheuvel's avatar Ard Biesheuvel

efi: memmap: Move EFI fake memmap support into x86 arch tree

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: default avatarArd Biesheuvel <ardb@kernel.org>
parent 75e1a246
...@@ -1994,6 +1994,26 @@ config EFI_MIXED ...@@ -1994,6 +1994,26 @@ config EFI_MIXED
If unsure, say N. 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" source "kernel/Kconfig.hz"
config KEXEC config KEXEC
......
...@@ -406,10 +406,15 @@ static inline void efi_reserve_boot_services(void) ...@@ -406,10 +406,15 @@ static inline void efi_reserve_boot_services(void)
#ifdef CONFIG_EFI_FAKE_MEMMAP #ifdef CONFIG_EFI_FAKE_MEMMAP
extern void __init efi_fake_memmap_early(void); extern void __init efi_fake_memmap_early(void);
extern void __init efi_fake_memmap(void);
#else #else
static inline void efi_fake_memmap_early(void) static inline void efi_fake_memmap_early(void)
{ {
} }
static inline void efi_fake_memmap(void)
{
}
#endif #endif
#define arch_ima_efi_boot_mode \ #define arch_ima_efi_boot_mode \
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <xen/xen.h> #include <xen/xen.h>
#include <asm/apic.h> #include <asm/apic.h>
#include <asm/efi.h>
#include <asm/numa.h> #include <asm/numa.h>
#include <asm/bios_ebda.h> #include <asm/bios_ebda.h>
#include <asm/bugs.h> #include <asm/bugs.h>
......
...@@ -4,3 +4,4 @@ GCOV_PROFILE := n ...@@ -4,3 +4,4 @@ GCOV_PROFILE := n
obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o 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_MIXED) += efi_thunk_$(BITS).o
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o
...@@ -17,10 +17,13 @@ ...@@ -17,10 +17,13 @@
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/sort.h> #include <linux/sort.h>
#include "fake_mem.h" #include <asm/e820/api.h>
#include <asm/efi.h>
struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM]; #define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
int nr_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) static int __init cmp_fake_mem(const void *x1, const void *x2)
{ {
...@@ -122,3 +125,73 @@ static int __init setup_fake_mem(char *p) ...@@ -122,3 +125,73 @@ static int __init setup_fake_mem(char *p)
} }
early_param("efi_fake_mem", setup_fake_mem); 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);
}
}
}
...@@ -37,28 +37,6 @@ config EFI_RUNTIME_MAP ...@@ -37,28 +37,6 @@ config EFI_RUNTIME_MAP
See also Documentation/ABI/testing/sysfs-firmware-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 config EFI_SOFT_RESERVE
bool "Reserve EFI Specific Purpose Memory" bool "Reserve EFI Specific Purpose Memory"
depends on EFI && EFI_STUB && ACPI_HMAT depends on EFI && EFI_STUB && ACPI_HMAT
......
...@@ -23,7 +23,6 @@ obj-$(CONFIG_UEFI_CPER) += cper.o ...@@ -23,7 +23,6 @@ obj-$(CONFIG_UEFI_CPER) += cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
subdir-$(CONFIG_EFI_STUB) += libstub subdir-$(CONFIG_EFI_STUB) += libstub
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_map.o
obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
obj-$(CONFIG_EFI_TEST) += test/ obj-$(CONFIG_EFI_TEST) += test/
obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o
...@@ -32,9 +31,6 @@ obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o ...@@ -32,9 +31,6 @@ obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o
obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += embedded-firmware.o obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += embedded-firmware.o
obj-$(CONFIG_LOAD_UEFI_KEYS) += mokvar-table.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 obj-$(CONFIG_SYSFB) += sysfb_efi.o
arm-obj-$(CONFIG_EFI) := efi-init.o arm-runtime.o arm-obj-$(CONFIG_EFI) := efi-init.o arm-runtime.o
......
/* 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__ */
// 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);
}
}
}
...@@ -749,12 +749,6 @@ extern struct kobject *efi_kobj; ...@@ -749,12 +749,6 @@ extern struct kobject *efi_kobj;
extern int efi_reboot_quirk_mode; extern int efi_reboot_quirk_mode;
extern bool efi_poweroff_required(void); 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; extern unsigned long efi_mem_attr_table;
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment