| From 785107923a83d8456bbd8564e288a24d84109a46 Mon Sep 17 00:00:00 2001 |
| From: Josh Triplett <josh@joshtriplett.org> |
| Date: Fri, 28 Sep 2012 17:55:44 -0700 |
| Subject: efi: Defer freeing boot services memory until after ACPI init |
| |
| From: Josh Triplett <josh@joshtriplett.org> |
| |
| commit 785107923a83d8456bbd8564e288a24d84109a46 upstream. |
| |
| Some new ACPI 5.0 tables reference resources stored in boot services |
| memory, so keep that memory around until we have ACPI and can extract |
| data from it. |
| |
| Signed-off-by: Josh Triplett <josh@joshtriplett.org> |
| Link: http://lkml.kernel.org/r/baaa6d44bdc4eb0c58e5d1b4ccd2c729f854ac55.1348876882.git.josh@joshtriplett.org |
| Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> |
| Cc: Matt Fleming <matt@console-pimps.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/platform/efi/efi.c | 31 ++++++++++++++++++------------- |
| include/linux/efi.h | 5 +++++ |
| init/main.c | 3 +++ |
| 3 files changed, 26 insertions(+), 13 deletions(-) |
| |
| --- a/arch/x86/platform/efi/efi.c |
| +++ b/arch/x86/platform/efi/efi.c |
| @@ -419,10 +419,21 @@ void __init efi_reserve_boot_services(vo |
| } |
| } |
| |
| -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 +449,8 @@ static void __init efi_free_boot_service |
| |
| free_bootmem_late(start, size); |
| } |
| + |
| + efi_unmap_memmap(); |
| } |
| |
| static int __init efi_systab_init(void *phys) |
| @@ -787,8 +800,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,13 +893,6 @@ 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. |
| * |
| @@ -907,9 +915,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); |
| } |
| |
| --- a/include/linux/efi.h |
| +++ b/include/linux/efi.h |
| @@ -496,6 +496,11 @@ extern void efi_map_pal_code (void); |
| extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); |
| extern void efi_gettimeofday (struct timespec *ts); |
| extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ |
| +#ifdef CONFIG_X86 |
| +extern void efi_free_boot_services(void); |
| +#else |
| +static inline void efi_free_boot_services(void) {} |
| +#endif |
| extern u64 efi_get_iobase (void); |
| extern u32 efi_mem_type (unsigned long phys_addr); |
| extern u64 efi_mem_attributes (unsigned long phys_addr); |
| --- a/init/main.c |
| +++ b/init/main.c |
| @@ -631,6 +631,9 @@ asmlinkage void __init start_kernel(void |
| acpi_early_init(); /* before LAPIC and SMP init */ |
| sfi_init_late(); |
| |
| + if (efi_enabled) |
| + efi_free_boot_services(); |
| + |
| ftrace_init(); |
| |
| /* Do the rest non-__init'ed, we're now alive */ |