[PATCH 2/9] arm64/efi: refactor EFI init and runtime code for reuse by 32-bit ARM

Ard Biesheuvel ard.biesheuvel at linaro.org
Thu Oct 1 10:04:16 PDT 2015


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.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
---
 arch/arm64/include/asm/efi.h       |  16 ++++
 arch/arm64/kernel/efi.c            |  51 ++++++++++
 drivers/firmware/efi/arm-init.c    |  11 ++-
 drivers/firmware/efi/arm-runtime.c | 101 ++++++--------------
 drivers/firmware/efi/efi.c         |   4 +-
 5 files changed, 105 insertions(+), 78 deletions(-)

diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index 7cc8df68c638..a16490d6ec1a 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -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);
@@ -12,6 +14,8 @@ extern void efi_parse_fdt(void *fdt);
 #define efi_parse_fdt(x)
 #endif
 
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+
 #define efi_call_virt(f, ...)						\
 ({									\
 	efi_##f##_t *__f;						\
@@ -65,6 +69,18 @@ extern void efi_parse_fdt(void *fdt);
  *   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/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index bd3b2f5adf0c..77df172f0e6d 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -17,6 +17,57 @@
 
 #include <asm/efi.h>
 
+int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
+{
+	u64 paddr, npages, size;
+	pteval_t prot_val;
+
+	paddr = md->phys_addr;
+	npages = md->num_pages;
+	memrange_efi_to_native(&paddr, &npages);
+	size = npages << PAGE_SHIFT;
+
+	/*
+	 * Order is important here: memory regions may have all of the
+	 * bits below set (and usually do), and any memory that has the
+	 * EFI_MEMORY_WB bit set may be covered by the linear mapping
+	 * and mapped write-back cacheable already. So check the
+	 * EFI_MEMORY_WB bit first.
+	 */
+	if (md->attribute & EFI_MEMORY_WB)
+		prot_val = pgprot_val(PAGE_KERNEL_EXEC);
+	else if (md->attribute & EFI_MEMORY_WT)
+		prot_val = PROT_NORMAL_WT;
+	else if (md->attribute & EFI_MEMORY_WC)
+		prot_val = PROT_NORMAL_NC;
+	else if (md->attribute & EFI_MEMORY_UC)
+		prot_val = PROT_DEVICE_nGnRnE;
+	else
+		return -EINVAL;
+
+	/*
+	 * Since the UEFI spec requires only the type attributes to be
+	 * identical within the same 64 KB page frame, we may encounter
+	 * regions that are not 64 KB aligned, but whose attributes only
+	 * differ from adjacent regions in the permission bits.
+	 * This means we can only enforce any permission restrictions if
+	 * the boundaries of this region are aligned to the OS page
+	 * size.
+	 */
+	if (PAGE_SIZE == EFI_PAGE_SIZE ||
+	    (PAGE_ALIGNED(md->virt_addr) &&
+	     PAGE_ALIGNED(md->virt_addr + md->num_pages * EFI_PAGE_SIZE))) {
+
+		if (md->attribute & EFI_MEMORY_RO)
+			prot_val |= PTE_RDONLY;
+		if (md->attribute & EFI_MEMORY_XP)
+			prot_val |= PTE_PXN;
+	}
+
+	create_pgd_mapping(mm, paddr, md->virt_addr, size, __pgprot(prot_val));
+	return 0;
+}
+
 static int __init arm64_dmi_init(void)
 {
 	/*
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
index 56987a5b9033..235677b86e4e 100644
--- a/drivers/firmware/efi/arm-init.c
+++ b/drivers/firmware/efi/arm-init.c
@@ -66,7 +66,7 @@ static int __init uefi_init(void)
 {
 	efi_char16_t *c16;
 	void *config_tables;
-	u64 table_size;
+	int table_size;
 	char vendor[100] = "unknown";
 	int i, retval;
 
@@ -78,7 +78,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
@@ -112,7 +113,7 @@ static int __init uefi_init(void)
 				       table_size);
 
 	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:
@@ -186,7 +187,7 @@ void __init efi_parse_fdt(void *fdt)
 
 	efi_system_table = params.system_table;
 
-	memmap.phys_map = (void *)params.mmap;
+	memmap.phys_map = (void *)(unsigned long)params.mmap;
 	memmap.desc_size = params.desc_size;
 	memmap.desc_version = params.desc_ver;
 	memmap.nr_map = params.mmap_size / params.desc_size;
@@ -201,7 +202,7 @@ void __init efi_init(void)
 	if (!efi_enabled(EFI_MEMMAP))
 		return;
 
-	memmap.map = early_memremap((u64)memmap.phys_map, mmap_size);
+	memmap.map = early_memremap((unsigned long)memmap.phys_map, mmap_size);
 	memmap.map_end = memmap.map + mmap_size;
 
 	if (uefi_init() < 0)
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
index 5a94ea48670d..7f23f3cffb46 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -23,18 +23,19 @@
 
 #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
 
 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),
@@ -47,67 +48,34 @@ 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;
-		pteval_t prot_val;
+		phys_addr_t phys = (phys_addr_t)md->phys_addr;
+		int ret;
 
 		if (!(md->attribute & EFI_MEMORY_RUNTIME))
 			continue;
 		if (md->virt_addr == 0)
 			return false;
 
-		paddr = md->phys_addr;
-		npages = md->num_pages;
-		memrange_efi_to_native(&paddr, &npages);
-		size = npages << PAGE_SHIFT;
-
-		/*
-		 * Order is important here: memory regions may have all of the
-		 * bits below set (and usually do), and any memory that has the
-		 * EFI_MEMORY_WB bit set may be covered by the linear mapping
-		 * and mapped write-back cacheable already. So check the
-		 * EFI_MEMORY_WB bit first.
-		 */
-		if (md->attribute & EFI_MEMORY_WB) {
-			prot_val = pgprot_val(PAGE_KERNEL_EXEC);
-		} else if (md->attribute & EFI_MEMORY_WT) {
-			prot_val = PROT_NORMAL_WT;
-		} else if (md->attribute & EFI_MEMORY_WC) {
-			prot_val = PROT_NORMAL_NC;
-		} else if (md->attribute & EFI_MEMORY_UC) {
-			prot_val = PROT_DEVICE_nGnRnE;
-		} else {
-			pr_warn("  EFI remap 0x%012llx: not remapping due to unsupported memory attributes (0x%llx)\n",
-				md->phys_addr, md->attribute);
-			continue;
-		}
-
-		/*
-		 * Since the UEFI spec requires only the type attributes to be
-		 * identical within the same 64 KB page frame, we may encounter
-		 * regions that are not 64 KB aligned, but whose attributes only
-		 * differ from adjacent regions in the permission bits.
-		 * This means we can only enforce any permission restrictions if
-		 * the boundaries of this region are aligned to the OS page
-		 * size.
-		 */
-		if (PAGE_SIZE == EFI_PAGE_SIZE ||
-		    (PAGE_ALIGNED(md->virt_addr) &&
-		     PAGE_ALIGNED(md->virt_addr + md->num_pages * EFI_PAGE_SIZE))) {
-
-			if (md->attribute & EFI_MEMORY_RO)
-				prot_val |= PTE_RDONLY;
-			if (md->attribute & EFI_MEMORY_XP)
-				prot_val |= PTE_PXN;
+		ret = efi_create_mapping(&efi_mm, md);
+		switch (ret) {
+		case 0:
+			pr_info("  EFI remap %pa => %p (R%c%c)\n",
+				&phys, (void *)(unsigned long)md->virt_addr,
+				md->attribute & EFI_MEMORY_RO ? '-' : 'W',
+				md->attribute & EFI_MEMORY_XP ? '-' : 'X');
+			break;
+		case -EINVAL:
+			pr_warn("  EFI remap %pa: not remapping due to unsupported memory attributes (0x%llx)\n",
+				&phys, md->attribute);
+			return false;
+		default:
+			pr_warn("  EFI remap %pa: failed to create mapping (%d)\n",
+				&phys, ret);
+			return false;
 		}
-
-		pr_info("  EFI remap 0x%012llx => %p (R%c%c)\n",
-			md->phys_addr, (void *)md->virt_addr,
-			prot_val & PTE_RDONLY ? '-' : 'W',
-			prot_val & PTE_PXN ? '-' : 'X');
-
-		create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size,
-				   __pgprot(prot_val));
 	}
 	return true;
 }
@@ -117,7 +85,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;
 
@@ -134,7 +102,7 @@ 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,
+	memmap.map = (__force void *)ioremap_cache((unsigned long)memmap.phys_map,
 						   mapsize);
 	if (!memmap.map) {
 		pr_err("Failed to remap EFI memory map\n");
@@ -155,6 +123,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;
 	}
+	iounmap(memmap.map);
 
 	/* Set up runtime services function pointers */
 	efi_native_runtime_setup();
@@ -164,19 +133,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)
 {
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index f5e586bd3b24..2eb31e28a35c 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -23,6 +23,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,
@@ -286,7 +288,7 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
 		 * So just always get our own virtual map on the CPU.
 		 *
 		 */
-		md = early_memremap((phys_addr_t)p, sizeof (*md));
+		md = early_memremap((unsigned long)p, sizeof (*md));
 		if (!md) {
 			pr_err_once("early_memremap(%p, %zu) failed.\n",
 				    p, sizeof (*md));
-- 
1.9.1




More information about the linux-arm-kernel mailing list