arm64/efi: refactor EFI init and runtime code for reuse by 32-bit ARM
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Mon, 30 Nov 2015 12:28:19 +0000 (13:28 +0100)
committerWill Deacon <will.deacon@arm.com>
Wed, 9 Dec 2015 16:57:23 +0000 (16:57 +0000)
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>
arch/arm64/include/asm/efi.h
arch/arm64/kernel/efi.c
drivers/firmware/efi/arm-init.c
drivers/firmware/efi/arm-runtime.c
drivers/firmware/efi/efi.c

index ef572206f1c3eb6658618b40568e662f7e1865fc..8e88a696c9cbcbd2c8f717ea1c929b87750f1b03 100644 (file)
@@ -2,7 +2,9 @@
 #define _ASM_EFI_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 +12,8 @@ extern void efi_init(void);
 #define efi_init()
 #endif
 
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+
 #define efi_call_virt(f, ...)                                          \
 ({                                                                     \
        efi_##f##_t *__f;                                               \
@@ -63,6 +67,11 @@ 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)
+{
+       switch_mm(NULL, mm, NULL);
+}
+
 void efi_virtmap_load(void);
 void efi_virtmap_unload(void);
 
index bd3b2f5adf0c8f6927009a2613931e30c8a693a5..b6abc852f2a142123150662bc6dd6bf5c3de62af 100644 (file)
 
 #include <asm/efi.h>
 
+int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
+{
+       pteval_t prot_val;
+
+       /*
+        * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
+        * executable, everything else can be mapped with the XN bits
+        * set.
+        */
+       if ((md->attribute & EFI_MEMORY_WB) == 0)
+               prot_val = PROT_DEVICE_nGnRE;
+       else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
+                !PAGE_ALIGNED(md->phys_addr))
+               prot_val = pgprot_val(PAGE_KERNEL_EXEC);
+       else
+               prot_val = pgprot_val(PAGE_KERNEL);
+
+       create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
+                          md->num_pages << EFI_PAGE_SHIFT,
+                          __pgprot(prot_val | PTE_NG));
+       return 0;
+}
+
 static int __init arm64_dmi_init(void)
 {
        /*
index ffdd76a51929bffbc75322140bf26e8454177240..9e15d571b53c2bd759e1b0e6c0d0bda0795740a9 100644 (file)
@@ -57,7 +57,7 @@ static int __init uefi_init(void)
 {
        efi_char16_t *c16;
        void *config_tables;
-       u64 table_size;
+       size_t table_size;
        char vendor[100] = "unknown";
        int i, retval;
 
@@ -69,7 +69,8 @@ static int __init uefi_init(void)
        }
 
        set_bit(EFI_BOOT, &efi.flags);
-       set_bit(EFI_64BIT, &efi.flags);
+       if (IS_ENABLED(CONFIG_64BIT))
+               set_bit(EFI_64BIT, &efi.flags);
 
        /*
         * Verify the EFI Table
@@ -107,7 +108,7 @@ static int __init uefi_init(void)
                goto out;
        }
        retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
-                                        sizeof(efi_config_table_64_t), NULL);
+                                        sizeof(efi_config_table_t), NULL);
 
        early_memunmap(config_tables, table_size);
 out:
index 974743e13a4d7376c4a9b9517d2fa0443cdd88e7..6ae21e41a429402d132d8d5be215d5adde64d08c 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/efi.h>
+#include <linux/io.h>
 #include <linux/memblock.h>
 #include <linux/mm_types.h>
 #include <linux/preempt.h>
 
 #include <asm/cacheflush.h>
 #include <asm/efi.h>
-#include <asm/tlbflush.h>
-#include <asm/mmu_context.h>
 #include <asm/mmu.h>
+#include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 
-static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
-
 extern u64 efi_system_table;
 
 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),
@@ -46,35 +43,27 @@ static bool __init efi_virtmap_init(void)
 {
        efi_memory_desc_t *md;
 
+       efi_mm.pgd = pgd_alloc(&efi_mm);
        init_new_context(NULL, &efi_mm);
 
        for_each_efi_memory_desc(&memmap, md) {
-               pgprot_t prot;
+               phys_addr_t phys = md->phys_addr;
+               int ret;
 
                if (!(md->attribute & EFI_MEMORY_RUNTIME))
                        continue;
                if (md->virt_addr == 0)
                        return false;
 
-               pr_info("  EFI remap 0x%016llx => %p\n",
-                       md->phys_addr, (void *)md->virt_addr);
-
-               /*
-                * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
-                * executable, everything else can be mapped with the XN bits
-                * set.
-                */
-               if ((md->attribute & EFI_MEMORY_WB) == 0)
-                       prot = __pgprot(PROT_DEVICE_nGnRE);
-               else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
-                        !PAGE_ALIGNED(md->phys_addr))
-                       prot = PAGE_KERNEL_EXEC;
-               else
-                       prot = PAGE_KERNEL;
-
-               create_pgd_mapping(&efi_mm, md->phys_addr, md->virt_addr,
-                                  md->num_pages << EFI_PAGE_SHIFT,
-                                  __pgprot(pgprot_val(prot) | PTE_NG));
+               ret = efi_create_mapping(&efi_mm, md);
+               if  (!ret) {
+                       pr_info("  EFI remap %pa => %p\n",
+                               &phys, (void *)(unsigned long)md->virt_addr);
+               } else {
+                       pr_warn("  EFI remap %pa: failed to create mapping (%d)\n",
+                               &phys, ret);
+                       return false;
+               }
        }
        return true;
 }
@@ -84,7 +73,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;
 
@@ -131,12 +120,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)
-{
-       switch_mm(NULL, mm, NULL);
-}
+early_initcall(arm_enable_runtime_services);
 
 void efi_virtmap_load(void)
 {
index 027ca212179f7f81276733d0bda6b97a636c6770..cffa89b3317b59f0194c01e1caaafe52bb3496bc 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
+#include <asm/efi.h>
+
 struct efi __read_mostly efi = {
        .mps                    = EFI_INVALID_TABLE_ADDR,
        .acpi                   = EFI_INVALID_TABLE_ADDR,