Skip to contentSkip to conversation

UEFI boot and runtime services support for 32-bit ARM

PATCH New Ard Biesheuvel 3 participants 20 messages Oct 1, 2015 – Nov 4, 2015 3 messages not in the archive

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover UEFI boot and runtime services support for 32-bit ARM

This series adds support for booting the 32-bit ARM kernel directly from UEFI firmware using a builtin UEFI stub. It mostly reuses refactored arm64 code, and the differences (primarily the PE/COFF header and entry point and the efi_create_mapping() implementation) are split out into arm64 and ARM versions.

Patch #1 splits off most of arch/arm64/kernel/efi.c into arch agnostic files arm-init.c and arm-runtime.c under drivers/firmware/efi.

Patch #2 refactors the code split off in patch #1 to isolate the arm64 specific pieces, and change a couple of arm64-isms that ARM handles slightly differently.

Patch #3 enables the generic early_ioremap and early_memremap implementations for ARM. It reuses the kmap fixmap region, which is not used that early anyway.

Patch #4 adds support to ARM for the MEMBLOCK_NOMAP region flag.

Patch #5 splits off the core functionality of create_mapping() into a new function __create_mapping() that we can reuse for mapping UEFI runtime regions.

Patch #6 factors out the early_alloc() routine so we can invoke __create_mapping using another (late) allocator.

Patch #7 implements create_mapping_late() that uses a late allocator.

Patch #8 implements the UEFI support in the kernel proper to probe the UEFI memory map and map the runtime services.

Patch #9 ties together all of the above, by implementing the UEFI stub, and introducing the Kconfig symbols that allow all of this to be built.

There are a number of prerequisites for this series that have all been sent to the linux-arm-kernel mailing list at some point (and mostly ignored).

Matt Fleming's efi-next branch:
https://git.kernel.org/cgit/linux/kernel/git/mfleming/efi.git/log/?h=next

arm64: EFI stub isolation:
http://thread.gmane.org/gmane.linux.kernel.efi/6414

arm64: remove UEFI reserved regions from linear mapping (aka MEMBLOCK_NOMAP)
http://thread.gmane.org/gmane.linux.kernel.mm/138474

arm64 UEFI early FDT handling
http://thread.gmane.org/gmane.linux.kernel.efi/6334

arm64/efi: adapt to UEFI 2.5 properties table changes
http://thread.gmane.org/gmane.linux.kernel.efi/5847

The complete series (including all prerequisites) can be found here:
https://git.linaro.org/people/ard.biesheuvel/linux-arm.git/shortlog/refs/heads/arm32-uefi-support

Instructions how to build and run the 32-bit ARM UEFI firmware can be found here:
https://wiki.linaro.org/LEG/UEFIforQEMU

Ard Biesheuvel (8):
arm64/efi: split off EFI init and runtime code for reuse by 32-bit ARM arm64/efi: refactor EFI init and runtime code for reuse by 32-bit ARM
ARM: add support for generic early_ioremap/early_memremap
ARM: only consider memblocks with NOMAP cleared for linear mapping
ARM: split off core mapping logic from create_mapping
ARM: factor out allocation routine from __create_mapping()
ARM: implement create_mapping_late() for EFI use
ARM: wire up UEFI init and runtime support

Roy Franz (1):
ARM: add UEFI stub support

 arch/arm/Kconfig                        |  20 +
 arch/arm/boot/compressed/Makefile       |   5 +-
 arch/arm/boot/compressed/efi-header.S   | 130 +++++++
 arch/arm/boot/compressed/efi-stub.c     |  89 +++++
 arch/arm/boot/compressed/head.S         |  54 ++-
 arch/arm/boot/compressed/vmlinux.lds.S  |   7 +
 arch/arm/include/asm/Kbuild             |   1 +
 arch/arm/include/asm/efi.h              |  92 +++++
 arch/arm/include/asm/fixmap.h           |  28 +-
 arch/arm/include/asm/mach/map.h         |   1 +
 arch/arm/kernel/Makefile                |   1 +
 arch/arm/kernel/devtree.c               |   4 +
 arch/arm/kernel/efi.c                   |  71 ++++
 arch/arm/kernel/setup.c                 |  10 +-
 arch/arm/mm/init.c                      |  16 +-
 arch/arm/mm/ioremap.c                   |   9 +
 arch/arm/mm/mmu.c                       | 110 ++++--
 arch/arm64/include/asm/efi.h            |  16 +
 arch/arm64/kernel/efi.c                 | 392 ++------------------
 drivers/firmware/efi/Makefile           |   4 +-
 drivers/firmware/efi/arm-init.c         | 215 +++++++++++
 drivers/firmware/efi/arm-runtime.c      | 148 ++++++++
 drivers/firmware/efi/efi.c              |   4 +-
 drivers/firmware/efi/libstub/Makefile   |  12 +
 drivers/firmware/efi/libstub/arm-stub.c |   4 +-
 25 files changed, 1046 insertions(+), 397 deletions(-)
 create mode 100644 arch/arm/boot/compressed/efi-header.S
 create mode 100644 arch/arm/boot/compressed/efi-stub.c
 create mode 100644 arch/arm/include/asm/efi.h
 create mode 100644 arch/arm/kernel/efi.c
 create mode 100644 drivers/firmware/efi/arm-init.c
 create mode 100644 drivers/firmware/efi/arm-runtime.c
Signature · 1 line
1.9.1
#1 lore raw

PATCH 1/9 arm64/efi: split off EFI init and runtime code for reuse by 32-bit ARM

This splits off the early EFI init and runtime code that
- discovers the EFI params and the memory map from the FDT, and installs the memblocks and config tables.
- prepares and installs the EFI page tables so that UEFI Runtime Services can be invoked at the virtual address installed by the stub.

This will allow it to be reused for 32-bit ARM.

---
 arch/arm64/kernel/efi.c            | 363 +-------------------
 drivers/firmware/efi/Makefile      |   4 +-
 drivers/firmware/efi/arm-init.c    | 214 ++++++++++++
 drivers/firmware/efi/arm-runtime.c | 191 ++++++++++
 4 files changed, 409 insertions(+), 363 deletions(-)
arch/arm64/kernel/efi.c +1 -362
index caca71590984..bd3b2f5adf0c 100644
@@ -11,348 +11,11 @@
  *
  */
 
-#include <linux/atomic.h>
 #include <linux/dmi.h>
 #include <linux/efi.h>
-#include <linux/export.h>
-#include <linux/memblock.h>
-#include <linux/mm_types.h>
-#include <linux/bootmem.h>
-#include <linux/of.h>
-#include <linux/of_fdt.h>
-#include <linux/preempt.h>
-#include <linux/rbtree.h>
-#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
 
-#include <asm/cacheflush.h>
 #include <asm/efi.h>
-#include <asm/tlbflush.h>
-#include <asm/mmu_context.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-
-struct efi_memory_map memmap;
-
-static u64 efi_system_table;
-
-static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
-
-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),
-	.page_table_lock	= __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
-	.mmlist			= LIST_HEAD_INIT(efi_mm.mmlist),
-	INIT_MM_CONTEXT(efi_mm)
-};
-
-static int __init is_normal_ram(efi_memory_desc_t *md)
-{
-	if (md->attribute & EFI_MEMORY_WB)
-		return 1;
-	return 0;
-}
-
-/*
- * Translate a EFI virtual address into a physical address: this is necessary,
- * as some data members of the EFI system table are virtually remapped after
- * SetVirtualAddressMap() has been called.
- */
-static phys_addr_t efi_to_phys(unsigned long addr)
-{
-	efi_memory_desc_t *md;
-
-	for_each_efi_memory_desc(&memmap, md) {
-		if (!(md->attribute & EFI_MEMORY_RUNTIME))
-			continue;
-		if (md->virt_addr == 0)
-			/* no virtual mapping has been installed by the stub */
-			break;
-		if (md->virt_addr <= addr &&
-		    (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
-			return md->phys_addr + addr - md->virt_addr;
-	}
-	return addr;
-}
-
-static int __init uefi_init(void)
-{
-	efi_char16_t *c16;
-	void *config_tables;
-	u64 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;
-	}
-	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) * sizeof(efi_char16_t));
-	if (c16) {
-		for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
-			vendor[i] = c16[i];
-		vendor[i] = '\0';
-		early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
-	}
-
-	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);
-
-	retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
-					 sizeof(efi_config_table_64_t), NULL);
-
-	early_memunmap(config_tables, table_size);
-out:
-	early_memunmap(efi.systab,  sizeof(efi_system_table_t));
-	return retval;
-}
-
-/*
- * Return true for RAM regions we want to permanently reserve.
- */
-static __init int is_reserve_region(efi_memory_desc_t *md)
-{
-	switch (md->type) {
-	case EFI_LOADER_CODE:
-	case EFI_LOADER_DATA:
-	case EFI_BOOT_SERVICES_CODE:
-	case EFI_BOOT_SERVICES_DATA:
-	case EFI_CONVENTIONAL_MEMORY:
-	case EFI_PERSISTENT_MEMORY:
-		return 0;
-	default:
-		break;
-	}
-	return is_normal_ram(md);
-}
-
-static __init void reserve_regions(void)
-{
-	efi_memory_desc_t *md;
-	u64 paddr, npages, size;
-
-	if (efi_enabled(EFI_DBG))
-		pr_info("Processing EFI memory map:\n");
-
-	for_each_efi_memory_desc(&memmap, md) {
-		paddr = md->phys_addr;
-		npages = md->num_pages;
-
-		if (efi_enabled(EFI_DBG)) {
-			char buf[64];
-
-			pr_info("  0x%012llx-0x%012llx %s",
-				paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
-				efi_md_typeattr_format(buf, sizeof(buf), md));
-		}
-
-		memrange_efi_to_native(&paddr, &npages);
-		size = npages << PAGE_SHIFT;
-
-		if (is_normal_ram(md))
-			early_init_dt_add_memory(paddr, size);
-
-		if (is_reserve_region(md)) {
-			memblock_mark_nomap(paddr, size);
-			if (efi_enabled(EFI_DBG))
-				pr_cont("*");
-		}
-
-		if (efi_enabled(EFI_DBG))
-			pr_cont("\n");
-	}
-}
-
-void __init efi_parse_fdt(void *fdt)
-{
-	struct efi_fdt_params params;
-
-	/* Grab UEFI information placed in FDT by stub */
-	if (!efi_get_fdt_params(fdt, &params))
-		return;
-
-	efi_system_table = params.system_table;
-
-	memmap.phys_map = (void *)params.mmap;
-	memmap.desc_size = params.desc_size;
-	memmap.desc_version = params.desc_ver;
-	memmap.nr_map = params.mmap_size / params.desc_size;
-
-	set_bit(EFI_MEMMAP, &efi.flags);
-}
-
-void __init efi_init(void)
-{
-	int mmap_size = memmap.nr_map * memmap.desc_size;
-
-	if (!efi_enabled(EFI_MEMMAP))
-		return;
-
-	memmap.map = early_memremap((u64)memmap.phys_map, mmap_size);
-	memmap.map_end = memmap.map + mmap_size;
-
-	if (uefi_init() < 0)
-		return;
-
-	reserve_regions();
-	early_memunmap(memmap.map, mmap_size);
-	memblock_mark_nomap((unsigned long)memmap.phys_map & PAGE_MASK,
-			    PAGE_ALIGN(mmap_size));
-}
-
-static bool __init efi_virtmap_init(void)
-{
-	efi_memory_desc_t *md;
-
-	for_each_efi_memory_desc(&memmap, md) {
-		u64 paddr, npages, size;
-		pteval_t prot_val;
-
-		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;
-		}
-
-		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;
-}
-
-/*
- * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
- * 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)
-{
-	u64 mapsize;
-
-	if (!efi_enabled(EFI_BOOT)) {
-		pr_info("EFI services will not be available.\n");
-		return -1;
-	}
-
-	if (efi_runtime_disabled()) {
-		pr_info("EFI runtime services will be disabled.\n");
-		return -1;
-	}
-
-	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);
-	if (!memmap.map) {
-		pr_err("Failed to remap EFI memory map\n");
-		return -1;
-	}
-	memmap.map_end = memmap.map + mapsize;
-	efi.memmap = &memmap;
-
-	efi.systab = (__force void *)ioremap_cache(efi_system_table,
-						   sizeof(efi_system_table_t));
-	if (!efi.systab) {
-		pr_err("Failed to remap EFI System Table\n");
-		return -1;
-	}
-	set_bit(EFI_SYSTEM_TABLES, &efi.flags);
-
-	if (!efi_virtmap_init()) {
-		pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
-		return -1;
-	}
-
-	/* Set up runtime services function pointers */
-	efi_native_runtime_setup();
-	set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-
-	efi.runtime_version = efi.systab->hdr.revision;
-
-	return 0;
-}
-early_initcall(arm64_enable_runtime_services);
 
 static int __init arm64_dmi_init(void)
 {
@@ -368,30 +31,6 @@ static int __init arm64_dmi_init(void)
 }
 core_initcall(arm64_dmi_init);
 
-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();
-}
-
-void efi_virtmap_load(void)
-{
-	preempt_disable();
-	efi_set_pgd(&efi_mm);
-}
-
-void efi_virtmap_unload(void)
-{
-	efi_set_pgd(current->active_mm);
-	preempt_enable();
-}
-
 /*
  * UpdateCapsule() depends on the system being shutdown via
  * ResetSystem().
drivers/firmware/efi/Makefile +3 -1
index d9140208fc1c..62b272375422 100644
@@ -1,7 +1,9 @@
 #
 # Makefile for linux kernel
 #
-obj-$(CONFIG_EFI)			+= efi.o vars.o reboot.o
+arm-obj-$(CONFIG_ARM64)$(CONFIG_ARM)	:= arm-init.o arm-runtime.o
+
+obj-$(CONFIG_EFI)			+= efi.o vars.o reboot.o $(arm-obj-y)
 obj-$(CONFIG_EFI_VARS)			+= efivars.o
 obj-$(CONFIG_EFI_ESRT)			+= esrt.o
 obj-$(CONFIG_EFI_VARS_PSTORE)		+= efi-pstore.o
drivers/firmware/efi/arm-init.c new file +214 -0

214 lines not on this page · raw message

drivers/firmware/efi/arm-runtime.c new file +191 -0

191 lines not on this page · raw message

Signature · 1 line
1.9.1
#2 lore raw

PATCH 1/9 arm64/efi: split off EFI init and runtime code for reuse by 32-bit ARM

Quoted 15 lines · Ard Biesheuvel

This splits off the early EFI init and runtime code that
- discovers the EFI params and the memory map from the FDT, and installs the memblocks and config tables.
- prepares and installs the EFI page tables so that UEFI Runtime Services can be invoked at the virtual address installed by the stub.

This will allow it to be reused for 32-bit ARM.

---
 arch/arm64/kernel/efi.c            | 363 +-------------------
 drivers/firmware/efi/Makefile      |   4 +-
 drivers/firmware/efi/arm-init.c    | 214 ++++++++++++
 drivers/firmware/efi/arm-runtime.c | 191 ++++++++++
 4 files changed, 409 insertions(+), 363 deletions(-)

[...]

drivers/firmware/efi/arm-init.c line 34

Quoted 8 lines
drivers/firmware/efi/arm-init.c new file +8 -0
+static int uefi_debug __initdata;
+static int __init uefi_debug_setup(char *str)
+{
+	uefi_debug = 1;
+
+	return 0;
+}
+early_param("uefi_debug", uefi_debug_setup);

Was this hunk an unintentional reintroduction of the code Leif deleted in commit a9cc0cf5701b ("arm64: Use core efi=debug instead of uefi_debug command line parameter")?

Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
#3 lore raw

PATCH 1/9 arm64/efi: split off EFI init and runtime code for reuse by 32-bit ARM

Quoted 19 lines · Matt Fleming
Quoted 15 lines · Ard Biesheuvel

This splits off the early EFI init and runtime code that
- discovers the EFI params and the memory map from the FDT, and installs the memblocks and config tables.
- prepares and installs the EFI page tables so that UEFI Runtime Services can be invoked at the virtual address installed by the stub.

This will allow it to be reused for 32-bit ARM.

---
 arch/arm64/kernel/efi.c            | 363 +-------------------
 drivers/firmware/efi/Makefile      |   4 +-
 drivers/firmware/efi/arm-init.c    | 214 ++++++++++++
 drivers/firmware/efi/arm-runtime.c | 191 ++++++++++
 4 files changed, 409 insertions(+), 363 deletions(-)

[...]

Quoted 13 lines

drivers/firmware/efi/arm-init.c line 34

Quoted 8 lines
drivers/firmware/efi/arm-init.c new file +8 -0
+static int uefi_debug __initdata;
+static int __init uefi_debug_setup(char *str)
+{
+     uefi_debug = 1;
+
+     return 0;
+}
+early_param("uefi_debug", uefi_debug_setup);

Was this hunk an unintentional reintroduction of the code Leif deleted in commit a9cc0cf5701b ("arm64: Use core efi=debug instead of uefi_debug command line parameter")?

Indeed. I will get rid of it on v2

#4 lore raw

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

In reply to Ard Biesheuvel

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.

---
 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(-)
arch/arm64/include/asm/efi.h +16 -0
index 7cc8df68c638..a16490d6ec1a 100644
@@ -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);
 
arch/arm64/kernel/efi.c +51 -0

57 lines not on this page · raw message

drivers/firmware/efi/arm-init.c +6 -5
index 56987a5b9033..235677b86e4e 100644
@@ -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)
drivers/firmware/efi/arm-runtime.c +29 -72

153 lines not on this page · raw message

drivers/firmware/efi/efi.c +3 -1
index f5e586bd3b24..2eb31e28a35c 100644
@@ -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));
Signature · 1 line
1.9.1
#5 lore raw

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

Quoted 11 lines · Ard Biesheuvel

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.

---
 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(-)

[...]

drivers/firmware/efi/arm-init.c static int __init uefi_init(void) · line 71

Quoted 12 lines
drivers/firmware/efi/arm-init.c +1 -1
index 56987a5b9033..235677b86e4e 100644
@@ -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;

Perhaps 'table_size' should be unsigned long? At the very least it should be size_t, not int.

drivers/firmware/efi/efi.c line 30

Quoted 13 lines
drivers/firmware/efi/efi.c +2 -0
index f5e586bd3b24..2eb31e28a35c 100644
@@ -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,

Hmm... not quite sure why this new include is required?

Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
#6 lore raw

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

Quoted 15 lines · Matt Fleming
Quoted 11 lines · Ard Biesheuvel

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.

---
 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(-)

[...]

Quoted 16 lines

drivers/firmware/efi/arm-init.c static int __init uefi_init(void) · line 71

Quoted 12 lines
drivers/firmware/efi/arm-init.c +1 -1
index 56987a5b9033..235677b86e4e 100644
@@ -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;

Perhaps 'table_size' should be unsigned long? At the very least it should be size_t, not int.

OK, I will change that.

Quoted 8 lines
Quoted 8 lines
drivers/firmware/efi/efi.c +0 -0
index f5e586bd3b24..2eb31e28a35c 100644
@@ -23,6 +23,8 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
Quoted 8 lines

drivers/firmware/efi/efi.c line 30

Quoted 5 lines
drivers/firmware/efi/efi.c +2 -0
+#include <asm/efi.h>
+
 struct efi __read_mostly efi = {
      .mps                    = EFI_INVALID_TABLE_ADDR,
      .acpi                   = EFI_INVALID_TABLE_ADDR,

Hmm... not quite sure why this new include is required?

I need this or the file won't build on ARM.

We are currently relying on a transitive include of <asm/early_ioremap.h>, which does not exist on IA-64. This is a bit of a kludge, and I am open to better ways of dealing with this. (IA-64 declares early_ioremap() in asm/io.h, and #define's early_memremap() as an alias of it) and I am reluctant to include asm/early_ioremap.h in ARM's asm/io.h (as the other archs do)

Signature · 1 line
Ard.
#7 lore raw

PATCH 3/9 ARM: add support for generic early_ioremap/early_memremap

In reply to Ard Biesheuvel

This enables the generic early_ioremap implementation for ARM.

It uses the fixmap region reserved for kmap. Since early_ioremap is only supported before paging_init(), and kmap is only supported afterwards, this is guaranteed not to cause any clashes.

---
 arch/arm/Kconfig              |  1 +
 arch/arm/include/asm/Kbuild   |  1 +
 arch/arm/include/asm/fixmap.h | 28 +++++++++++++++++++-
 arch/arm/kernel/setup.c       |  7 +++--
 arch/arm/mm/ioremap.c         |  9 +++++++
 arch/arm/mm/mmu.c             |  2 +-
 6 files changed, 44 insertions(+), 4 deletions(-)
arch/arm/Kconfig +1 -0
index 72ad724c67ae..e4b7d6cfd8eb 100644
@@ -20,6 +20,7 @@ config ARM
 	select GENERIC_ALLOCATOR
 	select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
 	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+	select GENERIC_EARLY_IOREMAP
 	select GENERIC_IDLE_POLL_SETUP
 	select GENERIC_IRQ_PROBE
 	select GENERIC_IRQ_SHOW
arch/arm/include/asm/Kbuild +1 -0
index be648eb47cd9..4ea9642af500 100644
@@ -3,6 +3,7 @@
 generic-y += bitsperlong.h
 generic-y += cputime.h
 generic-y += current.h
+generic-y += early_ioremap.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
arch/arm/include/asm/fixmap.h +27 -1
index 58cfe9f1a687..defac13e161a 100644
@@ -19,9 +19,26 @@ enum fixed_addresses {
 	FIX_TEXT_POKE0,
 	FIX_TEXT_POKE1,
 
-	__end_of_fixed_addresses
+	__end_of_fixmap_region,
+
+	/*
+	 * Share the kmap() region with early_ioremap(): this is guaranteed
+	 * not to clash since early_ioremap() is only available before
+	 * paging_init(), and kmap() only after.
+	 */
+#define NR_FIX_BTMAPS		32
+#define FIX_BTMAPS_SLOTS	7
+#define TOTAL_FIX_BTMAPS	(NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
+
+	FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
+	FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
+	__end_of_early_ioremap_region
 };
 
+static const enum fixed_addresses __end_of_fixed_addresses =
+	__end_of_fixmap_region > __end_of_early_ioremap_region ?
+	__end_of_fixmap_region : __end_of_early_ioremap_region;
+
 #define FIXMAP_PAGE_COMMON	(L_PTE_YOUNG | L_PTE_PRESENT | L_PTE_XN | L_PTE_DIRTY)
 
 #define FIXMAP_PAGE_NORMAL	(FIXMAP_PAGE_COMMON | L_PTE_MT_WRITEBACK)
@@ -30,9 +47,18 @@ enum fixed_addresses {
 #define FIXMAP_PAGE_IO		(FIXMAP_PAGE_COMMON | L_PTE_MT_DEV_SHARED | L_PTE_SHARED)
 #define FIXMAP_PAGE_NOCACHE	FIXMAP_PAGE_IO
 
+#define __early_set_fixmap	__set_fixmap
+
+#ifdef CONFIG_MMU
+
 void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
 void __init early_fixmap_init(void);
 
 #include <asm-generic/fixmap.h>
 
+#else
+
+static inline void early_fixmap_init(void) { }
+
+#endif
 #endif
arch/arm/kernel/setup.c +5 -2
index 20edd349d379..5df2bca57c42 100644
@@ -38,6 +38,7 @@
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/elf.h>
+#include <asm/early_ioremap.h>
 #include <asm/fixmap.h>
 #include <asm/procinfo.h>
 #include <asm/psci.h>
@@ -956,8 +957,8 @@ void __init setup_arch(char **cmdline_p)
 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
 	*cmdline_p = cmd_line;
 
-	if (IS_ENABLED(CONFIG_FIX_EARLYCON_MEM))
-		early_fixmap_init();
+	early_fixmap_init();
+	early_ioremap_init();
 
 	parse_early_param();
 
@@ -968,6 +969,8 @@ void __init setup_arch(char **cmdline_p)
 	sanity_check_meminfo();
 	arm_memblock_init(mdesc);
 
+	early_ioremap_reset();
+
 	paging_init(mdesc);
 	request_standard_resources(mdesc);
 
arch/arm/mm/ioremap.c +9 -0
index 0c81056c1dd7..66a978d05958 100644
@@ -30,6 +30,7 @@
 #include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/cacheflush.h>
+#include <asm/early_ioremap.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -469,3 +470,11 @@ int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
 }
 EXPORT_SYMBOL_GPL(pci_ioremap_io);
 #endif
+
+/*
+ * Must be called after early_fixmap_init
+ */
+void __init early_ioremap_init(void)
+{
+	early_ioremap_setup();
+}
arch/arm/mm/mmu.c +1 -1
index 7cd15143a507..b74686be6272 100644
@@ -389,7 +389,7 @@ void __init early_fixmap_init(void)
 	 * The early fixmap range spans multiple pmds, for which
 	 * we are not prepared:
 	 */
-	BUILD_BUG_ON((__fix_to_virt(__end_of_permanent_fixed_addresses) >> PMD_SHIFT)
+	BUILD_BUG_ON((__fix_to_virt(__end_of_early_ioremap_region) >> PMD_SHIFT)
 		     != FIXADDR_TOP >> PMD_SHIFT);
 
 	pmd = fixmap_pmd(FIXADDR_TOP);
Signature · 1 line
1.9.1
#8 lore raw

PATCH 4/9 ARM: only consider memblocks with NOMAP cleared for linear mapping

In reply to Ard Biesheuvel

Take the new memblock attribute MEMBLOCK_NOMAP into account when deciding whether a certain region is or should be covered by the kernel direct mapping.

---
 arch/arm/mm/init.c | 2 +-
 arch/arm/mm/mmu.c  | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)
arch/arm/mm/init.c +1 -1
index 8a63b4cdc0f2..1c667c6804a6 100644
@@ -191,7 +191,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max_low,
 #ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
 {
-	return memblock_is_memory(__pfn_to_phys(pfn));
+	return memblock_is_map_memory(__pfn_to_phys(pfn));
 }
 EXPORT_SYMBOL(pfn_valid);
 #endif
arch/arm/mm/mmu.c +3 -0
index b74686be6272..008f28ef6d68 100644
@@ -1388,6 +1388,9 @@ static void __init map_lowmem(void)
 		phys_addr_t end = start + reg->size;
 		struct map_desc map;
 
+		if (memblock_is_nomap(reg))
+			continue;
+
 		if (end > arm_lowmem_limit)
 			end = arm_lowmem_limit;
 		if (start >= end)
Signature · 1 line
1.9.1
#9 lore raw

PATCH 5/9 ARM: split off core mapping logic from create_mapping

In reply to Ard Biesheuvel

In order to be able to reuse the core mapping logic of create_mapping for mapping the UEFI Runtime Services into a private set of page tables, split it off from create_mapping() into a separate function __create_mapping which we will wire up in a subsequent patch.

---
 arch/arm/mm/mmu.c | 56 +++++++++++---------
 1 file changed, 31 insertions(+), 25 deletions(-)
