forked from mirrors/linux
		
	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: Matt Fleming <matt@codeblueprint.co.uk> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
		
							parent
							
								
									e5bc22a42e
								
							
						
					
					
						commit
						f7d9248942
					
				
					 5 changed files with 54 additions and 35 deletions
				
			
		| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	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)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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)
 | 
				
			||||||
		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 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue