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

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
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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	\
+1 −0
Original line number Diff line number Diff line
@@ -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>
+1 −0
Original line number Diff line number Diff line
@@ -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
+76 −3
Original line number Diff line number Diff line
@@ -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);
		}
	}
}
Loading