[PATCH 5/5] kexec: X86: Pass memory ranges via e820 table instead of memmap= boot parameter

Thomas Renninger trenn at suse.de
Thu Apr 11 08:26:47 EDT 2013


Currently ranges are passed via kernel boot parameters:
memmap=exactmap memmap=X#Y memmap=

Pass them via e820 table directly instead.

CC: Simon Horman <horms at verge.net.au>
CC: kexec at lists.infradead.org
CC: H. Peter Anvin <hpa at zytor.com>
CC: Eric W. Biederman <ebiederm at xmission.com>
CC: vgoyal at redhat.com
CC: yinghai at kernel.org
CC: cpw at sgi.com

Signed-off-by: Thomas Renninger <trenn at suse.de>
Signed-off-by: Thomas Renninger <Thomas Renninger" trenn at suse.de>
---
 kexec/arch/i386/crashdump-x86.c   |  221 ++++++++++++++++++-------------------
 kexec/arch/i386/x86-linux-setup.c |   11 ++-
 2 files changed, 116 insertions(+), 116 deletions(-)

diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c
index f7821bc..8009efe 100644
--- a/kexec/arch/i386/crashdump-x86.c
+++ b/kexec/arch/i386/crashdump-x86.c
@@ -659,70 +659,6 @@ static void ultoa(unsigned long i, char *str)
 	}
 }
 
-static void cmdline_add_memmap_internal(char *cmdline, unsigned long startk,
-					unsigned long endk, int type)
-{
-	int cmdlen, len;
-	char str_mmap[256], str_tmp[20];
-
-	strcpy (str_mmap, " memmap=");
-	ultoa((endk-startk), str_tmp);
-	strcat (str_mmap, str_tmp);
-
-	if (type == RANGE_RAM)
-		strcat (str_mmap, "K@");
-	else if (type == RANGE_RESERVED)
-		strcat (str_mmap, "K$");
-	else if (type == RANGE_ACPI || type == RANGE_ACPI_NVS)
-		strcat (str_mmap, "K#");
-
-	ultoa(startk, str_tmp);
-	strcat (str_mmap, str_tmp);
-	strcat (str_mmap, "K");
-	len = strlen(str_mmap);
-	cmdlen = strlen(cmdline) + len;
-	if (cmdlen > (COMMAND_LINE_SIZE - 1))
-		die("Command line overflow\n");
-	strcat(cmdline, str_mmap);
-}
-
-/* Adds the appropriate memmap= options to command line, indicating the
- * memory regions the new kernel can use to boot into. */
-static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p)
-{
-	int i, cmdlen, len;
-	unsigned long min_sizek = 100;
-	char str_mmap[256];
-
-	/* Exact map */
-	strcpy(str_mmap, " memmap=exactmap");
-	len = strlen(str_mmap);
-	cmdlen = strlen(cmdline) + len;
-	if (cmdlen > (COMMAND_LINE_SIZE - 1))
-		die("Command line overflow\n");
-	strcat(cmdline, str_mmap);
-
-	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
-		unsigned long startk, endk;
-		startk = (memmap_p[i].start/1024);
-		endk = ((memmap_p[i].end + 1)/1024);
-		if (!startk && !endk)
-			/* All regions traversed. */
-			break;
-
-		/* A region is not worth adding if region size < 100K. It eats
-		 * up precious command line length. */
-		if ((endk - startk) < min_sizek)
-			continue;
-		cmdline_add_memmap_internal(cmdline, startk, endk, RANGE_RAM);
-	}
-
-	dbgprintf("Command line after adding memmap\n");
-	dbgprintf("%s\n", cmdline);
-
-	return 0;
-}
-
 /* Adds the elfcorehdr= command line parameter to command line. */
 static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr)
 {
@@ -803,26 +739,6 @@ static enum coretype get_core_type(struct crash_elf_info *elf_info,
 	}
 }
 
