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: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Ard Biesheuvel 2022-10-01 18:38:15 +02:00
parent 75e1a2460d
commit 4059ba656c
10 changed files with 103 additions and 120 deletions

View 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

View 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 \

View 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>

View 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

View File

@ -17,10 +17,13 @@
#include <linux/memblock.h>
#include <linux/types.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];
int nr_fake_mem;
#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
static struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
static int nr_fake_mem;
static int __init cmp_fake_mem(const void *x1, const void *x2)
{
@ -122,3 +125,73 @@ static int __init setup_fake_mem(char *p)
}
early_param("efi_fake_mem", setup_fake_mem);
void __init efi_fake_memmap_early(void)
{
int i;
/*
* The late efi_fake_mem() call can handle all requests if
* EFI_MEMORY_SP support is disabled.
*/
if (!efi_soft_reserve_enabled())
return;
if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
return;
/*
* Given that efi_fake_memmap() needs to perform memblock
* allocations it needs to run after e820__memblock_setup().
* However, if efi_fake_mem specifies EFI_MEMORY_SP for a given
* address range that potentially needs to mark the memory as
* reserved prior to e820__memblock_setup(). Update e820
* directly if EFI_MEMORY_SP is specified for an
* EFI_CONVENTIONAL_MEMORY descriptor.
*/
for (i = 0; i < nr_fake_mem; i++) {
struct efi_mem_range *mem = &efi_fake_mems[i];
efi_memory_desc_t *md;
u64 m_start, m_end;
if ((mem->attribute & EFI_MEMORY_SP) == 0)
continue;
m_start = mem->range.start;
m_end = mem->range.end;
for_each_efi_memory_desc(md) {
u64 start, end, size;
if (md->type != EFI_CONVENTIONAL_MEMORY)
continue;
start = md->phys_addr;
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
if (m_start <= end && m_end >= start)
/* fake range overlaps descriptor */;
else
continue;
/*
* Trim the boundary of the e820 update to the
* descriptor in case the fake range overlaps
* !EFI_CONVENTIONAL_MEMORY
*/
start = max(start, m_start);
end = min(end, m_end);
size = end - start + 1;
if (end <= start)
continue;
/*
* Ensure each efi_fake_mem instance results in
* a unique e820 resource
*/
e820__range_remove(start, size, E820_TYPE_RAM, 1);
e820__range_add(start, size, E820_TYPE_SOFT_RESERVED);
e820__update_table(e820_table);
}
}
}

View 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

View 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

View File

@ -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__ */

View File

@ -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);
}
}
}

View 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;
/*