efi: Refactor efi_memmap_init_early() into arch-neutral code

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.

Tested-by: Dave Young <[email protected]> [kexec/kdump]
Tested-by: Ard Biesheuvel <[email protected]> [arm]
Acked-by: Ard Biesheuvel <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Peter Jones <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Mark Rutland <[email protected]>
Signed-off-by: Matt Fleming <[email protected]>
This commit is contained in:
Matt Fleming 2016-02-26 21:22:05 +00:00
commit 9479c7cebf
8 changed files with 99 additions and 68 deletions

View file

@ -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 +

View file

@ -114,7 +114,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;
efi.memmap.map = memremap(efi.memmap.phys_map, mapsize, MEMREMAP_WB);
if (!efi.memmap.map) {

View file

@ -544,6 +544,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)
{

View file

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