-/* Appends memmap=X#Y commandline for ACPI to command line*/
-static int cmdline_add_memmap_acpi(char *cmdline, unsigned long start,
-					unsigned long end)
-{
-	int align = 1024;
-	unsigned long startk, endk;
-
-	if (!(end - start))
-		return 0;
-
-	startk = start/1024;
-	endk = (end + align - 1)/1024;
-	cmdline_add_memmap_internal(cmdline, startk, endk, RANGE_ACPI);
-
-	dbgprintf("Command line after adding acpi memmap\n");
-	dbgprintf("%s\n", cmdline);
-
-	return 0;
-}
-
 /* Appends 'acpi_rsdp=' commandline for efi boot crash dump */
 static void cmdline_add_efi(char *cmdline)
 {
@@ -881,24 +797,101 @@ static void get_backup_area(struct kexec_info *info,
 	info->backup_src_size = BACKUP_SRC_END - BACKUP_SRC_START + 1;
 }
 
-/* Appends memmap=X$Y commandline for reserved memory to command line*/
-static int cmdline_add_memmap_reserved(char *cmdline, unsigned long start,
-					unsigned long end)
+/*
+ * This function takes reserved (all kind of) memory from global
+ * crash_memory_range[] memory ranges and takes memory the kdump/crash
+ * kernel is allowed to use from the passed usable_mem memory ranges. 
+ * The passed usable_mem ranges are zero (!start && !end) terminated.
+ *
+ * The final memory map is again written into crash_memory_range[]
+ * and intended to get passed as e820 table to the crash kernel
+ */
+static int create_final_crash_map(struct memory_range *usable_mem)
 {
-	int align = 1024;
-	unsigned long startk, endk;
+	int i, m, c, tmp_map1_ranges, tmp_map2_ranges;
+	unsigned long min_sizek = 100;
+	/* crash_memory_map with usable memory ranges cut out */
+	struct memory_range tmp_map1[MAX_MEMORY_RANGES];
+	/* merge_map, but small ranges cut out */
+	struct memory_range tmp_map2[MAX_MEMORY_RANGES];
 
-	if (!(end - start))
-		return 0;
+	/*
+	 * Ignore usable memory ranges for kdump kernel smaller
+	 * than 100k to avoid too much ranges passed
+	 * Save the new ranges (exluding lower than 100k ranges) in tmp_map
+	 * and store the number of elements in tmp_map_ranges
+	 */
+	for (m = 0, i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+		unsigned long startk, endk;
+		startk = (usable_mem[i].start/1024);
+		endk = ((usable_mem[i].end + 1)/1024);
+		if (!startk && !endk)
+			/* All regions traversed. */
+			break;
+
+		/* A region is not worth adding if region size < 100K. It eats
+		 * up precious command line length. */
+		if ((endk - startk) < min_sizek) {
+			dbgprintf("Removing: %luk - %luk\n", startk, endk);
+			continue;
+		} else {
+			tmp_map1[m].start = usable_mem[i].start;
+			tmp_map1[m].end   = usable_mem[i].end;
+			tmp_map1[m].type = usable_mem[i].type;
+			m++;
+		}
+	}
+	/* No need to check for !start && !end anymore */
+	tmp_map1_ranges = m;
 
-	startk = start/1024;
-	endk = (end + align - 1)/1024;
-	cmdline_add_memmap_internal(cmdline, startk, endk, RANGE_RESERVED);
+	for(i = 0; i < tmp_map1_ranges; ++i)
+		dbgprintf("%016Lx-%016Lx (%d)\n", tmp_map1[i].start,
+			  tmp_map1[i].end, tmp_map1[i].type);
+
+	/*
+	 * Cut out RANGE_RAM regions from crash_memory_ranges and store
+	 * them in tmp_map2_ranges
+	 */
+	for (c = 0, i = 0; i < crash_ranges; i++) {
+		if (crash_memory_range[i].type == RANGE_RAM)
+			continue;
+		tmp_map2[c].start = crash_memory_range[i].start;
+		tmp_map2[c].end = crash_memory_range[i].end;
+		tmp_map2[c].type = crash_memory_range[i].type;
+		c++;
+	}
+	tmp_map2_ranges = c;
+
+	/*
+	 * TBD: Check that no ranges overlap?
+	 * Can this happen at all?
+	 */
+	for (c = 0, m = 0, i = 0; i < MAX_MEMORY_RANGES; i++) {
+		if (m < tmp_map1_ranges &&
+		    (c >= tmp_map2_ranges ||
+		     tmp_map2[c].start > tmp_map1[m].start)) {
+			crash_memory_range[i].start = tmp_map1[m].start;
+			crash_memory_range[i].end   = tmp_map1[m].end;
+			crash_memory_range[i].type  = RANGE_RAM;
+			m++;
+			continue;
+		} else if (c < tmp_map2_ranges) {
+			crash_memory_range[i] = tmp_map2[c];
+			c++;
+			continue;
+		} else
+			break;
+	}
+	crash_ranges = i;
+
+	/*
+	 * End address has to be exlusive for e820 map
+	 * x        - 00010000
+	 * 00010000 - y
+	 */
+	for(i = 0; i < crash_ranges; ++i)
+		crash_memory_range[i].end++;
 
-#ifdef DEBUG
-		printf("Command line after adding reserved memmap\n");
-		printf("%s\n", cmdline);
-#endif
 	return 0;
 }
 
@@ -944,6 +937,12 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 		return -1;
 	}
 
