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.prak...@intel.com>
Suggested-by: Ard Biesheuvel <ard.biesheu...@linaro.org>
Cc: Ingo Molnar <mi...@kernel.org>
Cc: Borislav Petkov <b...@alien8.de>
Cc: Bhupesh Sharma <bhsha...@redhat.com>
Cc: Ard Biesheuvel <ard.biesheu...@linaro.org>
---
 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

Reply via email to