efi_map_regions() uses realloc_pages() to allocate memory for runtime EFI memory map (EFI memory map which contains only memory descriptors of type Runtime Code/Data and Boot Code/Data). Since efi_memmap_alloc() also does the same, use it instead of realloc_pages() and install the new EFI memory map using efi_memmap_install() instead of efi_memmap_init_late(). This also fixes the leaking of existing EFI memory map. Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@xxxxxxxxx> Suggested-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx> Cc: Ingo Molnar <mingo@xxxxxxxxxx> Cc: Borislav Petkov <bp@xxxxxxxxx> Cc: Bhupesh Sharma <bhsharma@xxxxxxxxxx> Cc: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx> --- arch/x86/include/asm/efi.h | 2 +- arch/x86/platform/efi/efi.c | 93 +++++++++------------------------- arch/x86/platform/efi/efi_32.c | 2 +- arch/x86/platform/efi/efi_64.c | 7 ++- 4 files changed, 33 insertions(+), 71 deletions(-) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 744f945a00e7..524fda68b03f 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -131,7 +131,7 @@ extern void __init efi_map_region(efi_memory_desc_t *md); extern void __init efi_map_region_fixed(efi_memory_desc_t *md); extern void efi_sync_low_kernel_mappings(void); extern int __init efi_alloc_page_tables(void); -extern int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages); +extern int __init efi_setup_page_tables(void); extern void __init old_map_region(efi_memory_desc_t *md); extern void __init runtime_code_page_mkexec(void); extern void __init efi_runtime_update_mappings(void); diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 63885cc8e34e..1b0a9449096b 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -656,27 +656,6 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md) } } -static void *realloc_pages(void *old_memmap, int old_shift) -{ - void *ret; - - ret = (void *)__get_free_pages(GFP_KERNEL, old_shift + 1); - if (!ret) - goto out; - - /* - * A first-time allocation doesn't have anything to copy. - */ - if (!old_memmap) - return ret; - - memcpy(ret, old_memmap, PAGE_SIZE << old_shift); - -out: - free_pages((unsigned long)old_memmap, old_shift); - return ret; -} - /* * Iterate the EFI memory map in reverse order because the regions * will be mapped top-down. The end result is the same as if we had @@ -782,18 +761,15 @@ static bool should_map_region(efi_memory_desc_t *md) } /* - * Map the efi memory ranges of the runtime services and update new_mmap with - * virtual addresses. + * Map the efi memory ranges of the runtime services and update memory map with + * virtual addresses. Returns number of memory map entries mapped. */ -static void * __init efi_map_regions(int *count, int *pg_shift) +static int __init efi_map_regions(void) { - void *p, *new_memmap = NULL; - unsigned long left = 0; - unsigned long desc_size; + void *p; + int count = 0; efi_memory_desc_t *md; - desc_size = efi.memmap.desc_size; - p = NULL; while ((p = efi_map_next_entry(p))) { md = p; @@ -803,30 +779,15 @@ static void * __init efi_map_regions(int *count, int *pg_shift) efi_map_region(md); get_systab_virt_addr(md); - - if (left < desc_size) { - new_memmap = realloc_pages(new_memmap, *pg_shift); - if (!new_memmap) - return NULL; - - left += PAGE_SIZE << *pg_shift; - (*pg_shift)++; - } - - memcpy(new_memmap + (*count * desc_size), md, desc_size); - - left -= desc_size; - (*count)++; + count++; } - - return new_memmap; + return count; } static void __init kexec_enter_virtual_mode(void) { #ifdef CONFIG_KEXEC_CORE efi_memory_desc_t *md; - unsigned int num_pages; efi.systab = NULL; @@ -872,10 +833,7 @@ static void __init kexec_enter_virtual_mode(void) BUG_ON(!efi.systab); - num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE); - num_pages >>= PAGE_SHIFT; - - if (efi_setup_page_tables(efi.memmap.phys_map, num_pages)) { + if (efi_setup_page_tables()) { clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); return; } @@ -926,10 +884,12 @@ static void __init kexec_enter_virtual_mode(void) */ static void __init __efi_enter_virtual_mode(void) { - int count = 0, pg_shift = 0; - void *new_memmap = NULL; + struct efi_memory_map new_memmap; + efi_memory_desc_t *md; + int count = 0; efi_status_t status; unsigned long pa; + void *out; efi.systab = NULL; @@ -940,28 +900,25 @@ static void __init __efi_enter_virtual_mode(void) } efi_merge_regions(); - new_memmap = efi_map_regions(&count, &pg_shift); - if (!new_memmap) { + count = efi_map_regions(); + + if (efi_memmap_alloc(&new_memmap, count)) { pr_err("Error reallocating memory, EFI runtime non-functional!\n"); clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); return; } - pa = __pa(new_memmap); - - /* - * Unregister the early EFI memmap from efi_init() and install - * the new EFI memory map that we are about to pass to the - * firmware via SetVirtualAddressMap(). - */ - efi_memmap_unmap(); - - if (efi_memmap_init_late(pa, efi.memmap.desc_size * count)) { - pr_err("Failed to remap late EFI memory map\n"); - clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); - return; + out = new_memmap.map; + for_each_efi_memory_desc(md) { + if (!should_map_region(md)) + continue; + memcpy(out, md, efi.memmap.desc_size); + out += efi.memmap.desc_size; } + efi_memmap_install(new_memmap); + pa = new_memmap.phys_map; + if (efi_enabled(EFI_DBG)) { pr_info("EFI runtime memory map:\n"); efi_print_memmap(); @@ -969,7 +926,7 @@ static void __init __efi_enter_virtual_mode(void) BUG_ON(!efi.systab); - if (efi_setup_page_tables(pa, 1 << pg_shift)) { + if (efi_setup_page_tables()) { clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); return; } diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c index 9959657127f4..b058d6e710b9 100644 --- a/arch/x86/platform/efi/efi_32.c +++ b/arch/x86/platform/efi/efi_32.c @@ -53,7 +53,7 @@ void __init efi_dump_pagetable(void) #endif } -int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) +int __init efi_setup_page_tables(void) { return 0; } diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index cf0347f61b21..dcf52d005fd7 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -336,12 +336,17 @@ virt_to_phys_or_null_size(void *va, unsigned long size) #define virt_to_phys_or_null(addr) \ virt_to_phys_or_null_size((addr), sizeof(*(addr))) -int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) +int __init efi_setup_page_tables(void) { unsigned long pfn, text, pf; struct page *page; unsigned npages; pgd_t *pgd = efi_mm.pgd; + unsigned long pa_memmap = efi.memmap.phys_map; + unsigned int num_pages; + + num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE); + num_pages >>= PAGE_SHIFT; if (efi_enabled(EFI_OLD_MEMMAP)) return 0; -- 2.19.1