+	/*
+	 * From now on the memory regions are stored in crash_memory_range[]
+	 * Currently the end address is inclusive at this point:
+	 * x        - 0000ffff
+	 * 00010000 - y
+	 */
 	if (xen_present()) {
 		if (get_crash_memory_ranges_xen(&mem_range, &crash_ranges,
 						elf_info.lowmem_limit) < 0)
@@ -971,7 +970,7 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 
 	get_backup_area(info, mem_range, crash_ranges);
 
-	dbgprintf("CRASH MEMORY RANGES\n");
+	dbgprintf("TEMPORARY CRASH MEMORY RANGES\n");
 
 	for(i = 0; i < crash_ranges; ++i)
 		dbgprintf("%016Lx-%016Lx (%d)\n", mem_range[i].start,
@@ -1063,24 +1062,18 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
 	dbgprintf("Created elf header segment at 0x%lx\n", elfcorehdr);
 	if (delete_memmap(memmap_p, elfcorehdr, memsz) < 0)
 		return -1;
-	cmdline_add_memmap(mod_cmdline, memmap_p);
 	cmdline_add_efi(mod_cmdline);
 	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
 
-	/* Inform second kernel about the presence of ACPI tables. */
-	for (i = 0; i < MAX_MEMORY_RANGES; i++) {
-		unsigned long start, end;
-		if ( !( mem_range[i].type == RANGE_ACPI
-			|| mem_range[i].type == RANGE_ACPI_NVS
-			|| mem_range[i].type == RANGE_RESERVED) )
-			continue;
-		start = mem_range[i].start;
-		end = mem_range[i].end;
-		if (mem_range[i].type == RANGE_RESERVED)
-			cmdline_add_memmap_reserved(mod_cmdline, start, end);
-		else
-			cmdline_add_memmap_acpi(mod_cmdline, start, end);
-	}
+	/*
+	 * Redo crash_memory_range so that it can get passed as e820 info
+	 */
+	create_final_crash_map(memmap_p);
+
+	dbgprintf("FINAL CRASH MEMORY RANGES\n");
+	for(i = 0; i < crash_ranges; ++i)
+		dbgprintf("%016Lx-%016Lx (%d)\n", mem_range[i].start,
+			  mem_range[i].end, mem_range[i].type);
 	return 0;
 }
 
diff --git a/kexec/arch/i386/x86-linux-setup.c b/kexec/arch/i386/x86-linux-setup.c
index c538897..82b4bb9 100644
--- a/kexec/arch/i386/x86-linux-setup.c
+++ b/kexec/arch/i386/x86-linux-setup.c
@@ -505,8 +505,15 @@ void setup_linux_system_parameters(struct kexec_info *info,
 	/* another safe default */
 	real_mode->aux_device_info = 0;
 
-	range = info->memory_range;
-	ranges = info->memory_ranges;
+	if (info->kexec_flags & KEXEC_ON_CRASH || 
+	    info->kexec_flags & KEXEC_PRESERVE_CONTEXT) {
+		range = crash_memory_range;
+		ranges = crash_ranges;
+	} else {
+		range = info->memory_range;
+		ranges = info->memory_ranges;
+	}
+
 	if (ranges > E820MAX) {
 		if (!(info->kexec_flags & KEXEC_ON_CRASH))
 			/*
-- 
1.7.6.1




More information about the kexec mailing list