diff options
Diffstat (limited to 'arch/x86/platform/efi/efi.c')
| -rw-r--r-- | arch/x86/platform/efi/efi.c | 66 | 
1 files changed, 53 insertions, 13 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 92660edaa1e..aded2a91162 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -31,6 +31,7 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/efi.h> +#include <linux/efi-bgrt.h>  #include <linux/export.h>  #include <linux/bootmem.h>  #include <linux/memblock.h> @@ -419,10 +420,21 @@ void __init efi_reserve_boot_services(void)  	}  } -static void __init efi_free_boot_services(void) +static void __init efi_unmap_memmap(void) +{ +	if (memmap.map) { +		early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); +		memmap.map = NULL; +	} +} + +void __init efi_free_boot_services(void)  {  	void *p; +	if (!efi_native) +		return; +  	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {  		efi_memory_desc_t *md = p;  		unsigned long long start = md->phys_addr; @@ -438,6 +450,8 @@ static void __init efi_free_boot_services(void)  		free_bootmem_late(start, size);  	} + +	efi_unmap_memmap();  }  static int __init efi_systab_init(void *phys) @@ -732,6 +746,11 @@ void __init efi_init(void)  #endif  } +void __init efi_late_init(void) +{ +	efi_bgrt_init(); +} +  void __init efi_set_executable(efi_memory_desc_t *md, bool executable)  {  	u64 addr, npages; @@ -764,6 +783,34 @@ static void __init runtime_code_page_mkexec(void)  }  /* + * We can't ioremap data in EFI boot services RAM, because we've already mapped + * it as RAM.  So, look it up in the existing EFI memory map instead.  Only + * callable after efi_enter_virtual_mode and before efi_free_boot_services. + */ +void __iomem *efi_lookup_mapped_addr(u64 phys_addr) +{ +	void *p; +	if (WARN_ON(!memmap.map)) +		return NULL; +	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { +		efi_memory_desc_t *md = p; +		u64 size = md->num_pages << EFI_PAGE_SHIFT; +		u64 end = md->phys_addr + size; +		if (!(md->attribute & EFI_MEMORY_RUNTIME) && +		    md->type != EFI_BOOT_SERVICES_CODE && +		    md->type != EFI_BOOT_SERVICES_DATA) +			continue; +		if (!md->virt_addr) +			continue; +		if (phys_addr >= md->phys_addr && phys_addr < end) { +			phys_addr += md->virt_addr - md->phys_addr; +			return (__force void __iomem *)(unsigned long)phys_addr; +		} +	} +	return NULL; +} + +/*   * This function will switch the EFI runtime services to virtual mode.   * Essentially, look through the EFI memmap and map every region that   * has the runtime attribute bit set in its memory descriptor and update @@ -787,8 +834,10 @@ void __init efi_enter_virtual_mode(void)  	 * non-native EFI  	 */ -	if (!efi_native) -		goto out; +	if (!efi_native) { +		efi_unmap_memmap(); +		return; +	}  	/* Merge contiguous regions of the same type and attribute */  	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { @@ -878,18 +927,12 @@ void __init efi_enter_virtual_mode(void)  	}  	/* -	 * Thankfully, it does seem that no runtime services other than -	 * SetVirtualAddressMap() will touch boot services code, so we can -	 * get rid of it all at this point -	 */ -	efi_free_boot_services(); - -	/*  	 * Now that EFI is in virtual mode, update the function  	 * pointers in the runtime service table to the new virtual addresses.  	 *  	 * Call EFI services through wrapper functions.  	 */ +	efi.runtime_version = efi_systab.fw_revision;  	efi.get_time = virt_efi_get_time;  	efi.set_time = virt_efi_set_time;  	efi.get_wakeup_time = virt_efi_get_wakeup_time; @@ -906,9 +949,6 @@ void __init efi_enter_virtual_mode(void)  	if (__supported_pte_mask & _PAGE_NX)  		runtime_code_page_mkexec(); -out: -	early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); -	memmap.map = NULL;  	kfree(new_memmap);  }  |