arch/arm/mm/mmu.c +31 -25
index 008f28ef6d68..3930bad44a61 100644
@@ -817,7 +817,8 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
 }
 
 #ifndef CONFIG_ARM_LPAE
-static void __init create_36bit_mapping(struct map_desc *md,
+static void __init create_36bit_mapping(struct mm_struct *mm,
+					struct map_desc *md,
 					const struct mem_type *type)
 {
 	unsigned long addr, length, end;
@@ -858,7 +859,7 @@ static void __init create_36bit_mapping(struct map_desc *md,
 	 */
 	phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
 
-	pgd = pgd_offset_k(addr);
+	pgd = pgd_offset(mm, addr);
 	end = addr + length;
 	do {
 		pud_t *pud = pud_offset(pgd, addr);
@@ -875,33 +876,13 @@ static void __init create_36bit_mapping(struct map_desc *md,
 }
 #endif	/* !CONFIG_ARM_LPAE */
 
-/*
- * Create the page directory entries and any necessary
- * page tables for the mapping specified by `md'.  We
- * are able to cope here with varying sizes and address
- * offsets, and we take full advantage of sections and
- * supersections.
- */
-static void __init create_mapping(struct map_desc *md)
+static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md)
 {
 	unsigned long addr, length, end;
 	phys_addr_t phys;
 	const struct mem_type *type;
 	pgd_t *pgd;
 
-	if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
-		pr_warn("BUG: not creating mapping for 0x%08llx@0x%08lx in user region\n",
-			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
-		return;
-	}
-
-	if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
-	    md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
-	    (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
-		pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
-			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
-	}
-
 	type = &mem_types[md->type];
 
 #ifndef CONFIG_ARM_LPAE
@@ -909,7 +890,7 @@ static void __init create_mapping(struct map_desc *md)
 	 * Catch 36-bit addresses
 	 */
 	if (md->pfn >= 0x100000) {
-		create_36bit_mapping(md, type);
+		create_36bit_mapping(mm, md, type);
 		return;
 	}
 #endif
@@ -924,7 +905,7 @@ static void __init create_mapping(struct map_desc *md)
 		return;
 	}
 
-	pgd = pgd_offset_k(addr);
+	pgd = pgd_offset(mm, addr);
 	end = addr + length;
 	do {
 		unsigned long next = pgd_addr_end(addr, end);
@@ -937,6 +918,31 @@ static void __init create_mapping(struct map_desc *md)
 }
 
 /*
+ * Create the page directory entries and any necessary
+ * page tables for the mapping specified by `md'.  We
+ * are able to cope here with varying sizes and address
+ * offsets, and we take full advantage of sections and
+ * supersections.
+ */
+static void __init create_mapping(struct map_desc *md)
+{
+	if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
+		pr_warn("BUG: not creating mapping for 0x%08llx@0x%08lx in user region\n",
+			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
+		return;
+	}
+
+	if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
+	    md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
+	    (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
+		pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
+			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
+	}
+
+	__create_mapping(&init_mm, md);
+}
+
+/*
  * Create the architecture specific mappings
  */
 void __init iotable_init(struct map_desc *io_desc, int nr)
Signature · 1 line
1.9.1
#10 lore raw

PATCH 6/9 ARM: factor out allocation routine from __create_mapping()

In reply to Ard Biesheuvel

To allow __create_mapping() to be used for populating UEFI Runtime Services page tables, factor out the allocation routine 'early_alloc' and pass it down as a function pointer into alloc_init_[pud|pmd|pte]. This way, new users of __create_mapping() can supply another allocation function.

---
 arch/arm/mm/mmu.c | 34 +++++++++++++-------
 1 file changed, 23 insertions(+), 11 deletions(-)
arch/arm/mm/mmu.c +23 -11
index 3930bad44a61..dd0967ee23b7 100644
@@ -723,21 +723,30 @@ static void __init *early_alloc(unsigned long sz)
 	return early_alloc_aligned(sz, sz);
 }
 
-static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot)
+static pte_t * __init pte_alloc(pmd_t *pmd, unsigned long addr,
+				unsigned long prot,
+				void *(*alloc)(unsigned long sz))
 {
 	if (pmd_none(*pmd)) {
-		pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+		pte_t *pte = alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
 		__pmd_populate(pmd, __pa(pte), prot);
 	}
 	BUG_ON(pmd_bad(*pmd));
 	return pte_offset_kernel(pmd, addr);
 }
 
+static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr,
+				      unsigned long prot)
+{
+	return pte_alloc(pmd, addr, prot, early_alloc);
+}
+
 static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
 				  unsigned long end, unsigned long pfn,
-				  const struct mem_type *type)
+				  const struct mem_type *type,
+				  void *(*alloc)(unsigned long sz))
 {
-	pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);
+	pte_t *pte = pte_alloc(pmd, addr, type->prot_l1, alloc);
 	do {
 		set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
 		pfn++;
@@ -773,7 +782,8 @@ static void __init __map_init_section(pmd_t *pmd, unsigned long addr,
 
 static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
 				      unsigned long end, phys_addr_t phys,
-				      const struct mem_type *type)
+				      const struct mem_type *type,
+				      void *(*alloc)(unsigned long sz))
 {
 	pmd_t *pmd = pmd_offset(pud, addr);
 	unsigned long next;
@@ -794,7 +804,7 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
 			__map_init_section(pmd, addr, next, phys, type);
 		} else {
 			alloc_init_pte(pmd, addr, next,
-						__phys_to_pfn(phys), type);
+				       __phys_to_pfn(phys), type, alloc);
 		}
 
 		phys += next - addr;
@@ -804,14 +814,15 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
 
 static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
 				  unsigned long end, phys_addr_t phys,
-				  const struct mem_type *type)
+				  const struct mem_type *type,
+				  void *(*alloc)(unsigned long sz))
 {
 	pud_t *pud = pud_offset(pgd, addr);
 	unsigned long next;
 
 	do {
 		next = pud_addr_end(addr, end);
-		alloc_init_pmd(pud, addr, next, phys, type);
+		alloc_init_pmd(pud, addr, next, phys, type, alloc);
 		phys += next - addr;
 	} while (pud++, addr = next, addr != end);
 }
@@ -876,7 +887,8 @@ static void __init create_36bit_mapping(struct mm_struct *mm,
 }
 #endif	/* !CONFIG_ARM_LPAE */
 
-static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md)
+static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md,
+				    void *(*alloc)(unsigned long sz))
 {
 	unsigned long addr, length, end;
 	phys_addr_t phys;
@@ -910,7 +922,7 @@ static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md)
 	do {
 		unsigned long next = pgd_addr_end(addr, end);
 
-		alloc_init_pud(pgd, addr, next, phys, type);
+		alloc_init_pud(pgd, addr, next, phys, type, alloc);
 
 		phys += next - addr;
 		addr = next;
@@ -939,7 +951,7 @@ static void __init create_mapping(struct map_desc *md)
 			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
 	}
 
-	__create_mapping(&init_mm, md);
+	__create_mapping(&init_mm, md, early_alloc);
 }
 
 /*
Signature · 1 line
1.9.1
#11 lore raw

PATCH 7/9 ARM: implement create_mapping_late() for EFI use

In reply to Ard Biesheuvel

This implements create_mapping_late(), which we will use to populate the UEFI Runtime Services page tables.

---
 arch/arm/include/asm/mach/map.h |  1 +
 arch/arm/mm/mmu.c               | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+)
arch/arm/include/asm/mach/map.h +1 -0
index f98c7f32c9c8..14fe67bd0272 100644
@@ -42,6 +42,7 @@ enum {
 extern void iotable_init(struct map_desc *, int);
 extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
 				  void *caller);
+extern void create_mapping_late(struct mm_struct *mm, struct map_desc *md);
 
 #ifdef CONFIG_DEBUG_LL
 extern void debug_ll_addr(unsigned long *paddr, unsigned long *vaddr);
arch/arm/mm/mmu.c +19 -0
index dd0967ee23b7..c5f0c0ade981 100644
@@ -723,6 +723,14 @@ static void __init *early_alloc(unsigned long sz)
 	return early_alloc_aligned(sz, sz);
 }
 
+static void *__init late_alloc(unsigned long sz)
+{
+	void *ptr = (void *)__get_free_pages(PGALLOC_GFP, get_order(sz));
+
+	BUG_ON(!ptr);
+	return ptr;
+}
+
 static pte_t * __init pte_alloc(pmd_t *pmd, unsigned long addr,
 				unsigned long prot,
 				void *(*alloc)(unsigned long sz))
@@ -954,6 +962,17 @@ static void __init create_mapping(struct map_desc *md)
 	__create_mapping(&init_mm, md, early_alloc);
 }
 
+void __init create_mapping_late(struct mm_struct *mm, struct map_desc *md)
+{
+#ifdef CONFIG_ARM_LPAE
+	pud_t *pud = pud_alloc(mm, pgd_offset(mm, md->virtual), md->virtual);
+	if (WARN_ON(!pud))
+		return;
+	pmd_alloc(mm, pud, 0);
+#endif
+	__create_mapping(mm, md, late_alloc);
+}
+
 /*
  * Create the architecture specific mappings
  */
