[PATCH V2 3/3] x86/efi: Use efi_memmap_<alloc/install>() to create runtime EFI memory map

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux