Skip to content

Commit dca0f97

Browse files
committed
efi: Add efi_memmap_init_late() for permanent EFI memmap
Drivers need a way to access the EFI memory map at runtime. ARM and arm64 currently provide this by remapping the EFI memory map into the vmalloc space before setting up the EFI virtual mappings. x86 does not provide this functionality which has resulted in the code in efi_mem_desc_lookup() where it will manually map individual EFI memmap entries if the memmap has already been torn down on x86, /* * If a driver calls this after efi_free_boot_services, * ->map will be NULL, and the target may also not be mapped. * So just always get our own virtual map on the CPU. * */ md = early_memremap(p, sizeof (*md)); There isn't a good reason for not providing a permanent EFI memory map for runtime queries, especially since the EFI regions are not mapped into the standard kernel page tables. Tested-by: Dave Young <dyoung@redhat.com> [kexec/kdump] Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> [arm] Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Leif Lindholm <leif.lindholm@linaro.org> Cc: Peter Jones <pjones@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
1 parent 9479c7c commit dca0f97

File tree

5 files changed

+130
-57
lines changed

5 files changed

+130
-57
lines changed

arch/x86/platform/efi/efi.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,19 @@ static void __init kexec_enter_virtual_mode(void)
827827
get_systab_virt_addr(md);
828828
}
829829

830+
/*
831+
* Unregister the early EFI memmap from efi_init() and install
832+
* the new EFI memory map.
833+
*/
834+
efi_memmap_unmap();
835+
836+
if (efi_memmap_init_late(efi.memmap.phys_map,
837+
efi.memmap.desc_size * efi.memmap.nr_map)) {
838+
pr_err("Failed to remap late EFI memory map\n");
839+
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
840+
return;
841+
}
842+
830843
save_runtime_map();
831844

832845
BUG_ON(!efi.systab);
@@ -888,6 +901,7 @@ static void __init __efi_enter_virtual_mode(void)
888901
int count = 0, pg_shift = 0;
889902
void *new_memmap = NULL;
890903
efi_status_t status;
904+
phys_addr_t pa;
891905

892906
efi.systab = NULL;
893907

@@ -905,11 +919,26 @@ static void __init __efi_enter_virtual_mode(void)
905919
return;
906920
}
907921

922+
pa = __pa(new_memmap);
923+
924+
/*
925+
* Unregister the early EFI memmap from efi_init() and install
926+
* the new EFI memory map that we are about to pass to the
927+
* firmware via SetVirtualAddressMap().
928+
*/
929+
efi_memmap_unmap();
930+
931+
if (efi_memmap_init_late(pa, efi.memmap.desc_size * count)) {
932+
pr_err("Failed to remap late EFI memory map\n");
933+
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
934+
return;
935+
}
936+
908937
save_runtime_map();
909938

910939
BUG_ON(!efi.systab);
911940

912-
if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift)) {
941+
if (efi_setup_page_tables(pa, 1 << pg_shift)) {
913942
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
914943
return;
915944
}
@@ -921,14 +950,14 @@ static void __init __efi_enter_virtual_mode(void)
921950
efi.memmap.desc_size * count,
922951
efi.memmap.desc_size,
923952
efi.memmap.desc_version,
924-
(efi_memory_desc_t *)__pa(new_memmap));
953+
(efi_memory_desc_t *)pa);
925954
} else {
926955
status = efi_thunk_set_virtual_address_map(
927956
efi_phys.set_virtual_address_map,
928957
efi.memmap.desc_size * count,
929958
efi.memmap.desc_size,
930959
efi.memmap.desc_version,
931-
(efi_memory_desc_t *)__pa(new_memmap));
960+
(efi_memory_desc_t *)pa);
932961
}
933962

934963
if (status != EFI_SUCCESS) {
@@ -960,15 +989,6 @@ static void __init __efi_enter_virtual_mode(void)
960989
efi_runtime_update_mappings();
961990
efi_dump_pagetable();
962991

963-
/*
964-
* We mapped the descriptor array into the EFI pagetable above
965-
* but we're not unmapping it here because if we're running in
966-
* EFI mixed mode we need all of memory to be accessible when
967-
* we pass parameters to the EFI runtime services in the
968-
* thunking code.
969-
*/
970-
free_pages((unsigned long)new_memmap, pg_shift);
971-
972992
/* clean DUMMY object */
973993
efi_delete_dummy_variable();
974994
}

arch/x86/platform/efi/quirks.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,6 @@ void __init efi_free_boot_services(void)
286286

287287
free_bootmem_late(start, size);
288288
}
289-
290-
efi_memmap_unmap();
291289
}
292290