Signature · 1 line
1.9.1
#12 lore raw

PATCH 8/9 ARM: wire up UEFI init and runtime support

In reply to Ard Biesheuvel

This adds support to the kernel proper for booting via UEFI. It shares most of the code with arm64, so this patch mostly just wires it up for use with ARM.

Note that this does not include the EFI stub, it is added in a subsequent patch.

---
 arch/arm/include/asm/efi.h              | 69 +++++++++++++++++++
 arch/arm/kernel/Makefile                |  1 +
 arch/arm/kernel/devtree.c               |  4 ++
 arch/arm/kernel/efi.c                   | 71 ++++++++++++++++++++
 arch/arm/kernel/setup.c                 |  3 +
 arch/arm/mm/init.c                      | 14 +++-
 drivers/firmware/efi/libstub/arm-stub.c |  4 +-
 7 files changed, 164 insertions(+), 2 deletions(-)
arch/arm/include/asm/efi.h new file +69 -0
new file mode 100644
index 000000000000..2622322f1135
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARM_EFI_H
+#define __ASM_ARM_EFI_H
+
+#include <asm/cacheflush.h>
+#include <asm/cachetype.h>
+#include <asm/early_ioremap.h>
+#include <asm/fixmap.h>
+#include <asm/highmem.h>
+#include <asm/mach/map.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_EFI
+void efi_init(void);
+void efi_parse_fdt(void *fdt);
+
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+
+#define efi_call_virt(f, ...)						\
+({									\
+	efi_##f##_t *__f;						\
+	efi_status_t __s;						\
+									\
+	efi_virtmap_load();						\
+	__f = efi.systab->runtime->f;					\
+	__s = __f(__VA_ARGS__);						\
+	efi_virtmap_unload();						\
+	__s;								\
+})
+
+#define __efi_call_virt(f, ...)						\
+({									\
+	efi_##f##_t *__f;						\
+									\
+	efi_virtmap_load();						\
+	__f = efi.systab->runtime->f;					\
+	__f(__VA_ARGS__);						\
+	efi_virtmap_unload();						\
+})
+
+static inline void efi_set_pgd(struct mm_struct *mm)
+{
+	if (unlikely(mm->context.vmalloc_seq != init_mm.context.vmalloc_seq))
+		__check_vmalloc_seq(mm);
+
+	cpu_switch_mm(mm->pgd, mm);
+
+	flush_tlb_all();
+	if (icache_is_vivt_asid_tagged())
+		__flush_icache_all();
+}
+
+void efi_virtmap_load(void);
+void efi_virtmap_unload(void);
+
+#else
+#define efi_init()
+#define efi_parse_fdt(x)
+#endif /* CONFIG_EFI */
+
+#endif /* _ASM_ARM_EFI_H */
arch/arm/kernel/Makefile +1 -0
index af9e59bf3831..c90f4a70d646 100644
@@ -77,6 +77,7 @@ CFLAGS_pj4-cp0.o		:= -marm
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 obj-$(CONFIG_VDSO)		+= vdso.o
+obj-$(CONFIG_EFI)		+= efi.o
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
   obj-y		+= io.o
arch/arm/kernel/devtree.c +4 -0
index 11c54de9f8cf..c3439eaf46ce 100644
@@ -9,6 +9,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/efi.h>
 #include <linux/export.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -21,6 +22,7 @@
 #include <linux/smp.h>
 
 #include <asm/cputype.h>
+#include <asm/efi.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/smp_plat.h>
@@ -215,6 +217,8 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
 	if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys)))
 		return NULL;
 
+	efi_parse_fdt(phys_to_virt(dt_phys));
+
 	mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
 
 	if (!mdesc) {
arch/arm/kernel/efi.c new file +71 -0

71 lines not on this page · raw message

arch/arm/kernel/setup.c +3 -0
index 5df2bca57c42..b341b1c3b2fa 100644
@@ -7,6 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/efi.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
@@ -37,6 +38,7 @@
 #include <asm/cp15.h>
 #include <asm/cpu.h>
 #include <asm/cputype.h>
+#include <asm/efi.h>
 #include <asm/elf.h>
 #include <asm/early_ioremap.h>
 #include <asm/fixmap.h>
@@ -966,6 +968,7 @@ void __init setup_arch(char **cmdline_p)
 	early_paging_init(mdesc);
 #endif
 	setup_dma_zone(mdesc);
+	efi_init();
 	sanity_check_meminfo();
 	arm_memblock_init(mdesc);
 
arch/arm/mm/init.c +13 -1
index 1c667c6804a6..43df6a23689b 100644
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/kernel.h>
+#include <linux/efi.h>
 #include <linux/errno.h>
 #include <linux/swap.h>
 #include <linux/init.h>
@@ -24,6 +25,7 @@
 #include <linux/sizes.h>
 
 #include <asm/cp15.h>
+#include <asm/efi.h>
 #include <asm/mach-types.h>
 #include <asm/memblock.h>
 #include <asm/prom.h>
@@ -269,7 +271,8 @@ void __init arm_memblock_init(const struct machine_desc *mdesc)
 		mdesc->reserve();
 
 	early_init_fdt_reserve_self();
-	early_init_fdt_scan_reserved_mem();
+	if (!efi_enabled(EFI_MEMMAP))
+		early_init_fdt_scan_reserved_mem();
 
 	/* reserve memory for DMA contiguous allocations */
 	dma_contiguous_reserve(arm_dma_limit);
@@ -751,3 +754,12 @@ static int __init keepinitrd_setup(char *__unused)
 
 __setup("keepinitrd", keepinitrd_setup);
 #endif
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+	/*
+	 * Ignore DT memory nodes if we are booting via UEFI.
+	 */
+	if (!efi_enabled(EFI_MEMMAP))
+		early_init_dt_add_memory(base, size);
+}
drivers/firmware/efi/libstub/arm-stub.c +3 -1
index 950c87f5d279..3397902e4040 100644
@@ -303,8 +303,10 @@ fail:
  * The value chosen is the largest non-zero power of 2 suitable for this purpose
  * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
  * be mapped efficiently.
+ * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split,
+ * map everything below 1 GB.
  */
-#define EFI_RT_VIRTUAL_BASE	0x40000000
+#define EFI_RT_VIRTUAL_BASE	SZ_512M
 
 static int cmp_mem_desc(const void *l, const void *r)
 {
Signature · 1 line
1.9.1
#13 lore raw

PATCH 9/9 ARM: add UEFI stub support

In reply to Ard Biesheuvel

From: Roy Franz <[email protected]>

This patch adds EFI stub support for the ARM Linux kernel.

The EFI stub operates similarly to the x86 and arm64 stubs: it is a shim between the EFI firmware and the normal zImage entry point, and sets up the environment that the zImage is expecting. This includes optionally loading the initrd and device tree from the system partition based on the kernel command line.

---
 arch/arm/Kconfig                       |  19 +++
 arch/arm/boot/compressed/Makefile      |   5 +-
 arch/arm/boot/compressed/efi-header.S  | 130 ++++++++++++++++++++
 arch/arm/boot/compressed/efi-stub.c    |  89 ++++++++++++++
 arch/arm/boot/compressed/head.S        |  54 +++++++-
 arch/arm/boot/compressed/vmlinux.lds.S |   7 ++
 arch/arm/include/asm/efi.h             |  23 ++++
 drivers/firmware/efi/libstub/Makefile  |  12 ++
 8 files changed, 336 insertions(+), 3 deletions(-)
arch/arm/Kconfig +19 -0
index e4b7d6cfd8eb..6d7fd83c2ee4 100644
@@ -2061,6 +2061,25 @@ config AUTO_ZRELADDR
 	  0xf8000000. This assumes the zImage being placed in the first 128MB
 	  from start of memory.
 
+config EFI_STUB
+	bool
+
+config EFI
+	bool "UEFI runtime support"
+	depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR && !XIP_KERNEL
+	select UCS2_STRING
+	select EFI_PARAMS_FROM_FDT
+	select EFI_STUB
+	select EFI_ARMSTUB
+	select EFI_RUNTIME_WRAPPERS
+	---help---
+	  This option provides support for runtime services provided
+	  by UEFI firmware (such as non-volatile variables, realtime
+	  clock, and platform reset). A UEFI stub is also provided to
+	  allow the kernel to be booted as an EFI application. This
+	  is only useful for kernels that may run on systems that have
+	  UEFI firmware.
+
 endmenu
 
 menu "CPU Power Management"
arch/arm/boot/compressed/Makefile +4 -1
index 3f9a9ebc77c3..0e5624d6215d 100644
@@ -167,9 +167,12 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
 	false; \
 fi
 
+efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o $(obj)/efi-banner.o \
+			      $(objtree)/drivers/firmware/efi/libstub/lib.a
+
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
 		$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
-		$(bswapsdi2) FORCE
+		$(bswapsdi2) $(efi-obj-y) FORCE
 	@$(check_for_multiple_zreladdr)
 	$(call if_changed,ld)
 	@$(check_for_bad_syms)
arch/arm/boot/compressed/efi-header.S new file +130 -0

130 lines not on this page · raw message

arch/arm/boot/compressed/efi-stub.c new file +89 -0

89 lines not on this page · raw message

arch/arm/boot/compressed/head.S +52 -2

78 lines not on this page · raw message

arch/arm/boot/compressed/vmlinux.lds.S +7 -0
index 2b60b843ac5e..81c493156ce8 100644
@@ -48,6 +48,13 @@ SECTIONS
     *(.rodata)
     *(.rodata.*)
   }
