This refactors the EFI init and runtime code that is now shared between arm64 and ARM so that: - 64-bit specific types and flags are made build-time conditional - the code sequences that use early memremap/memunmap are reshuffled so that they can be implemented using fixmap on ARM - take a copy of the EFI system table rather than keep it mapped.
This allows the same code to be built and run for arm64 and ARM.
Signed-off-by: Ard Biesheuvel ard.biesheuvel@linaro.org --- arch/arm64/include/asm/efi.h | 29 +++++++++++++++ drivers/firmware/efi/arm-init.c | 73 +++++++++++++++++++++----------------- drivers/firmware/efi/arm-runtime.c | 46 ++++++++++-------------- 3 files changed, 89 insertions(+), 59 deletions(-)
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index ef572206f1c3..c822af4a8ff8 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -1,8 +1,11 @@ #ifndef _ASM_EFI_H #define _ASM_EFI_H
+#include <asm/early_ioremap.h> #include <asm/io.h> +#include <asm/mmu_context.h> #include <asm/neon.h> +#include <asm/tlbflush.h>
#ifdef CONFIG_EFI extern void efi_init(void); @@ -10,6 +13,20 @@ extern void efi_init(void); #define efi_init() #endif
+typedef pgprot_t __arm_efi_prot_t; + +#define __EFI_DEVICE __pgprot(PROT_DEVICE_nGnRE) +#define __EFI_MEMORY_RW PAGE_KERNEL +#define __EFI_MEMORY_RWX PAGE_KERNEL_EXEC + +#define __arm_efi_early_memremap early_memremap +#define __arm_efi_early_memunmap early_memunmap + +#define __arm_efi_memremap ioremap_cache +#define __arm_efi_memunmap iounmap + +#define create_efi_mapping create_pgd_mapping + #define efi_call_virt(f, ...) \ ({ \ efi_##f##_t *__f; \ @@ -63,6 +80,18 @@ extern void efi_init(void); * Services are enabled and the EFI_RUNTIME_SERVICES bit set. */
+static inline void efi_set_pgd(struct mm_struct *mm) +{ + if (mm == &init_mm) + cpu_set_reserved_ttbr0(); + else + cpu_switch_mm(mm->pgd, mm); + + flush_tlb_all(); + if (icache_is_aivivt()) + __flush_icache_all(); +} + void efi_virtmap_load(void); void efi_virtmap_unload(void);
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 12e666ac6a34..b28d020a97c2 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -62,62 +62,51 @@ static phys_addr_t efi_to_phys(unsigned long addr) return addr; }
-static int __init uefi_init(void) +static void __init uefi_init(phys_addr_t fw_vendor, phys_addr_t tables) { + const int sizeof_config_table = IS_ENABLED(CONFIG_64BIT) ? + sizeof(efi_config_table_64_t) : + sizeof(efi_config_table_32_t); efi_char16_t *c16; void *config_tables; - u64 table_size; + int table_size; char vendor[100] = "unknown"; int i, retval;
- efi.systab = early_memremap(efi_system_table, - sizeof(efi_system_table_t)); - if (efi.systab == NULL) { - pr_warn("Unable to map EFI system table.\n"); - return -ENOMEM; - } - - set_bit(EFI_BOOT, &efi.flags); - set_bit(EFI_64BIT, &efi.flags); - /* * Verify the EFI Table */ if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { pr_err("System table signature incorrect\n"); - retval = -EINVAL; - goto out; + return; } + set_bit(EFI_SYSTEM_TABLES, &efi.flags); + if ((efi.systab->hdr.revision >> 16) < 2) pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n", efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff);
/* Show what we know for posterity */ - c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor), - sizeof(vendor)); + c16 = __arm_efi_early_memremap(fw_vendor, sizeof(vendor)); if (c16) { for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) vendor[i] = c16[i]; vendor[i] = '\0'; - early_memunmap(c16, sizeof(vendor)); + __arm_efi_early_memunmap(c16, sizeof(vendor)); }
pr_info("EFI v%u.%.02u by %s\n", efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor);
- table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables; - config_tables = early_memremap(efi_to_phys(efi.systab->tables), - table_size); + table_size = sizeof_config_table * efi.systab->nr_tables; + config_tables = __arm_efi_early_memremap(tables, table_size);
retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, - sizeof(efi_config_table_64_t), NULL); + sizeof_config_table, NULL);
- early_memunmap(config_tables, table_size); -out: - early_memunmap(efi.systab, sizeof(efi_system_table_t)); - return retval; + __arm_efi_early_memunmap(config_tables, table_size); }
/* @@ -179,25 +168,45 @@ static __init void reserve_regions(void)
void __init efi_init(void) { + static efi_system_table_t cached_efi_systab; struct efi_fdt_params params; + efi_system_table_t *efi_systab; + phys_addr_t fw_vendor, tables;
/* Grab UEFI information placed in FDT by stub */ if (!efi_get_fdt_params(¶ms, uefi_debug)) return;
- efi_system_table = params.system_table; + set_bit(EFI_BOOT, &efi.flags); + if (IS_ENABLED(CONFIG_64BIT)) + set_bit(EFI_64BIT, &efi.flags); + + efi_systab = __arm_efi_early_memremap(params.system_table, + sizeof(efi_system_table_t)); + if (efi_systab == NULL) { + pr_warn("Unable to map EFI system table.\n"); + return; + } + + cached_efi_systab = *efi_systab; + efi.systab = &cached_efi_systab; + + __arm_efi_early_memunmap(efi_systab, sizeof(efi_system_table_t));
memblock_reserve(params.mmap & PAGE_MASK, PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK))); - memmap.phys_map = (void *)params.mmap; - memmap.map = early_memremap(params.mmap, params.mmap_size); + memmap.phys_map = (void *)(unsigned long)params.mmap; + memmap.map = __arm_efi_early_memremap(params.mmap, params.mmap_size); memmap.map_end = memmap.map + params.mmap_size; memmap.desc_size = params.desc_size; memmap.desc_version = params.desc_ver;
- if (uefi_init() < 0) - return; - reserve_regions(); - early_memunmap(memmap.map, params.mmap_size); + + fw_vendor = efi_to_phys(efi.systab->fw_vendor); + tables = efi_to_phys(efi.systab->tables); + + __arm_efi_early_memunmap(memmap.map, params.mmap_size); + + uefi_init(fw_vendor, tables); } diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index a8243018dfec..de5086fc44e1 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -23,16 +23,17 @@
#include <asm/cacheflush.h> #include <asm/efi.h> -#include <asm/tlbflush.h> -#include <asm/mmu_context.h> +#include <asm/io.h> #include <asm/mmu.h> +#include <asm/pgalloc.h> #include <asm/pgtable.h>
-static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss; +#ifndef INIT_MM_CONTEXT +#define INIT_MM_CONTEXT(name) +#endif
static struct mm_struct efi_mm = { .mm_rb = RB_ROOT, - .pgd = efi_pgd, .mm_users = ATOMIC_INIT(2), .mm_count = ATOMIC_INIT(1), .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem), @@ -45,9 +46,11 @@ static bool __init efi_virtmap_init(void) { efi_memory_desc_t *md;
+ efi_mm.pgd = pgd_alloc(&efi_mm); + for_each_efi_memory_desc(&memmap, md) { u64 paddr, npages, size; - pgprot_t prot; + __arm_efi_prot_t prot;
if (!(md->attribute & EFI_MEMORY_RUNTIME)) continue; @@ -59,8 +62,8 @@ static bool __init efi_virtmap_init(void) memrange_efi_to_native(&paddr, &npages); size = npages << PAGE_SHIFT;
- pr_info(" EFI remap 0x%016llx => %p\n", - md->phys_addr, (void *)md->virt_addr); + pr_info(" EFI remap %pa => %p\n", + &md->phys_addr, (void *)(unsigned long)md->virt_addr);
/* * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be @@ -68,13 +71,13 @@ static bool __init efi_virtmap_init(void) * set. */ if (md->type == EFI_MEMORY_MAPPED_IO) - prot = __pgprot(PROT_DEVICE_nGnRE); + prot = __EFI_DEVICE; else if (md->type == EFI_RUNTIME_SERVICES_CODE) - prot = PAGE_KERNEL_EXEC; + prot = __EFI_MEMORY_RWX; else - prot = PAGE_KERNEL; + prot = __EFI_MEMORY_RW;
- create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size, prot); + create_efi_mapping(&efi_mm, paddr, md->virt_addr, size, prot); } return true; } @@ -84,7 +87,7 @@ static bool __init efi_virtmap_init(void) * non-early mapping of the UEFI system table and virtual mappings for all * EFI_MEMORY_RUNTIME regions. */ -static int __init arm64_enable_runtime_services(void) +static int __init arm_enable_runtime_services(void) { u64 mapsize;
@@ -101,8 +104,8 @@ static int __init arm64_enable_runtime_services(void) pr_info("Remapping and enabling EFI services.\n");
mapsize = memmap.map_end - memmap.map; - memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, - mapsize); + memmap.map = (__force void *)__arm_efi_memremap( + (phys_addr_t)(unsigned long)memmap.phys_map, mapsize); if (!memmap.map) { pr_err("Failed to remap EFI memory map\n"); return -1; @@ -114,6 +117,7 @@ static int __init arm64_enable_runtime_services(void) pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); return -1; } + __arm_efi_memunmap(memmap.map);
/* Set up runtime services function pointers */ efi_native_runtime_setup(); @@ -123,19 +127,7 @@ static int __init arm64_enable_runtime_services(void)
return 0; } -early_initcall(arm64_enable_runtime_services); - -static void efi_set_pgd(struct mm_struct *mm) -{ - if (mm == &init_mm) - cpu_set_reserved_ttbr0(); - else - cpu_switch_mm(mm->pgd, mm); - - flush_tlb_all(); - if (icache_is_aivivt()) - __flush_icache_all(); -} +early_initcall(arm_enable_runtime_services);
void efi_virtmap_load(void) {