Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64/efi: refactor EFI init and runtime code for reuse by 32-bit ARM

This refactors the EFI init and runtime code that will be shared
between arm64 and ARM so that it can be built for both archs.

Reviewed-by: Matt Fleming <matt@codeblueprint.co.uk>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>

authored by

Ard Biesheuvel and committed by
Will Deacon
f7d92489 e5bc22a4

+54 -35
+9
arch/arm64/include/asm/efi.h
··· 2 2 #define _ASM_EFI_H 3 3 4 4 #include <asm/io.h> 5 + #include <asm/mmu_context.h> 5 6 #include <asm/neon.h> 7 + #include <asm/tlbflush.h> 6 8 7 9 #ifdef CONFIG_EFI 8 10 extern void efi_init(void); 9 11 #else 10 12 #define efi_init() 11 13 #endif 14 + 15 + int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); 12 16 13 17 #define efi_call_virt(f, ...) \ 14 18 ({ \ ··· 66 62 * into a private set of page tables. If this all succeeds, the Runtime 67 63 * Services are enabled and the EFI_RUNTIME_SERVICES bit set. 68 64 */ 65 + 66 + static inline void efi_set_pgd(struct mm_struct *mm) 67 + { 68 + switch_mm(NULL, mm, NULL); 69 + } 69 70 70 71 void efi_virtmap_load(void); 71 72 void efi_virtmap_unload(void);
+23
arch/arm64/kernel/efi.c
··· 17 17 18 18 #include <asm/efi.h> 19 19 20 + int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) 21 + { 22 + pteval_t prot_val; 23 + 24 + /* 25 + * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be 26 + * executable, everything else can be mapped with the XN bits 27 + * set. 28 + */ 29 + if ((md->attribute & EFI_MEMORY_WB) == 0) 30 + prot_val = PROT_DEVICE_nGnRE; 31 + else if (md->type == EFI_RUNTIME_SERVICES_CODE || 32 + !PAGE_ALIGNED(md->phys_addr)) 33 + prot_val = pgprot_val(PAGE_KERNEL_EXEC); 34 + else 35 + prot_val = pgprot_val(PAGE_KERNEL); 36 + 37 + create_pgd_mapping(mm, md->phys_addr, md->virt_addr, 38 + md->num_pages << EFI_PAGE_SHIFT, 39 + __pgprot(prot_val | PTE_NG)); 40 + return 0; 41 + } 42 + 20 43 static int __init arm64_dmi_init(void) 21 44 { 22 45 /*
+4 -3
drivers/firmware/efi/arm-init.c
··· 57 57 { 58 58 efi_char16_t *c16; 59 59 void *config_tables; 60 - u64 table_size; 60 + size_t table_size; 61 61 char vendor[100] = "unknown"; 62 62 int i, retval; 63 63 ··· 69 69 } 70 70 71 71 set_bit(EFI_BOOT, &efi.flags); 72 - set_bit(EFI_64BIT, &efi.flags); 72 + if (IS_ENABLED(CONFIG_64BIT)) 73 + set_bit(EFI_64BIT, &efi.flags); 73 74 74 75 /* 75 76 * Verify the EFI Table ··· 108 107 goto out; 109 108 } 110 109 retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, 111 - sizeof(efi_config_table_64_t), NULL); 110 + sizeof(efi_config_table_t), NULL); 112 111 113 112 early_memunmap(config_tables, table_size); 114 113 out:
+16 -32
drivers/firmware/efi/arm-runtime.c
··· 12 12 */ 13 13 14 14 #include <linux/efi.h> 15 + #include <linux/io.h> 15 16 #include <linux/memblock.h> 16 17 #include <linux/mm_types.h> 17 18 #include <linux/preempt.h> ··· 24 23 25 24 #include <asm/cacheflush.h> 26 25 #include <asm/efi.h> 27 - #include <asm/tlbflush.h> 28 - #include <asm/mmu_context.h> 29 26 #include <asm/mmu.h> 27 + #include <asm/pgalloc.h> 30 28 #include <asm/pgtable.h> 31 - 32 - static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss; 33 29 34 30 extern u64 efi_system_table; 35 31 36 32 static struct mm_struct efi_mm = { 37 33 .mm_rb = RB_ROOT, 38 - .pgd = efi_pgd, 39 34 .mm_users = ATOMIC_INIT(2), 40 35 .mm_count = ATOMIC_INIT(1), 41 36 .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem), ··· 43 46 { 44 47 efi_memory_desc_t *md; 45 48 49 + efi_mm.pgd = pgd_alloc(&efi_mm); 46 50 init_new_context(NULL, &efi_mm); 47 51 48 52 for_each_efi_memory_desc(&memmap, md) { 49 - pgprot_t prot; 53 + phys_addr_t phys = md->phys_addr; 54 + int ret; 50 55 51 56 if (!(md->attribute & EFI_MEMORY_RUNTIME)) 52 57 continue; 53 58 if (md->virt_addr == 0) 54 59 return false; 55 60 56 - pr_info(" EFI remap 0x%016llx => %p\n", 57 - md->phys_addr, (void *)md->virt_addr); 58 - 59 - /* 60 - * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be 61 - * executable, everything else can be mapped with the XN bits 62 - * set. 63 - */ 64 - if ((md->attribute & EFI_MEMORY_WB) == 0) 65 - prot = __pgprot(PROT_DEVICE_nGnRE); 66 - else if (md->type == EFI_RUNTIME_SERVICES_CODE || 67 - !PAGE_ALIGNED(md->phys_addr)) 68 - prot = PAGE_KERNEL_EXEC; 69 - else 70 - prot = PAGE_KERNEL; 71 - 72 - create_pgd_mapping(&efi_mm, md->phys_addr, md->virt_addr, 73 - md->num_pages << EFI_PAGE_SHIFT, 74 - __pgprot(pgprot_val(prot) | PTE_NG)); 61 + ret = efi_create_mapping(&efi_mm, md); 62 + if (!ret) { 63 + pr_info(" EFI remap %pa => %p\n", 64 + &phys, (void *)(unsigned long)md->virt_addr); 65 + } else { 66 + pr_warn(" EFI remap %pa: failed to create mapping (%d)\n", 67 + &phys, ret); 68 + return false; 69 + } 75 70 } 76 71 return true; 77 72 } ··· 73 84 * non-early mapping of the UEFI system table and virtual mappings for all 74 85 * EFI_MEMORY_RUNTIME regions. 75 86 */ 76 - static int __init arm64_enable_runtime_services(void) 87 + static int __init arm_enable_runtime_services(void) 77 88 { 78 89 u64 mapsize; 79 90 ··· 120 131 121 132 return 0; 122 133 } 123 - early_initcall(arm64_enable_runtime_services); 124 - 125 - static void efi_set_pgd(struct mm_struct *mm) 126 - { 127 - switch_mm(NULL, mm, NULL); 128 - } 134 + early_initcall(arm_enable_runtime_services); 129 135 130 136 void efi_virtmap_load(void) 131 137 {
+2
drivers/firmware/efi/efi.c
··· 25 25 #include <linux/io.h> 26 26 #include <linux/platform_device.h> 27 27 28 + #include <asm/efi.h> 29 + 28 30 struct efi __read_mostly efi = { 29 31 .mps = EFI_INVALID_TABLE_ADDR, 30 32 .acpi = EFI_INVALID_TABLE_ADDR,