+  .data : {
+    /*
+     * The EFI stub always executes from RAM, and runs strictly before the
+     * decompressor, so we can make an exception for its r/w data, and keep it
+     */
+    *(.data.efistub)
+  }
   .piggydata : {
     *(.piggydata)
   }
arch/arm/include/asm/efi.h +23 -0
index 2622322f1135..bf22d0d1d52d 100644
@@ -66,4 +66,27 @@ void efi_virtmap_unload(void);
 #define efi_parse_fdt(x)
 #endif /* CONFIG_EFI */
 
+/* arch specific definitions used by the stub code */
+
+#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
+
+/*
+ * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
+ * so we will reserve that amount of memory. We have no easy way to tell what
+ * the actuall size of code + data the uncompressed kernel will use.
+ * If this is insufficient, the decompressor will relocate itself out of the
+ * way before performing the decompression.
+ */
+#define MAX_UNCOMP_KERNEL_SIZE	SZ_32M
+
+/*
+ * The kernel zImage should preferably be located between 32 MB and 128 MB
+ * from the base of DRAM. The min address leaves space for a maximal size
+ * uncompressed image, and the max address is due to how the zImage decompressor
+ * picks a destination address.
+ */
+#define ZIMAGE_OFFSET_LIMIT	SZ_128M
+#define MIN_ZIMAGE_OFFSET	MAX_UNCOMP_KERNEL_SIZE
+#define MAX_FDT_OFFSET		ZIMAGE_OFFSET_LIMIT
+
 #endif /* _ASM_ARM_EFI_H */
drivers/firmware/efi/libstub/Makefile +12 -0
index 50557f4d12db..6d86e2713e9f 100644
@@ -62,3 +62,15 @@ quiet_cmd_stubcopy = STUBCPY $@
 		     $(OBJDUMP) -r $@ | grep R_AARCH64_ABS 		\
 		     && (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \
 			 rm -f $@; /bin/false); else /bin/false; fi
+
+#
+# ARM discards the .data section because it disallows r/w data in the
+# decompressor. So move our .data to .data.efistub, which is preserved
+# explicitly by the decompressor linker script.
+#
+extra-$(CONFIG_ARM)		:= $(lib-y)
+lib-$(CONFIG_ARM)		:= $(patsubst %.o,%.stub.o,$(lib-y))
+
+$(obj)/%.stub.o: OBJCOPYFLAGS := --rename-section .data=.data.efistub
+$(obj)/%.stub.o: $(obj)/%.o FORCE
+	$(call if_changed,objcopy)
Signature · 1 line
1.9.1

A message that is not in the archive (sent off-list or not yet received): CAD0U-h+zPhDe6Fqpg_vhF46FLjvvsbeSrQ_Fnj86o5cRc+A2QQ@mail.gmail.com

#15 lore raw

PATCH 9/9 ARM: add UEFI stub support

Quoted 37 lines · Ryan Harkin

Hi Ard/Roy,

Quoted 33 lines · Ard Biesheuvel

From: Roy Franz <[email protected]>

This patch adds EFI stub support for the ARM Linux kernel.

The EFI stub operates similarly to the x86 and arm64 stubs: it is a shim between the EFI firmware and the normal zImage entry point, and sets up the environment that the zImage is expecting. This includes optionally loading the initrd and device tree from the system partition based on the kernel command line.

---
 arch/arm/Kconfig                       |  19 +++
 arch/arm/boot/compressed/Makefile      |   5 +-
 arch/arm/boot/compressed/efi-header.S  | 130 ++++++++++++++++++++
 arch/arm/boot/compressed/efi-stub.c    |  89 ++++++++++++++
 arch/arm/boot/compressed/head.S        |  54 +++++++-
 arch/arm/boot/compressed/vmlinux.lds.S |   7 ++
 arch/arm/include/asm/efi.h             |  23 ++++
 drivers/firmware/efi/libstub/Makefile  |  12 ++
 8 files changed, 336 insertions(+), 3 deletions(-)
arch/arm/Kconfig +0 -0
index e4b7d6cfd8eb..6d7fd83c2ee4 100644
@@ -2061,6 +2061,25 @@ config AUTO_ZRELADDR
          0xf8000000. This assumes the zImage being placed in the first

128MB
from start of memory.

Quoted 17 lines

arch/arm/Kconfig

Quoted 12 lines
arch/arm/Kconfig +6 -0
+config EFI_STUB
+       bool
+
+config EFI
+       bool "UEFI runtime support"
+       depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR &&

!XIP_KERNEL

arch/arm/Kconfig +5 -0
+       select UCS2_STRING
+       select EFI_PARAMS_FROM_FDT
+       select EFI_STUB
+       select EFI_ARMSTUB
+       select EFI_RUNTIME_WRAPPERS

Should we make this "default y" like ARM64? I think so.

It is not necessarily something that should be enabled by default, imo. The distro kernels will probably enabled it, which is good enough for me.

Quoted 26 lines
Quoted 17 lines
arch/arm/Kconfig +8 -0
+       ---help---
+         This option provides support for runtime services provided
+         by UEFI firmware (such as non-volatile variables, realtime
+         clock, and platform reset). A UEFI stub is also provided to
+         allow the kernel to be booted as an EFI application. This
+         is only useful for kernels that may run on systems that have
+         UEFI firmware.
+
 endmenu
 
 menu "CPU Power Management"
arch/arm/boot/compressed/Makefile +0 -0
index 3f9a9ebc77c3..0e5624d6215d 100644

