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

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
...@@ -2,7 +2,9 @@ ...@@ -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); ...@@ -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); ...@@ -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);
......
...@@ -17,6 +17,29 @@ ...@@ -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)
{ {
/* /*
......
...@@ -57,7 +57,7 @@ static int __init uefi_init(void) ...@@ -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,7 +69,8 @@ static int __init uefi_init(void) ...@@ -69,7 +69,8 @@ static int __init uefi_init(void)
} }
set_bit(EFI_BOOT, &efi.flags); 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 * Verify the EFI Table
...@@ -107,7 +108,7 @@ static int __init uefi_init(void) ...@@ -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:
......
...@@ -12,6 +12,7 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
{ {
......
...@@ -25,6 +25,8 @@ ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment