Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7d92489 authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Will Deacon
Browse files

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



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

Reviewed-by: default avatarMatt Fleming <matt@codeblueprint.co.uk>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent e5bc22a4
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -2,7 +2,9 @@
#define _ASM_EFI_H
#define _ASM_EFI_H


#include <asm/io.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/neon.h>
#include <asm/neon.h>
#include <asm/tlbflush.h>


#ifdef CONFIG_EFI
#ifdef CONFIG_EFI
extern void efi_init(void);
extern void efi_init(void);
@@ -10,6 +12,8 @@ extern void efi_init(void);
#define efi_init()
#define efi_init()
#endif
#endif


int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);

#define efi_call_virt(f, ...)						\
#define efi_call_virt(f, ...)						\
({									\
({									\
	efi_##f##_t *__f;						\
	efi_##f##_t *__f;						\
@@ -63,6 +67,11 @@ extern void efi_init(void);
 *   Services are enabled and the EFI_RUNTIME_SERVICES bit set.
 *   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_load(void);
void efi_virtmap_unload(void);
void efi_virtmap_unload(void);


+23 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,29 @@


#include <asm/efi.h>
#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)
static int __init arm64_dmi_init(void)
{
{
	/*
	/*
+4 −3
Original line number Original line Diff line number Diff line
@@ -57,7 +57,7 @@ static int __init uefi_init(void)
{
{
	efi_char16_t *c16;
	efi_char16_t *c16;
	void *config_tables;
	void *config_tables;
	u64 table_size;
	size_t table_size;
	char vendor[100] = "unknown";
	char vendor[100] = "unknown";
	int i, retval;
	int i, retval;


@@ -69,6 +69,7 @@ static int __init uefi_init(void)
	}
	}


	set_bit(EFI_BOOT, &efi.flags);
	set_bit(EFI_BOOT, &efi.flags);
	if (IS_ENABLED(CONFIG_64BIT))
		set_bit(EFI_64BIT, &efi.flags);
		set_bit(EFI_64BIT, &efi.flags);


	/*
	/*
@@ -107,7 +108,7 @@ static int __init uefi_init(void)
		goto out;
		goto out;
	}
	}
	retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
	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);
	early_memunmap(config_tables, table_size);
out:
out:
+16 −32
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@
 */
 */


#include <linux/efi.h>
#include <linux/efi.h>
#include <linux/io.h>
#include <linux/memblock.h>
#include <linux/memblock.h>
#include <linux/mm_types.h>
#include <linux/mm_types.h>
#include <linux/preempt.h>
#include <linux/preempt.h>
@@ -23,18 +24,14 @@


#include <asm/cacheflush.h>
#include <asm/cacheflush.h>
#include <asm/efi.h>
#include <asm/efi.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
#include <asm/mmu.h>
#include <asm/mmu.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/pgtable.h>


static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;

extern u64 efi_system_table;
extern u64 efi_system_table;


static struct mm_struct efi_mm = {
static struct mm_struct efi_mm = {
	.mm_rb			= RB_ROOT,
	.mm_rb			= RB_ROOT,
	.pgd			= efi_pgd,
	.mm_users		= ATOMIC_INIT(2),
	.mm_users		= ATOMIC_INIT(2),
	.mm_count		= ATOMIC_INIT(1),
	.mm_count		= ATOMIC_INIT(1),
	.mmap_sem		= __RWSEM_INITIALIZER(efi_mm.mmap_sem),
	.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_memory_desc_t *md;


	efi_mm.pgd = pgd_alloc(&efi_mm);
	init_new_context(NULL, &efi_mm);
	init_new_context(NULL, &efi_mm);


	for_each_efi_memory_desc(&memmap, md) {
	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))
		if (!(md->attribute & EFI_MEMORY_RUNTIME))
			continue;
			continue;
		if (md->virt_addr == 0)
		if (md->virt_addr == 0)
			return false;
			return false;


		pr_info("  EFI remap 0x%016llx => %p\n",
		ret = efi_create_mapping(&efi_mm, md);
			md->phys_addr, (void *)md->virt_addr);
		if  (!ret) {

			pr_info("  EFI remap %pa => %p\n",
		/*
				&phys, (void *)(unsigned long)md->virt_addr);
		 * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
		} else {
		 * executable, everything else can be mapped with the XN bits
			pr_warn("  EFI remap %pa: failed to create mapping (%d)\n",
		 * set.
				&phys, ret);
		 */
			return false;
		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));
	}
	}
	return true;
	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
 * non-early mapping of the UEFI system table and virtual mappings for all
 * EFI_MEMORY_RUNTIME regions.
 * EFI_MEMORY_RUNTIME regions.
 */
 */
static int __init arm64_enable_runtime_services(void)
static int __init arm_enable_runtime_services(void)
{
{
	u64 mapsize;
	u64 mapsize;


@@ -131,12 +120,7 @@ static int __init arm64_enable_runtime_services(void)


	return 0;
	return 0;
}
}
early_initcall(arm64_enable_runtime_services);
early_initcall(arm_enable_runtime_services);

static void efi_set_pgd(struct mm_struct *mm)
{
	switch_mm(NULL, mm, NULL);
}


void efi_virtmap_load(void)
void efi_virtmap_load(void)
{
{
+2 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,8 @@
#include <linux/io.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>


#include <asm/efi.h>

struct efi __read_mostly efi = {
struct efi __read_mostly efi = {
	.mps			= EFI_INVALID_TABLE_ADDR,
	.mps			= EFI_INVALID_TABLE_ADDR,
	.acpi			= EFI_INVALID_TABLE_ADDR,
	.acpi			= EFI_INVALID_TABLE_ADDR,