arch/arm/boot/compressed/Makefile if [ $(words $(ZRELADDR)) -gt 1 -a · line 171

Quoted 5 lines
arch/arm/boot/compressed/Makefile +1 -0
@@ -167,9 +167,12 @@ if [ $(words $(ZRELADDR)) -gt 1 -a
 "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
        false; \
 fi
 
+efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o $(obj)/efi-banner.o \

When I try to compile the kernel from your branch, I get:

Quoted 5 lines

make[2]: *** No rule to make target 'arch/arm/boot/compressed/efi-banner.o', needed by 'arch/arm/boot/compressed/vmlinux'. Stop.

Did I miss something or is this a problem?

It was I who missed something: I have been reshuffling some bits, and this fell through the cracks. I didn't spot it since I apparently did not try to rebuild it cleanly.

I would like to get rid of the linux_banner reference in the stub completely, and I posted a patch here

In the mean time, could you try with this folded in?

-------------------8<--------------------

(quoted diff) +0 -0

b/arch/arm/boot/compressed/Makefile
index 0e5624d6215d..a6aa7f9123a2 100644

arch/arm/boot/compressed/Makefile +4 -0
@@ -170,6 +170,10 @@ fi
 efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o $(obj)/efi-banner.o \
                              $(objtree)/drivers/firmware/efi/libstub/lib.a
 
+$(obj)/efi-banner.o: OBJCOPYFLAGS=-j .rodata
+$(obj)/efi-banner.o: $(objtree)/init/version.o FORCE
+       $(call if_changed,objcopy)
+
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
                $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
                $(bswapsdi2) $(efi-obj-y) FORCE
(quoted diff) +0 -0

b/drivers/firmware/efi/libstub/fdt.c
index a7e87cd582f2..f45a6f715e73 100644

drivers/firmware/efi/libstub/fdt.c +2 -0
@@ -16,6 +16,8 @@
 
 #include "efistub.h"
 
+extern __attribute__((__visibility__("hidden"))) const char linux_banner[];
+
 efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
                        unsigned long orig_fdt_size,
                        void *fdt, int new_fdt_size, char *cmdline_ptr,

-------------------8<--------------------

Thanks for testing!

Signature · 1 line
Ard.
#16 lore raw

PATCH 9/9 ARM: add UEFI stub support

Quoted 92 lines · Ard Biesheuvel
Quoted 37 lines · Ryan Harkin

Hi Ard/Roy,

Quoted 33 lines · Ard Biesheuvel

From: Roy Franz <[email protected]>

This patch adds EFI stub support for the ARM Linux kernel.

The EFI stub operates similarly to the x86 and arm64 stubs: it is a shim between the EFI firmware and the normal zImage entry point, and sets up the environment that the zImage is expecting. This includes optionally loading the initrd and device tree from the system partition based on the kernel command line.

---
 arch/arm/Kconfig                       |  19 +++
 arch/arm/boot/compressed/Makefile      |   5 +-
 arch/arm/boot/compressed/efi-header.S  | 130 ++++++++++++++++++++
 arch/arm/boot/compressed/efi-stub.c    |  89 ++++++++++++++
 arch/arm/boot/compressed/head.S        |  54 +++++++-
 arch/arm/boot/compressed/vmlinux.lds.S |   7 ++
 arch/arm/include/asm/efi.h             |  23 ++++
 drivers/firmware/efi/libstub/Makefile  |  12 ++
 8 files changed, 336 insertions(+), 3 deletions(-)
arch/arm/Kconfig +0 -0
index e4b7d6cfd8eb..6d7fd83c2ee4 100644
@@ -2061,6 +2061,25 @@ config AUTO_ZRELADDR
          0xf8000000. This assumes the zImage being placed in the first

128MB
from start of memory.

Quoted 17 lines

arch/arm/Kconfig

Quoted 12 lines
arch/arm/Kconfig +6 -0
+config EFI_STUB
+       bool
+
+config EFI
+       bool "UEFI runtime support"
+       depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR &&

!XIP_KERNEL

arch/arm/Kconfig +5 -0
+       select UCS2_STRING
+       select EFI_PARAMS_FROM_FDT
+       select EFI_STUB
+       select EFI_ARMSTUB
+       select EFI_RUNTIME_WRAPPERS

Should we make this "default y" like ARM64? I think so.

It is not necessarily something that should be enabled by default, imo. The distro kernels will probably enabled it, which is good enough for me.

Quoted 26 lines
Quoted 17 lines
arch/arm/Kconfig +8 -0
+       ---help---
+         This option provides support for runtime services provided
+         by UEFI firmware (such as non-volatile variables, realtime
+         clock, and platform reset). A UEFI stub is also provided to
+         allow the kernel to be booted as an EFI application. This
+         is only useful for kernels that may run on systems that have
+         UEFI firmware.
+
 endmenu
 
 menu "CPU Power Management"
arch/arm/boot/compressed/Makefile +0 -0
index 3f9a9ebc77c3..0e5624d6215d 100644

arch/arm/boot/compressed/Makefile if [ $(words $(ZRELADDR)) -gt 1 -a · line 171

Quoted 5 lines
arch/arm/boot/compressed/Makefile +1 -0
@@ -167,9 +167,12 @@ if [ $(words $(ZRELADDR)) -gt 1 -a
 "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
        false; \
 fi
 
+efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o $(obj)/efi-banner.o \

When I try to compile the kernel from your branch, I get:

Quoted 5 lines

make[2]: *** No rule to make target 'arch/arm/boot/compressed/efi-banner.o', needed by 'arch/arm/boot/compressed/vmlinux'. Stop.

Did I miss something or is this a problem?

Quoted 7 lines

It was I who missed something: I have been reshuffling some bits, and this fell through the cracks. I didn't spot it since I apparently did not try to rebuild it cleanly.

I would like to get rid of the linux_banner reference in the stub completely, and I posted a patch here

Where? Here:
http://marc.info/?l=linux-arm-kernel&m=144313135923256

Quoted 39 lines

In the mean time, could you try with this folded in?

-------------------8<--------------------

arch/arm/boot/compressed/Makefile +4 -0
index 0e5624d6215d..a6aa7f9123a2 100644
@@ -170,6 +170,10 @@ fi
 efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o $(obj)/efi-banner.o \
                              $(objtree)/drivers/firmware/efi/libstub/lib.a
 
+$(obj)/efi-banner.o: OBJCOPYFLAGS=-j .rodata
+$(obj)/efi-banner.o: $(objtree)/init/version.o FORCE
+       $(call if_changed,objcopy)
+
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
                $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
                $(bswapsdi2) $(efi-obj-y) FORCE
drivers/firmware/efi/libstub/fdt.c +2 -1
index a7e87cd582f2..f45a6f715e73 100644
@@ -16,6 +16,8 @@
 
 #include "efistub.h"
 
+extern __attribute__((__visibility__("hidden"))) const char linux_banner[];
+
 efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
                        unsigned long orig_fdt_size,
                        void *fdt, int new_fdt_size, char *cmdline_ptr,
-------------------8<--------------------

Thanks for testing!

--
Ard.

A message that is not in the archive (sent off-list or not yet received): CAD0U-hK8=65digSpQ8b3zQcx4P3DFayu8eONDsYp9wA4ypPscg@mail.gmail.com

#18 lore raw

PATCH 9/9 ARM: add UEFI stub support

Quoted 159 lines · Ryan Harkin
Quoted 61 lines · Ard Biesheuvel
Quoted 58 lines · Ard Biesheuvel
Quoted 56 lines · Ryan Harkin

Hi Ard/Roy,

Quoted 42 lines · Ard Biesheuvel

From: Roy Franz <[email protected]>

This patch adds EFI stub support for the ARM Linux kernel.

The EFI stub operates similarly to the x86 and arm64 stubs: it is a shim between the EFI firmware and the normal zImage entry point, and sets up the environment that the zImage is expecting. This includes optionally loading the initrd and device tree from the system partition
based on the kernel command line.

---
 arch/arm/Kconfig                       |  19 +++
 arch/arm/boot/compressed/Makefile      |   5 +-
 arch/arm/boot/compressed/efi-header.S  | 130 ++++++++++++++++++++
 arch/arm/boot/compressed/efi-stub.c    |  89 ++++++++++++++
 arch/arm/boot/compressed/head.S        |  54 +++++++-
 arch/arm/boot/compressed/vmlinux.lds.S |   7 ++
 arch/arm/include/asm/efi.h             |  23 ++++
 drivers/firmware/efi/libstub/Makefile  |  12 ++
 8 files changed, 336 insertions(+), 3 deletions(-)
arch/arm/Kconfig +0 -0
index e4b7d6cfd8eb..6d7fd83c2ee4 100644
@@ -2061,6 +2061,25 @@ config AUTO_ZRELADDR
          0xf8000000. This assumes the zImage being placed in the

first
128MB
from start of memory.

arch/arm/Kconfig +6 -0
+config EFI_STUB
+       bool
+
+config EFI
+       bool "UEFI runtime support"
+       depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR &&

!XIP_KERNEL

arch/arm/Kconfig

Quoted 5 lines
arch/arm/Kconfig +5 -0
+       select UCS2_STRING
+       select EFI_PARAMS_FROM_FDT
+       select EFI_STUB
+       select EFI_ARMSTUB
+       select EFI_RUNTIME_WRAPPERS

Should we make this "default y" like ARM64? I think so.

Quoted 3 lines
Quoted 3 lines

It is not necessarily something that should be enabled by default, imo. The distro kernels will probably enabled it, which is good enough for me.

That's fair enough. I think it is default for arm64, hence why I asked. But I can enable it myself in my own configs easily enough.

Quoted 75 lines
Quoted 34 lines
Quoted 27 lines
Quoted 18 lines
arch/arm/Kconfig +8 -0
+       ---help---
+         This option provides support for runtime services provided
+         by UEFI firmware (such as non-volatile variables, realtime
+         clock, and platform reset). A UEFI stub is also provided to
+         allow the kernel to be booted as an EFI application. This
+         is only useful for kernels that may run on systems that have
+         UEFI firmware.
+
 endmenu
 
 menu "CPU Power Management"
arch/arm/boot/compressed/Makefile +0 -0
index 3f9a9ebc77c3..0e5624d6215d 100644

arch/arm/boot/compressed/Makefile if [ $(words $(ZRELADDR)) -gt 1 -a · line 171

Quoted 5 lines
arch/arm/boot/compressed/Makefile +1 -0
@@ -167,9 +167,12 @@ if [ $(words $(ZRELADDR)) -gt 1 -a
 "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
        false; \
 fi
 
+efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o $(obj)/efi-banner.o \

When I try to compile the kernel from your branch, I get:

Quoted 6 lines

make[2]: *** No rule to make target 'arch/arm/boot/compressed/efi-banner.o', needed by 'arch/arm/boot/compressed/vmlinux'. Stop.

Did I miss something or is this a problem?

Quoted 7 lines

It was I who missed something: I have been reshuffling some bits, and this fell through the cracks. I didn't spot it since I apparently did not try to rebuild it cleanly.

I would like to get rid of the linux_banner reference in the stub completely, and I posted a patch here

Where? Here:
http://marc.info/?l=linux-arm-kernel&m=144313135923256

Quoted 30 lines

In the mean time, could you try with this folded in?

-------------------8<--------------------

arch/arm/boot/compressed/Makefile +0 -0
index 0e5624d6215d..a6aa7f9123a2 100644
@@ -170,6 +170,10 @@ fi
 efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o $(obj)/efi-banner.o \
 

$(objtree)/drivers/firmware/efi/libstub/lib.a

+$(obj)/efi-banner.o: OBJCOPYFLAGS=-j .rodata +$(obj)/efi-banner.o: $(objtree)/init/version.o FORCE

arch/arm/boot/compressed/Makefile +2 -0
+       $(call if_changed,objcopy)
+
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD)
$(obj)/piggy.$(suffix_y).o \
                $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
                $(bswapsdi2) $(efi-obj-y) FORCE
drivers/firmware/efi/libstub/fdt.c +0 -0
index a7e87cd582f2..f45a6f715e73 100644
@@ -16,6 +16,8 @@
 
 #include "efistub.h"
 
Quoted 8 lines
Quoted 8 lines
drivers/firmware/efi/libstub/fdt.c +2 -0
+extern __attribute__((__visibility__("hidden"))) const char
 linux_banner[];
+
 efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
                        unsigned long orig_fdt_size,

void *fdt, int new_fdt_size, char *cmdline_ptr,
-------------------8<--------------------

Now I get a slightly different error, but it amounts to the same thing:

Quoted 3 lines

arm-linux-gnueabi-ld: cannot find arch/arm/boot/compressed/efi-banner.o: No such file or directory

Strange. So did it actually build efi-banner.o ?
Could you check if the leading tabs in the Makefile hunks got pasted ok?

Signature · 1 line
Ard.

A message that is not in the archive (sent off-list or not yet received): CAD0U-hLrY6ZoeT-p6ytmPmwxWcqw0cd3Ax-u0RbEd_Lkj_btUg@mail.gmail.com

#20 lore raw

PATCH 9/9 ARM: add UEFI stub support

Quoted 183 lines · Ryan Harkin
Quoted 179 lines · Ard Biesheuvel
Quoted 176 lines · Ryan Harkin
Quoted 64 lines · Ard Biesheuvel
Quoted 61 lines · Ard Biesheuvel
Quoted 58 lines · Ryan Harkin

Hi Ard/Roy,

Quoted 43 lines · Ard Biesheuvel

From: Roy Franz <[email protected]>

This patch adds EFI stub support for the ARM Linux kernel.

The EFI stub operates similarly to the x86 and arm64 stubs: it is a shim between the EFI firmware and the normal zImage entry point, and
sets up the environment that the zImage is expecting. This includes optionally loading the initrd and device tree from the system partition
based on the kernel command line.

---
 arch/arm/Kconfig                       |  19 +++
 arch/arm/boot/compressed/Makefile      |   5 +-
 arch/arm/boot/compressed/efi-header.S  | 130 ++++++++++++++++++++
 arch/arm/boot/compressed/efi-stub.c    |  89 ++++++++++++++
 arch/arm/boot/compressed/head.S        |  54 +++++++-
 arch/arm/boot/compressed/vmlinux.lds.S |   7 ++
 arch/arm/include/asm/efi.h             |  23 ++++
 drivers/firmware/efi/libstub/Makefile  |  12 ++
 8 files changed, 336 insertions(+), 3 deletions(-)
arch/arm/Kconfig +0 -0
index e4b7d6cfd8eb..6d7fd83c2ee4 100644
@@ -2061,6 +2061,25 @@ config AUTO_ZRELADDR
          0xf8000000. This assumes the zImage being placed in the

first
128MB
from start of memory.

arch/arm/Kconfig +6 -0
+config EFI_STUB
+       bool
+
+config EFI
+       bool "UEFI runtime support"
+       depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR &&

!XIP_KERNEL

arch/arm/Kconfig

Quoted 5 lines
arch/arm/Kconfig +5 -0
+       select UCS2_STRING
+       select EFI_PARAMS_FROM_FDT
+       select EFI_STUB
+       select EFI_ARMSTUB
+       select EFI_RUNTIME_WRAPPERS

Should we make this "default y" like ARM64? I think so.

Quoted 4 lines
Quoted 4 lines

It is not necessarily something that should be enabled by default, imo. The distro kernels will probably enabled it, which is good enough
for me.

That's fair enough. I think it is default for arm64, hence why I asked. But I can enable it myself in my own configs easily enough.

Quoted 82 lines
Quoted 39 lines
Quoted 32 lines
Quoted 22 lines
arch/arm/Kconfig +2 -0
+       ---help---
+         This option provides support for runtime services

provided
+ by UEFI firmware (such as non-volatile variables,
realtime
+ clock, and platform reset). A UEFI stub is also provided
to

arch/arm/Kconfig +2 -0
+         allow the kernel to be booted as an EFI application. This
+         is only useful for kernels that may run on systems that

have

arch/arm/Kconfig +2 -0
+         UEFI firmware.
+
 endmenu
 
 menu "CPU Power Management"
arch/arm/boot/compressed/Makefile +0 -0
index 3f9a9ebc77c3..0e5624d6215d 100644

arch/arm/boot/compressed/Makefile if [ $(words $(ZRELADDR)) -gt 1 -a · line 172

Quoted 6 lines
arch/arm/boot/compressed/Makefile +1 -0
@@ -167,9 +167,12 @@ if [ $(words $(ZRELADDR)) -gt 1 -a
 "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
        false; \
 fi
 
+efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o
 $(obj)/efi-banner.o \

When I try to compile the kernel from your branch, I get:

Quoted 6 lines

make[2]: *** No rule to make target 'arch/arm/boot/compressed/efi-banner.o', needed by 'arch/arm/boot/compressed/vmlinux'. Stop.

Did I miss something or is this a problem?

Quoted 7 lines

It was I who missed something: I have been reshuffling some bits, and this fell through the cracks. I didn't spot it since I apparently did not try to rebuild it cleanly.

I would like to get rid of the linux_banner reference in the stub completely, and I posted a patch here

Where? Here:
http://marc.info/?l=linux-arm-kernel&m=144313135923256

Quoted 32 lines

In the mean time, could you try with this folded in?

-------------------8<--------------------

arch/arm/boot/compressed/Makefile +0 -0
index 0e5624d6215d..a6aa7f9123a2 100644
@@ -170,6 +170,10 @@ fi
 efi-obj-$(CONFIG_EFI_STUB) := $(obj)/efi-stub.o $(obj)/efi-banner.o
 \
 

$(objtree)/drivers/firmware/efi/libstub/lib.a

+$(obj)/efi-banner.o: OBJCOPYFLAGS=-j .rodata +$(obj)/efi-banner.o: $(objtree)/init/version.o FORCE

arch/arm/boot/compressed/Makefile +2 -0
+       $(call if_changed,objcopy)
+
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD)
$(obj)/piggy.$(suffix_y).o \
                $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3)
\
                $(bswapsdi2) $(efi-obj-y) FORCE
drivers/firmware/efi/libstub/fdt.c +0 -0
index a7e87cd582f2..f45a6f715e73 100644
@@ -16,6 +16,8 @@
 
 #include "efistub.h"
 
Quoted 10 lines
Quoted 10 lines
drivers/firmware/efi/libstub/fdt.c +2 -0
+extern __attribute__((__visibility__("hidden"))) const char
 linux_banner[];
+
 efi_status_t update_fdt(efi_system_table_t *sys_table, void
 *orig_fdt,

unsigned long orig_fdt_size, void *fdt, int new_fdt_size, char
*cmdline_ptr, -------------------8<--------------------

Now I get a slightly different error, but it amounts to the same thing:

arm-linux-gnueabi-ld: cannot find arch/arm/boot/compressed/efi-banner.o:
No
such file or directory

Quoted 7 lines
Quoted 2 lines

Strange. So did it actually build efi-banner.o ?
Could you check if the leading tabs in the Makefile hunks got pasted ok?

Sorry about that. As you suggested, I had spaces instead of tabs in your Makefile fix.

Well, it was probably the copy/paste at my end that caused the problem in the first place.

Quoted 7 lines

I compiles just fine now.

And it also works when booting to busybox. So with your fix in place, you add a:

Thanks a lot.
Which platform did you test btw?

Signature · 1 line
Ard.
#21 lore raw

cover UEFI boot and runtime services support for 32-bit ARM

In reply to Ard Biesheuvel
Quoted 3 lines · Ard Biesheuvel

There are a number of prerequisites for this series that have all been sent to the linux-arm-kernel mailing list at some point (and mostly ignored).

They've been ignored because they're UEFI and no one's said that it's something that 32-bit ARM should get... until this series has come along. It might help if Linaro was more engaging with developers who aren't part of Linaro.

Now, I'm not going to suddenly drop what I'm working on to start trying to gain an understanding of UEFI, and what its implications are for 32-bit ARM so that I can reasonably review these patches - let me put that another way: don't expect me to review this stuff quickly and come out with review comments on something I have very ltitle clue about. I have precisely zero UEFI knowledge.

Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
#22 lore raw

cover UEFI boot and runtime services support for 32-bit ARM

Quoted 10 lines · Russell King - ARM Linux
Quoted 3 lines · Ard Biesheuvel

There are a number of prerequisites for this series that have all been sent to the linux-arm-kernel mailing list at some point (and mostly ignored).

They've been ignored because they're UEFI and no one's said that it's something that 32-bit ARM should get... until this series has come along. It might help if Linaro was more engaging with developers who aren't part of Linaro.

Actually, the first iteration of this series was sent out by Roy more than two years ago.
But I am fully aware that these patches and the prerequisite series (plural) still need thorough review, I am just throwing this series out there early since it ties all of that together, so it puts the other stuff into context.

Quoted 7 lines

Now, I'm not going to suddenly drop what I'm working on to start trying to gain an understanding of UEFI, and what its implications are for 32-bit ARM so that I can reasonably review these patches - let me put that another way: don't expect me to review this stuff quickly and come out with review comments on something I have very ltitle clue about. I have precisely zero UEFI knowledge.

I think the UEFI peculiarities are mostly covered by the common code shared with x86 and arm64. What I would appreciate your input on is the ARM specific thinks like early .data in the decompressor (even before the GOT fixups), the early_ioremap addition and the changes to create_mapping(). But no rush at all.

Thanks,
Ard.