293291
/*

drivers/firmware/efi/arm-runtime.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,10 @@ static int __init arm_enable_runtime_services(void)
116116

117117
mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
118118

119-
efi.memmap.map = memremap(efi.memmap.phys_map, mapsize, MEMREMAP_WB);
120-
if (!efi.memmap.map) {
119+
if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
121120
pr_err("Failed to remap EFI memory map\n");
122121
return -ENOMEM;
123122
}
124-
efi.memmap.map_end = efi.memmap.map + mapsize;
125123

126124
if (!efi_virtmap_init()) {
127125
pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");

drivers/firmware/efi/efi.c

Lines changed: 95 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -347,68 +347,40 @@ subsys_initcall(efisubsys_init);
347347

348348
/*
349349
* Find the efi memory descriptor for a given physical address. Given a
350-
* physicall address, determine if it exists within an EFI Memory Map entry,
350+
* physical address, determine if it exists within an EFI Memory Map entry,
351351
* and if so, populate the supplied memory descriptor with the appropriate
352352
* data.
353353
*/
354354
int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
355355
{
356-
struct efi_memory_map *map = &efi.memmap;
357-
phys_addr_t p, e;
356+
efi_memory_desc_t *md;
358357

359358
if (!efi_enabled(EFI_MEMMAP)) {
360359
pr_err_once("EFI_MEMMAP is not enabled.\n");
361360
return -EINVAL;
362361
}
363362

364-
if (!map) {
365-
pr_err_once("efi.memmap is not set.\n");
366-
return -EINVAL;
367-
}
368363
if (!out_md) {
369364
pr_err_once("out_md is null.\n");
370365
return -EINVAL;
371366
}
372-
if (WARN_ON_ONCE(!map->phys_map))
373-
return -EINVAL;
374-
if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0))
375-
return -EINVAL;
376367

377-
e = map->phys_map + map->nr_map * map->desc_size;
378-
for (p = map->phys_map; p < e; p += map->desc_size) {
379-
efi_memory_desc_t *md;
368+
for_each_efi_memory_desc(md) {
380369
u64 size;
381370
u64 end;
382371

383-
/*
384-
* If a driver calls this after efi_free_boot_services,
385-
* ->map will be NULL, and the target may also not be mapped.
386-
* So just always get our own virtual map on the CPU.
387-
*
388-
*/
389-
md = early_memremap(p, sizeof (*md));
390-
if (!md) {
391-
pr_err_once("early_memremap(%pa, %zu) failed.\n",
392-
&p, sizeof (*md));
393-
return -ENOMEM;
394-
}
395-
396372
if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
397373
md->type != EFI_BOOT_SERVICES_DATA &&
398374
md->type != EFI_RUNTIME_SERVICES_DATA) {
399-
early_memunmap(md, sizeof (*md));
400375
continue;
401376
}
402377

403378
size = md->num_pages << EFI_PAGE_SHIFT;
404379
end = md->phys_addr + size;
405380
if (phys_addr >= md->phys_addr && phys_addr < end) {
406381
memcpy(out_md, md, sizeof(*out_md));
407-
early_memunmap(md, sizeof (*md));
408382
return 0;
409383
}
410-
411-
early_memunmap(md, sizeof (*md));
412384
}
413385
pr_err_once("requested map not found.\n");
414386
return -ENOENT;
@@ -545,32 +517,49 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
545517
}
546518

547519
/**
548-
* efi_memmap_init_early - Map the EFI memory map data structure
520+
* __efi_memmap_init - Common code for mapping the EFI memory map
549521
* @data: EFI memory map data
522+
* @late: Use early or late mapping function?
550523
*
551-
* Use early_memremap() to map the passed in EFI memory map and assign
552-
* it to efi.memmap.
524+
* This function takes care of figuring out which function to use to
525+
* map the EFI memory map in efi.memmap based on how far into the boot
526+
* we are.
527+
*
528+
* During bootup @late should be %false since we only have access to
529+
* the early_memremap*() functions as the vmalloc space isn't setup.
530+
* Once the kernel is fully booted we can fallback to the more robust
531+
* memremap*() API.
532+
*
533+
* Returns zero on success, a negative error code on failure.
553534
*/
554-
int __init efi_memmap_init_early(struct efi_memory_map_data *data)
535+
static int __init
536+
__efi_memmap_init(struct efi_memory_map_data *data, bool late)
555537
{
556538
struct efi_memory_map map;
539+
phys_addr_t phys_map;
557540

558541
if (efi_enabled(EFI_PARAVIRT))
559542
return 0;
560543

561-
map.phys_map = data->phys_map;
544+
phys_map = data->phys_map;
545+
546+
if (late)
547+
map.map = memremap(phys_map, data->size, MEMREMAP_WB);
548+
else
549+
map.map = early_memremap(phys_map, data->size);
562550

563-
map.map = early_memremap(data->phys_map, data->size);
564551
if (!map.map) {
565552
pr_err("Could not map the memory map!\n");
566553
return -ENOMEM;
567554
}
568555

556+
map.phys_map = data->phys_map;
569557
map.nr_map = data->size / data->desc_size;
570558
map.map_end = map.map + data->size;
571559

572560
map.desc_version = data->desc_version;
573561
map.desc_size = data->desc_size;
562+
map.late = late;
574563

575564
set_bit(EFI_MEMMAP, &efi.flags);
576565

@@ -579,17 +568,83 @@ int __init efi_memmap_init_early(struct efi_memory_map_data *data)
579568
return 0;
580569
}
581570

571+
/**
572+
* efi_memmap_init_early - Map the EFI memory map data structure
573+
* @data: EFI memory map data
574+
*
575+
* Use early_memremap() to map the passed in EFI memory map and assign
576+
* it to efi.memmap.
577+
*/
578+
int __init efi_memmap_init_early(struct efi_memory_map_data *data)
579+
{
580+
/* Cannot go backwards */
581+
WARN_ON(efi.memmap.late);
582+
583+
return __efi_memmap_init(data, false);
584+
}
585+
582586
void __init efi_memmap_unmap(void)
583587
{
584-
unsigned long size;
588+
if (!efi.memmap.late) {
589+
unsigned long size;
585590

586-
size = efi.memmap.desc_size * efi.memmap.nr_map;
591+
size = efi.memmap.desc_size * efi.memmap.nr_map;
592+
early_memunmap(efi.memmap.map, size);
593+
} else {
594+
memunmap(efi.memmap.map);
595+
}
587596

588-
early_memunmap(efi.memmap.map, size);
589597
efi.memmap.map = NULL;
590598
clear_bit(EFI_MEMMAP, &efi.flags);
591599
}
592600

601+
/**
602+
* efi_memmap_init_late - Map efi.memmap with memremap()
603+
* @phys_addr: Physical address of the new EFI memory map
604+
* @size: Size in bytes of the new EFI memory map
605+
*
606+
* Setup a mapping of the EFI memory map using ioremap_cache(). This
607+
* function should only be called once the vmalloc space has been
608+
* setup and is therefore not suitable for calling during early EFI
609+
* initialise, e.g. in efi_init(). Additionally, it expects
610+
* efi_memmap_init_early() to have already been called.
611+
*
612+
* The reason there are two EFI memmap initialisation
613+
* (efi_memmap_init_early() and this late version) is because the
614+
* early EFI memmap should be explicitly unmapped once EFI
615+
* initialisation is complete as the fixmap space used to map the EFI
616+
* memmap (via early_memremap()) is a scarce resource.
617+
*
618+
* This late mapping is intended to persist for the duration of
619+
* runtime so that things like efi_mem_desc_lookup() and
620+
* efi_mem_attributes() always work.
621+
*
622+
* Returns zero on success, a negative error code on failure.
623+
*/
624+
int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
625+
{
626+
struct efi_memory_map_data data = {
627+
.phys_map = addr,
628+
.size = size,
629+
};
630+
631+
/* Did we forget to unmap the early EFI memmap? */
632+
WARN_ON(efi.memmap.map);
633+
634+
/* Were we already called? */
635+
WARN_ON(efi.memmap.late);
636+
637+
/*
638+
* It makes no sense to allow callers to register different
639+
* values for the following fields. Copy them out of the
640+
* existing early EFI memmap.
641+
*/
642+
data.desc_version = efi.memmap.desc_version;
643+
data.desc_size = efi.memmap.desc_size;
644+
645+
return __efi_memmap_init(&data, true);
646+
}
647+
593648
#ifdef CONFIG_EFI_VARS_MODULE
594649
static int __init efi_load_efivars(void)
595650
{

include/linux/efi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ struct efi_memory_map {
688688
int nr_map;
689689
unsigned long desc_version;
690690
unsigned long desc_size;
691+
bool late;
691692
};
692693

693694
struct efi_fdt_params {
@@ -914,6 +915,7 @@ static inline efi_status_t efi_query_variable_store(u32 attributes,
914915
extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
915916

916917
extern int __init efi_memmap_init_early(struct efi_memory_map_data *data);
918+
extern int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size);
917919
extern void __init efi_memmap_unmap(void);
918920

919921
extern int efi_config_init(efi_config_table_type_t *arch_tables);

0 commit comments

Comments
 (0)