Kexec Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Use /sys/firmware/memmap in kexec
@ 2008-07-06 23:06 Bernhard Walle
  2008-07-06 23:06 ` [PATCH 1/5] Remove trailing whitespace Bernhard Walle
                   ` (4 more replies)
  0 siblings, 5 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-06 23:06 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle, vgoyal

Now as /sys/firmware/memmap is mainline in git, we can use it for kexec.
Please review and give feedback.

Signed-off-by: Bernhard Walle <bwalle@suse.de>



_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/5] Remove trailing whitespace
  2008-07-06 23:06 Use /sys/firmware/memmap in kexec Bernhard Walle
@ 2008-07-06 23:06 ` Bernhard Walle
  2008-07-07  7:02   ` Simon Horman
  2008-07-06 23:06 ` [PATCH 2/5] Fix compiler warning in kexec-x86.c Bernhard Walle
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: Bernhard Walle @ 2008-07-06 23:06 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle, Bernhard Walle, vgoyal

From: Bernhard Walle <bernhard.walle@gmx.de>

This patch just removes trailing whitespace from kexec/arch/i386/kexec-x86.c
before modifying something.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
Signed-off-by: Bernhard Walle <bernhard.walle@gmx.de>
---
 kexec/arch/i386/kexec-x86.c      |   28 ++++++++++++++--------------
 kexec/arch/x86_64/kexec-x86_64.c |   26 +++++++++++++-------------
 2 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 89ccb0b..31e4752 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -44,7 +44,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 	FILE *fp;
 	fp = fopen(iomem, "r");
 	if (!fp) {
-		fprintf(stderr, "Cannot open %s: %s\n", 
+		fprintf(stderr, "Cannot open %s: %s\n",
 			iomem, strerror(errno));
 		return -1;
 	}
@@ -58,7 +58,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 			break;
 		count = sscanf(line, "%Lx-%Lx : %n",
 			&start, &end, &consumed);
-		if (count != 2) 
+		if (count != 2)
 			continue;
 		str = line + consumed;
 		end = end + 1;
@@ -68,7 +68,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 #endif
 		if (memcmp(str, "System RAM\n", 11) == 0) {
 			type = RANGE_RAM;
-		} 
+		}
 		else if (memcmp(str, "reserved\n", 9) == 0) {
 			type = RANGE_RESERVED;
 		}
@@ -115,7 +115,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 }
 
 struct file_type file_type[] = {
-	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load, 
+	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
 	{ "elf-x86", elf_x86_probe, elf_x86_load, elf_x86_usage },
 	{ "bzImage", bzImage_probe, bzImage_load, bzImage_usage },
@@ -187,24 +187,24 @@ int arch_process_options(int argc, char **argv)
 				}
 			}
 			if (value >= 65536) {
-				fprintf(stderr, "Bad serial port base '%s'\n", 
+				fprintf(stderr, "Bad serial port base '%s'\n",
 					optarg);
 				usage();
 				return -1;
-				
+
 			}
 			arch_options.serial_base = value;
 			break;
 		case OPT_SERIAL_BAUD:
 			value = strtoul(optarg, &end, 0);
-			if ((value > 115200) || ((115200 %value) != 0) || 
-				(value < 9600) || (*end)) 
+			if ((value > 115200) || ((115200 %value) != 0) ||
+				(value < 9600) || (*end))
 			{
 				fprintf(stderr, "Bad serial port baud rate '%s'\n",
 					optarg);
 				usage();
 				return -1;
-				
+
 			}
 			arch_options.serial_baud = value;
 			break;
@@ -239,13 +239,13 @@ int arch_compat_trampoline(struct kexec_info *info)
 	if ((info->kexec_flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_X86_64)
 	{
 		if (!info->rhdr.e_shdr) {
-			fprintf(stderr, 
+			fprintf(stderr,
 				"A trampoline is required for cross architecture support\n");
 			return -1;
 		}
 		elf_rel_set_symbol(&info->rhdr, "compat_x86_64_entry32",
 			&info->entry, sizeof(info->entry));
-		
+
 		info->entry = (void *)elf_rel_get_addr(&info->rhdr, "compat_x86_64");
 	}
 	return 0;
@@ -259,11 +259,11 @@ void arch_update_purgatory(struct kexec_info *info)
 		&arch_options.reset_vga, sizeof(arch_options.reset_vga));
 	elf_rel_set_symbol(&info->rhdr, "serial_base",
 		&arch_options.serial_base, sizeof(arch_options.serial_base));
-	elf_rel_set_symbol(&info->rhdr, "serial_baud", 
+	elf_rel_set_symbol(&info->rhdr, "serial_baud",
 		&arch_options.serial_baud, sizeof(arch_options.serial_baud));
-	elf_rel_set_symbol(&info->rhdr, "console_vga", 
+	elf_rel_set_symbol(&info->rhdr, "console_vga",
 		&arch_options.console_vga, sizeof(arch_options.console_vga));
-	elf_rel_set_symbol(&info->rhdr, "console_serial", 
+	elf_rel_set_symbol(&info->rhdr, "console_serial",
 		&arch_options.console_serial, sizeof(arch_options.console_serial));
 	if (info->kexec_flags & KEXEC_ON_CRASH) {
 		panic_kernel = 1;
diff --git a/kexec/arch/x86_64/kexec-x86_64.c b/kexec/arch/x86_64/kexec-x86_64.c
index 5fef6ef..d0b3e90 100644
--- a/kexec/arch/x86_64/kexec-x86_64.c
+++ b/kexec/arch/x86_64/kexec-x86_64.c
@@ -45,7 +45,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 	FILE *fp;
 	fp = fopen(iomem, "r");
 	if (!fp) {
-		fprintf(stderr, "Cannot open %s: %s\n", 
+		fprintf(stderr, "Cannot open %s: %s\n",
 			iomem, strerror(errno));
 		return -1;
 	}
@@ -59,7 +59,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 			break;
 		count = sscanf(line, "%Lx-%Lx : %n",
 			&start, &end, &consumed);
-		if (count != 2) 
+		if (count != 2)
 			continue;
 		str = line + consumed;
 		end = end + 1;
@@ -69,7 +69,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 #endif
 		if (memcmp(str, "System RAM\n", 11) == 0) {
 			type = RANGE_RAM;
-		} 
+		}
 		else if (memcmp(str, "reserved\n", 9) == 0) {
 			type = RANGE_RESERVED;
 		}
@@ -117,7 +117,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 
 struct file_type file_type[] = {
 	{ "elf-x86_64", elf_x86_64_probe, elf_x86_64_load, elf_x86_64_usage },
-	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load, 
+	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
 	{ "elf-x86", elf_x86_probe, elf_x86_load, elf_x86_usage },
 	{ "bzImage", bzImage_probe, bzImage_load, bzImage_usage },
@@ -194,24 +194,24 @@ int arch_process_options(int argc, char **argv)
 				}
 			}
 			if (value >= 65536) {
-				fprintf(stderr, "Bad serial port base '%s'\n", 
+				fprintf(stderr, "Bad serial port base '%s'\n",
 					optarg);
 				usage();
 				return -1;
-				
+
 			}
 			arch_options.serial_base = value;
 			break;
 		case OPT_SERIAL_BAUD:
 			value = strtoul(optarg, &end, 0);
-			if ((value > 115200) || ((115200 %value) != 0) || 
-				(value < 9600) || (*end)) 
+			if ((value > 115200) || ((115200 %value) != 0) ||
+				(value < 9600) || (*end))
 			{
 				fprintf(stderr, "Bad serial port baud rate '%s'\n",
 					optarg);
 				usage();
 				return -1;
-				
+
 			}
 			arch_options.serial_baud = value;
 			break;
@@ -242,13 +242,13 @@ void arch_update_purgatory(struct kexec_info *info)
 
 	elf_rel_set_symbol(&info->rhdr, "reset_vga",
 		&arch_options.reset_vga, sizeof(arch_options.reset_vga));
-	elf_rel_set_symbol(&info->rhdr, "serial_base", 
+	elf_rel_set_symbol(&info->rhdr, "serial_base",
 		&arch_options.serial_base, sizeof(arch_options.serial_base));
-	elf_rel_set_symbol(&info->rhdr, "serial_baud", 
+	elf_rel_set_symbol(&info->rhdr, "serial_baud",
 		&arch_options.serial_baud, sizeof(arch_options.serial_baud));
-	elf_rel_set_symbol(&info->rhdr, "console_vga", 
+	elf_rel_set_symbol(&info->rhdr, "console_vga",
 		&arch_options.console_vga, sizeof(arch_options.console_vga));
-	elf_rel_set_symbol(&info->rhdr, "console_serial", 
+	elf_rel_set_symbol(&info->rhdr, "console_serial",
 		&arch_options.console_serial, sizeof(arch_options.console_serial));
 
 	if (info->kexec_flags & KEXEC_ON_CRASH) {
-- 
1.5.6.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 2/5] Fix compiler warning in kexec-x86.c
  2008-07-06 23:06 Use /sys/firmware/memmap in kexec Bernhard Walle
  2008-07-06 23:06 ` [PATCH 1/5] Remove trailing whitespace Bernhard Walle
@ 2008-07-06 23:06 ` Bernhard Walle
  2008-07-07  7:03   ` Simon Horman
  2008-07-06 23:06 ` [PATCH 3/5] Parse /sys/firmware/memmap Bernhard Walle
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: Bernhard Walle @ 2008-07-06 23:06 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle, Bernhard Walle, vgoyal

From: Bernhard Walle <bernhard.walle@gmx.de>

This patch fixes following compiler warning:

    kexec/arch/i386/kexec-x86.c:234: \
        warning: missing initializer
    kexec/arch/i386/kexec-x86.c:234: \
        warning: (near initialization for 'arches[5].arch')


Signed-off-by: Bernhard Walle <bwalle@suse.de>
Signed-off-by: Bernhard Walle <bernhard.walle@gmx.de>
---
 kexec/arch/i386/kexec-x86.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 31e4752..8c8ba7f 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -226,12 +226,12 @@ const struct arch_map_entry arches[] = {
 	/* For compatibility with older patches
 	 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_386 here.
 	 */
-	{ "i386", KEXEC_ARCH_DEFAULT },
-	{ "i486", KEXEC_ARCH_DEFAULT },
-	{ "i586", KEXEC_ARCH_DEFAULT },
-	{ "i686", KEXEC_ARCH_DEFAULT },
-	{ "x86_64", KEXEC_ARCH_X86_64 },
-	{ 0 },
+	{ "i386",   KEXEC_ARCH_DEFAULT },
+	{ "i486",   KEXEC_ARCH_DEFAULT },
+	{ "i586",   KEXEC_ARCH_DEFAULT },
+	{ "i686",   KEXEC_ARCH_DEFAULT },
+	{ "x86_64", KEXEC_ARCH_X86_64  },
+	{ 0,        0  		       },
 };
 
 int arch_compat_trampoline(struct kexec_info *info)
-- 
1.5.6.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/5] Parse /sys/firmware/memmap.
  2008-07-06 23:06 Use /sys/firmware/memmap in kexec Bernhard Walle
  2008-07-06 23:06 ` [PATCH 1/5] Remove trailing whitespace Bernhard Walle
  2008-07-06 23:06 ` [PATCH 2/5] Fix compiler warning in kexec-x86.c Bernhard Walle
@ 2008-07-06 23:06 ` Bernhard Walle
  2008-07-07  7:06   ` Simon Horman
  2008-07-06 23:06 ` [PATCH 4/5] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
  2008-07-06 23:06 ` [PATCH 5/5] Use get_memory_ranges() on x86-64 Bernhard Walle
  4 siblings, 1 reply; 21+ messages in thread
From: Bernhard Walle @ 2008-07-06 23:06 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle, Bernhard Walle, vgoyal

From: Bernhard Walle <bernhard.walle@gmx.de>

After the patch that provides /sys/firmware/memmap has been merged in the 'tip'
tree by Ingo Molnar, kexec should use that interface.

This patch implements architecture-independent parsing in a new file called
firmware_memmap.c. The x86 part is ported to use that memory map for
kexec. We don't use that memory map for building the ELF core headers,
that was the intention for that new interface.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
Signed-off-by: Bernhard Walle <bernhard.walle@gmx.de>
---
 kexec/Makefile              |    1 +
 kexec/arch/i386/kexec-x86.c |  124 ++++++++++++++++++++-
 kexec/firmware_memmap.c     |  266 +++++++++++++++++++++++++++++++++++++++++++
 kexec/firmware_memmap.h     |   63 ++++++++++
 4 files changed, 451 insertions(+), 3 deletions(-)
 create mode 100644 kexec/firmware_memmap.c
 create mode 100644 kexec/firmware_memmap.h

diff --git a/kexec/Makefile b/kexec/Makefile
index a80b940..3a00114 100644
--- a/kexec/Makefile
+++ b/kexec/Makefile
@@ -18,6 +18,7 @@ KEXEC_SRCS += kexec/kexec-elf-core.c
 KEXEC_SRCS += kexec/kexec-elf-rel.c
 KEXEC_SRCS += kexec/kexec-elf-boot.c
 KEXEC_SRCS += kexec/kexec-iomem.c
+KEXEC_SRCS += kexec/firmware_memmap.c
 KEXEC_SRCS += kexec/crashdump.c
 KEXEC_SRCS += kexec/crashdump-xen.c
 KEXEC_SRCS += kexec/phys_arch.c
diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 8c8ba7f..554c154 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -28,15 +28,26 @@
 #include "../../kexec.h"
 #include "../../kexec-elf.h"
 #include "../../kexec-syscall.h"
+#include "../../firmware_memmap.h"
 #include "kexec-x86.h"
 #include "crashdump-x86.h"
 #include <arch/options.h>
 
 static struct memory_range memory_range[MAX_MEMORY_RANGES];
 
-/* Return a sorted list of memory ranges. */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-				unsigned long kexec_flags)
+/**
+ * The old /proc/iomem parsing code.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges,
+					unsigned long kexec_flags)
 {
 	const char *iomem= proc_iomem();
 	int memory_ranges = 0;
@@ -114,6 +125,113 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 	return 0;
 }
 
+/**
+ * Calls the architecture independent get_firmware_memmap_ranges() to parse
+ * /sys/firmware/memmap and then do some x86 only modifications.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
+				   unsigned long kexec_flags)
+{
+	int ret;
+	size_t i;
+	size_t range_number = MAX_MEMORY_RANGES;
+	unsigned long long start, end;
+
+	ret = get_firmware_memmap_ranges(memory_range, &range_number);
+	if (ret != 0) {
+		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
+			"Falling back to /proc/iomem.\n");
+		return get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+	}
+
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < range_number; i++) {
+		if (memory_range[i].type == RANGE_RAM &&
+				(memory_range[i].start < 0x100)) {
+			memory_range[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
+	*range = memory_range;
+	*ranges = range_number;
+
+	return 0;
+}
+
+/**
+ * Return a sorted list of memory ranges.
+ *
+ * If we have the /sys/firmware/memmap interface, then use that. If not,
+ * or if parsing of that fails, use /proc/iomem as fallback.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+int get_memory_ranges(struct memory_range **range, int *ranges,
+		      unsigned long kexec_flags)
+{
+	int ret;
+
+	if (have_sys_firmware_memmap())
+		ret = get_memory_ranges_sysfs(range, ranges,kexec_flags);
+	else
+		ret = get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+
+	/*
+	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
+	 * have already printed an error message, so fail silently here
+	 */
+	if (ret != 0)
+		return ret;
+
+	/* just set 0 to 1 to enable printing for debugging */
+#if 0
+	{
+		int i;
+		printf("MEMORY RANGES\n");
+		for (i = 0; i < *ranges; i++) {
+			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
+				(*range)[i].end, (*range)[i].type);
+		}
+	}
+#endif
+
+	return ret;
+}
+
 struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
diff --git a/kexec/firmware_memmap.c b/kexec/firmware_memmap.c
new file mode 100644
index 0000000..cdac6f3
--- /dev/null
+++ b/kexec/firmware_memmap.c
@@ -0,0 +1,266 @@
+/*
+ * firmware_memmap.c: Read /sys/firmware/memmap
+ *
+ * Created by: Bernhard Walle (bwalle@suse.de)
+ * Copyright (C) SUSE LINUX Products GmbH, 2008. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#define _GNU_SOURCE /* for ULLONG_MAX without C99 */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "firmware_memmap.h"
+#include "kexec.h"
+
+/**
+ * The full path to the sysfs interface that provides the memory map.
+ */
+#define FIRMWARE_MEMMAP_DIR  "/sys/firmware/memmap"
+
+/**
+ * Parses a file that only contains one number. Typical for sysfs files.
+ *
+ * @param[in] filename the name of the file that should be parsed
+ * @return the value that has been read or ULLONG_MAX on error.
+ */
+static unsigned long long parse_numeric_sysfs(const char *filename)
+{
+	FILE *fp;
+	char linebuffer[BUFSIZ];
+	unsigned long long retval;
+
+	fp = fopen(filename, "r");
+	if (!fp) {
+		fprintf(stderr, "Opening \"%s\" failed: %s\n",
+			filename, strerror(errno));
+		return ULLONG_MAX;
+	}
+
+	fgets(linebuffer, BUFSIZ, fp);
+	linebuffer[BUFSIZ-1] = 0;
+
+	/* let strtoll() detect the base */
+	retval = strtoll(linebuffer, NULL, 0);
+
+	fclose(fp);
+
+	return retval;
+}
+
+/**
+ * Reads the contents of a one-line sysfs file to buffer. (This function is
+ * not threadsafe.)
+ *
+ * @param[in] filename the name of the file that should be read
+ *
+ * @return NULL on failure, a pointer to a static buffer (that should be copied
+ *         with strdup() if the caller plans to use it after next function call)
+ */
+static char *parse_string_sysfs(const char *filename)
+{
+	FILE *fp;
+	static char linebuffer[BUFSIZ];
+	char *end;
+
+	fp = fopen(filename, "r");
+	if (!fp) {
+		fprintf(stderr, "Opening \"%s\" failed: %s\n",
+			filename, strerror(errno));
+		return NULL;
+	}
+
+	fgets(linebuffer, BUFSIZ, fp);
+	linebuffer[BUFSIZ-1] = 0;
+
+	/* truncate trailing newline(s) */
+	end = linebuffer + strlen(linebuffer) - 1;
+	while (*end == '\n')
+		*end-- = 0;
+
+	fclose(fp);
+
+	return linebuffer;
+
+}
+
+static int parse_memmap_entry(const char *entry, struct memory_range *range)
+{
+	char filename[PATH_MAX];
+	char *type;
+
+	/*
+	 * entry/start
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "start");
+	filename[PATH_MAX-1] = 0;
+
+	range->start = parse_numeric_sysfs(filename);
+	if (range->start == ULLONG_MAX)
+		return -1;
+
+	/*
+	 * entry/end
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "end");
+	filename[PATH_MAX-1] = 0;
+
+	range->end = parse_numeric_sysfs(filename);
+	if (range->end == ULLONG_MAX)
+		return -1;
+	range->end++; /* inclusive vs. exclusive ranges */
+
+	/*
+	 * entry/type
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "type");
+	filename[PATH_MAX-1] = 0;
+
+	type = parse_string_sysfs(filename);
+	if (!type)
+		return -1;
+
+	if (strcmp(type, "System RAM") == 0)
+		range->type = RANGE_RAM;
+	else if (strcmp(type, "ACPI Tables") == 0)
+		range->type = RANGE_ACPI;
+	else if (strcmp(type, "reserved") == 0)
+		range->type = RANGE_RESERVED;
+	else if (strcmp(type, "ACPI Non-volatile Storage") == 0)
+		range->type = RANGE_ACPI_NVS;
+	else {
+		fprintf(stderr, "Unknown type (%s) while parsing %s. Please "
+			"report this as bug. Using RANGE_RESERVED now.\n",
+			type, filename);
+		range->type = RANGE_RESERVED;
+	}
+
+	return 0;
+}
+
+/**
+ * Compares two memory ranges according to their start address. This function
+ * can be used with qsort() as @c compar function.
+ *
+ * @param[in] first a pointer to the first memory range
+ * @param[in] second a pointer to the second memory range
+ * @return 0 if @p first and @p second have the same start address,
+ *         a value less then 0 if the start address of @p first is less than
+ *         the start address of @p second, and a value greater than 0 if
+ *         the opposite is in case.
+ */
+static int compare_ranges(const void *first, const void *second)
+{
+	const struct memory_range *first_range = first;
+	const struct memory_range *second_range = second;
+
+	/*
+	 * don't use the "first_range->start - second_range->start"
+	 * notation because unsigned long long might overflow
+	 */
+	if (first_range->start > second_range->start)
+		return 1;
+	else if (first_range->start < second_range->start)
+		return -1;
+	else /* first_range->start == second_range->start */
+		return 0;
+}
+
+/* documentation: firmware_memmap.h */
+int have_sys_firmware_memmap(void)
+{
+	int ret;
+	struct stat mystat;
+
+	ret = stat(FIRMWARE_MEMMAP_DIR, &mystat);
+	if (ret != 0)
+		return 0;
+
+	return S_ISDIR(mystat.st_mode);
+}
+
+/* documentation: firmware_memmap.h */
+int get_firmware_memmap_ranges(struct memory_range *range, size_t *ranges)
+{
+	DIR *firmware_memmap_dir = NULL;
+	struct dirent *dirent;
+	int i = 0;
+
+	/* argument checking */
+	if (!range || !ranges) {
+		fprintf(stderr, "%s: Invalid arguments.\n", __FUNCTION__);
+		return -1;
+	}
+
+	/* open the directory */
+	firmware_memmap_dir = opendir(FIRMWARE_MEMMAP_DIR);
+	if (!firmware_memmap_dir) {
+		perror("Could not open \"" FIRMWARE_MEMMAP_DIR "\"");
+		goto error;
+	}
+
+	/* parse the entries */
+	while ((dirent = readdir(firmware_memmap_dir)) != NULL) {
+		int ret;
+		char full_path[PATH_MAX];
+
+		/* array overflow check */
+		if ((size_t)i >= *ranges) {
+			fprintf(stderr, "The firmware provides more entries "
+				"allowed (%d). Please report that as bug.\n",
+				*ranges);
+			goto error;
+		}
+
+		/* exclude '.' and '..' */
+		if (dirent->d_name[0] && dirent->d_name[0] == '.') {
+			continue;
+		}
+
+		snprintf(full_path, PATH_MAX, "%s/%s", FIRMWARE_MEMMAP_DIR,
+			dirent->d_name);
+		full_path[PATH_MAX-1] = 0;
+		ret = parse_memmap_entry(full_path, &range[i]);
+		if (ret < 0) {
+			goto error;
+		}
+
+		i++;
+	}
+
+	/* close the dir as we don't need it any more */
+	closedir(firmware_memmap_dir);
+
+	/* update the number of ranges for the caller */
+	*ranges = i;
+
+	/* and finally sort the entries with qsort */
+	qsort(range, *ranges, sizeof(struct memory_range), compare_ranges);
+
+	return 0;
+
+error:
+	if (firmware_memmap_dir) {
+		closedir(firmware_memmap_dir);
+	}
+	return -1;
+}
+
diff --git a/kexec/firmware_memmap.h b/kexec/firmware_memmap.h
new file mode 100644
index 0000000..41c3b3f
--- /dev/null
+++ b/kexec/firmware_memmap.h
@@ -0,0 +1,63 @@
+/*
+ * firmware_memmap.c: Read /sys/firmware/memmap
+ *
+ * Created by: Bernhard Walle (bwalle@suse.de)
+ * Copyright (C) SUSE LINUX Products GmbH, 2008. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef FIRMWARE_MEMMAP_H
+#define FIRMWARE_MEMMAP_H
+
+#include "kexec.h"
+
+/**
+ * Reads the /sys/firmware/memmap interface, documented in
+ * Documentation/ABI/testing/sysfs-firmware-memmap (kernel tree).
+ *
+ * The difference between /proc/iomem and /sys/firmware/memmap is that
+ * /sys/firmware/memmap provides the raw memory map, provided by the
+ * firmware of the system. That memory map should be passed to a kexec'd
+ * kernel because the behaviour should be the same as a normal booted kernel,
+ * so any limitation (e.g. by the user providing the mem command line option)
+ * should not be passed to the kexec'd kernel.
+ *
+ * The parsing of the code is independent of the architecture. However, the
+ * actual architecture-specific code might postprocess the code a bit, like
+ * x86 does.
+ */
+
+/**
+ * Checks if the kernel provides the /sys/firmware/memmap interface.
+ * It makes sense to use that function in advance before calling
+ * get_firmware_memmap_ranges() because the latter function prints an error
+ * if it cannot open the directory. If have_sys_firmware_memmap() returns
+ * false, then one can use the old /proc/iomem interface (for older kernels).
+ */
+int have_sys_firmware_memmap(void);
+
+/**
+ * Parses the /sys/firmware/memmap memory map.
+ *
+ * @param[out] range a pointer to an array of type struct memory_range with
+ *             at least *range entries
+ * @param[in,out] ranges a pointer to an integer that holds the number of
+ *        	  entries which range contains (at least). After successful
+ *        	  return, the number of actual entries will be written.
+ * @return 0 on success, -1 on failure.
+ */
+int get_firmware_memmap_ranges(struct memory_range *range, size_t *ranges);
+
+
+#endif /* FIRMWARE_MEMMAP_H */
-- 
1.5.6.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 4/5] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs()
  2008-07-06 23:06 Use /sys/firmware/memmap in kexec Bernhard Walle
                   ` (2 preceding siblings ...)
  2008-07-06 23:06 ` [PATCH 3/5] Parse /sys/firmware/memmap Bernhard Walle
@ 2008-07-06 23:06 ` Bernhard Walle
  2008-07-06 23:06 ` [PATCH 5/5] Use get_memory_ranges() on x86-64 Bernhard Walle
  4 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-06 23:06 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle, Bernhard Walle, vgoyal

From: Bernhard Walle <bernhard.walle@gmx.de>

With the previous patch, we have a duplication between that both functions
for following tasks:

 - don't report the interrupt table as RAM,
 - set the mem_min and mem_max limits for kdump.

This patch removes that redundancy into the function get_memory_ranges()
that calls both functions internally.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
Signed-off-by: Bernhard Walle <bernhard.walle@gmx.de>
---
 kexec/arch/i386/kexec-x86.c |   96 ++++++++++++++++---------------------------
 1 files changed, 36 insertions(+), 60 deletions(-)

diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 554c154..d5b6737 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -41,13 +41,10 @@ static struct memory_range memory_range[MAX_MEMORY_RANGES];
  * @param[out] range pointer that will be set to an array that holds the
  *             memory ranges
  * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
  *
  * @return 0 on success, any other value on failure.
  */
-static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges,
-					unsigned long kexec_flags)
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
 {
 	const char *iomem= proc_iomem();
 	int memory_ranges = 0;
@@ -89,27 +86,9 @@ static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges
 		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
 			type = RANGE_ACPI_NVS;
 		}
-		else if (memcmp(str, "Crash kernel\n", 13) == 0) {
-		/* Redefine the memory region boundaries if kernel
-		 * exports the limits and if it is panic kernel.
-		 * Override user values only if kernel exported values are
-		 * subset of user defined values.
-		 */
-			if (kexec_flags & KEXEC_ON_CRASH) {
-				if (start > mem_min)
-					mem_min = start;
-				if (end < mem_max)
-					mem_max = end;
-			}
-			continue;
-		}
 		else {
 			continue;
 		}
-		/* Don't report the interrupt table as ram */
-		if (type == RANGE_RAM && (start < 0x100)) {
-			start = 0x100;
-		}
 		memory_range[memory_ranges].start = start;
 		memory_range[memory_ranges].end = end;
 		memory_range[memory_ranges].type = type;
@@ -132,52 +111,19 @@ static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges
  * @param[out] range pointer that will be set to an array that holds the
  *             memory ranges
  * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
  *
  * @return 0 on success, any other value on failure.
  */
-static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
-				   unsigned long kexec_flags)
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
 {
 	int ret;
-	size_t i;
 	size_t range_number = MAX_MEMORY_RANGES;
-	unsigned long long start, end;
 
 	ret = get_firmware_memmap_ranges(memory_range, &range_number);
 	if (ret != 0) {
 		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
 			"Falling back to /proc/iomem.\n");
-		return get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
-	}
-
-	/* Don't report the interrupt table as ram */
-	for (i = 0; i < range_number; i++) {
-		if (memory_range[i].type == RANGE_RAM &&
-				(memory_range[i].start < 0x100)) {
-			memory_range[i].start = 0x100;
-			break;
-		}
-	}
-
-	/*
-	 * Redefine the memory region boundaries if kernel
-	 * exports the limits and if it is panic kernel.
-	 * Override user values only if kernel exported values are
-	 * subset of user defined values.
-	 */
-	if (kexec_flags & KEXEC_ON_CRASH) {
-		ret = parse_iomem_single("Crash kernel\n", &start, &end);
-		if (ret != 0) {
-			fprintf(stderr, "parse_iomem_single failed.\n");
-			return -1;
-		}
-
-		if (start > mem_min)
-			mem_min = start;
-		if (end < mem_max)
-			mem_max = end;
+		return get_memory_ranges_proc_iomem(range, ranges);
 	}
 
 	*range = memory_range;
@@ -203,12 +149,12 @@ static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
 int get_memory_ranges(struct memory_range **range, int *ranges,
 		      unsigned long kexec_flags)
 {
-	int ret;
+	int ret, i;
 
 	if (have_sys_firmware_memmap())
-		ret = get_memory_ranges_sysfs(range, ranges,kexec_flags);
+		ret = get_memory_ranges_sysfs(range, ranges);
 	else
-		ret = get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+		ret = get_memory_ranges_proc_iomem(range, ranges);
 
 	/*
 	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
@@ -217,6 +163,36 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 	if (ret != 0)
 		return ret;
 
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < *ranges; i++) {
+		if ((*range)[i].type == RANGE_RAM &&
+				((*range)[i].start < 0x100)) {
+			(*range)[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		unsigned long long start, end;
+
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
 	/* just set 0 to 1 to enable printing for debugging */
 #if 0
 	{
-- 
1.5.6.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 5/5] Use get_memory_ranges() on x86-64.
  2008-07-06 23:06 Use /sys/firmware/memmap in kexec Bernhard Walle
                   ` (3 preceding siblings ...)
  2008-07-06 23:06 ` [PATCH 4/5] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
@ 2008-07-06 23:06 ` Bernhard Walle
  4 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-06 23:06 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle, Bernhard Walle, vgoyal

From: Bernhard Walle <bernhard.walle@gmx.de>

Because the get_memory_ranges() function was the same on i386 and x86_64, and
because that /sys/firmware/memmap interface should also be used for x86_64
without *new* code duplication, that part was moved out in a new file called
kexec-x86-common.c. That file only contains the memory map parsing for both the
"old" /proc/iomem interface and the new /sys/firmware/memmap interface.

That file is now built for i386 and x86_64.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
Signed-off-by: Bernhard Walle <bernhard.walle@gmx.de>
---
 kexec/arch/i386/Makefile           |    1 +
 kexec/arch/i386/kexec-x86-common.c |  207 ++++++++++++++++++++++++++++++++++++
 kexec/arch/i386/kexec-x86.c        |  175 ------------------------------
 kexec/arch/x86_64/Makefile         |    1 +
 kexec/arch/x86_64/kexec-x86_64.c   |   83 --------------
 5 files changed, 209 insertions(+), 258 deletions(-)
 create mode 100644 kexec/arch/i386/kexec-x86-common.c

diff --git a/kexec/arch/i386/Makefile b/kexec/arch/i386/Makefile
index f2d9636..d52a2f5 100644
--- a/kexec/arch/i386/Makefile
+++ b/kexec/arch/i386/Makefile
@@ -2,6 +2,7 @@
 # kexec i386 (linux booting linux)
 #
 i386_KEXEC_SRCS =  kexec/arch/i386/kexec-x86.c
+i386_KEXEC_SRCS += kexec/arch/i386/kexec-x86-common.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-elf-x86.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-elf-rel-x86.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-bzImage.c
diff --git a/kexec/arch/i386/kexec-x86-common.c b/kexec/arch/i386/kexec-x86-common.c
new file mode 100644
index 0000000..4533425
--- /dev/null
+++ b/kexec/arch/i386/kexec-x86-common.c
@@ -0,0 +1,207 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "../../kexec.h"
+#include "../../kexec-syscall.h"
+#include "../../firmware_memmap.h"
+#include "kexec-x86.h"
+
+static struct memory_range memory_range[MAX_MEMORY_RANGES];
+
+/**
+ * The old /proc/iomem parsing code.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
+{
+	const char *iomem= proc_iomem();
+	int memory_ranges = 0;
+	char line[MAX_LINE];
+	FILE *fp;
+	fp = fopen(iomem, "r");
+	if (!fp) {
+		fprintf(stderr, "Cannot open %s: %s\n",
+			iomem, strerror(errno));
+		return -1;
+	}
+	while(fgets(line, sizeof(line), fp) != 0) {
+		unsigned long long start, end;
+		char *str;
+		int type;
+		int consumed;
+		int count;
+		if (memory_ranges >= MAX_MEMORY_RANGES)
+			break;
+		count = sscanf(line, "%Lx-%Lx : %n",
+			&start, &end, &consumed);
+		if (count != 2)
+			continue;
+		str = line + consumed;
+		end = end + 1;
+#if 0
+		printf("%016Lx-%016Lx : %s",
+			start, end, str);
+#endif
+		if (memcmp(str, "System RAM\n", 11) == 0) {
+			type = RANGE_RAM;
+		}
+		else if (memcmp(str, "reserved\n", 9) == 0) {
+			type = RANGE_RESERVED;
+		}
+		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
+			type = RANGE_ACPI;
+		}
+		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
+			type = RANGE_ACPI_NVS;
+		}
+		else {
+			continue;
+		}
+		memory_range[memory_ranges].start = start;
+		memory_range[memory_ranges].end = end;
+		memory_range[memory_ranges].type = type;
+#if 0
+		printf("%016Lx-%016Lx : %x\n",
+			start, end, type);
+#endif
+		memory_ranges++;
+	}
+	fclose(fp);
+	*range = memory_range;
+	*ranges = memory_ranges;
+	return 0;
+}
+
+/**
+ * Calls the architecture independent get_firmware_memmap_ranges() to parse
+ * /sys/firmware/memmap and then do some x86 only modifications.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
+{
+	int ret;
+	size_t range_number = MAX_MEMORY_RANGES;
+
+	ret = get_firmware_memmap_ranges(memory_range, &range_number);
+	if (ret != 0) {
+		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
+			"Falling back to /proc/iomem.\n");
+		return get_memory_ranges_proc_iomem(range, ranges);
+	}
+
+	*range = memory_range;
+	*ranges = range_number;
+
+	return 0;
+}
+
+/**
+ * Return a sorted list of memory ranges.
+ *
+ * If we have the /sys/firmware/memmap interface, then use that. If not,
+ * or if parsing of that fails, use /proc/iomem as fallback.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+int get_memory_ranges(struct memory_range **range, int *ranges,
+		      unsigned long kexec_flags)
+{
+	int ret, i;
+
+	if (have_sys_firmware_memmap())
+		ret = get_memory_ranges_sysfs(range, ranges);
+	else
+		ret = get_memory_ranges_proc_iomem(range, ranges);
+
+	/*
+	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
+	 * have already printed an error message, so fail silently here
+	 */
+	if (ret != 0)
+		return ret;
+
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < *ranges; i++) {
+		if ((*range)[i].type == RANGE_RAM &&
+				((*range)[i].start < 0x100)) {
+			(*range)[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		unsigned long long start, end;
+
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
+	/* just set 0 to 1 to enable printing for debugging */
+#if 0
+	{
+		int i;
+		printf("MEMORY RANGES\n");
+		for (i = 0; i < *ranges; i++) {
+			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
+				(*range)[i].end, (*range)[i].type);
+		}
+	}
+#endif
+
+	return ret;
+}
+
+
diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index d5b6737..d33a14b 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -33,181 +33,6 @@
 #include "crashdump-x86.h"
 #include <arch/options.h>
 
-static struct memory_range memory_range[MAX_MEMORY_RANGES];
-
-/**
- * The old /proc/iomem parsing code.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- *
- * @return 0 on success, any other value on failure.
- */
-static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
-{
-	const char *iomem= proc_iomem();
-	int memory_ranges = 0;
-	char line[MAX_LINE];
-	FILE *fp;
-	fp = fopen(iomem, "r");
-	if (!fp) {
-		fprintf(stderr, "Cannot open %s: %s\n",
-			iomem, strerror(errno));
-		return -1;
-	}
-	while(fgets(line, sizeof(line), fp) != 0) {
-		unsigned long long start, end;
-		char *str;
-		int type;
-		int consumed;
-		int count;
-		if (memory_ranges >= MAX_MEMORY_RANGES)
-			break;
-		count = sscanf(line, "%Lx-%Lx : %n",
-			&start, &end, &consumed);
-		if (count != 2)
-			continue;
-		str = line + consumed;
-		end = end + 1;
-#if 0
-		printf("%016Lx-%016Lx : %s",
-			start, end, str);
-#endif
-		if (memcmp(str, "System RAM\n", 11) == 0) {
-			type = RANGE_RAM;
-		}
-		else if (memcmp(str, "reserved\n", 9) == 0) {
-			type = RANGE_RESERVED;
-		}
-		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
-			type = RANGE_ACPI;
-		}
-		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
-			type = RANGE_ACPI_NVS;
-		}
-		else {
-			continue;
-		}
-		memory_range[memory_ranges].start = start;
-		memory_range[memory_ranges].end = end;
-		memory_range[memory_ranges].type = type;
-#if 0
-		printf("%016Lx-%016Lx : %x\n",
-			start, end, type);
-#endif
-		memory_ranges++;
-	}
-	fclose(fp);
-	*range = memory_range;
-	*ranges = memory_ranges;
-	return 0;
-}
-
-/**
- * Calls the architecture independent get_firmware_memmap_ranges() to parse
- * /sys/firmware/memmap and then do some x86 only modifications.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- *
- * @return 0 on success, any other value on failure.
- */
-static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
-{
-	int ret;
-	size_t range_number = MAX_MEMORY_RANGES;
-
-	ret = get_firmware_memmap_ranges(memory_range, &range_number);
-	if (ret != 0) {
-		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
-			"Falling back to /proc/iomem.\n");
-		return get_memory_ranges_proc_iomem(range, ranges);
-	}
-
-	*range = memory_range;
-	*ranges = range_number;
-
-	return 0;
-}
-
-/**
- * Return a sorted list of memory ranges.
- *
- * If we have the /sys/firmware/memmap interface, then use that. If not,
- * or if parsing of that fails, use /proc/iomem as fallback.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
- *
- * @return 0 on success, any other value on failure.
- */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-		      unsigned long kexec_flags)
-{
-	int ret, i;
-
-	if (have_sys_firmware_memmap())
-		ret = get_memory_ranges_sysfs(range, ranges);
-	else
-		ret = get_memory_ranges_proc_iomem(range, ranges);
-
-	/*
-	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
-	 * have already printed an error message, so fail silently here
-	 */
-	if (ret != 0)
-		return ret;
-
-	/* Don't report the interrupt table as ram */
-	for (i = 0; i < *ranges; i++) {
-		if ((*range)[i].type == RANGE_RAM &&
-				((*range)[i].start < 0x100)) {
-			(*range)[i].start = 0x100;
-			break;
-		}
-	}
-
-	/*
-	 * Redefine the memory region boundaries if kernel
-	 * exports the limits and if it is panic kernel.
-	 * Override user values only if kernel exported values are
-	 * subset of user defined values.
-	 */
-	if (kexec_flags & KEXEC_ON_CRASH) {
-		unsigned long long start, end;
-
-		ret = parse_iomem_single("Crash kernel\n", &start, &end);
-		if (ret != 0) {
-			fprintf(stderr, "parse_iomem_single failed.\n");
-			return -1;
-		}
-
-		if (start > mem_min)
-			mem_min = start;
-		if (end < mem_max)
-			mem_max = end;
-	}
-
-	/* just set 0 to 1 to enable printing for debugging */
-#if 0
-	{
-		int i;
-		printf("MEMORY RANGES\n");
-		for (i = 0; i < *ranges; i++) {
-			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
-				(*range)[i].end, (*range)[i].type);
-		}
-	}
-#endif
-
-	return ret;
-}
-
 struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
diff --git a/kexec/arch/x86_64/Makefile b/kexec/arch/x86_64/Makefile
index c59c41f..7ca3e7e 100644
--- a/kexec/arch/x86_64/Makefile
+++ b/kexec/arch/x86_64/Makefile
@@ -7,6 +7,7 @@ x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-multiboot-x86.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-beoboot-x86.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-nbi.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/x86-linux-setup.c
+x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-x86-common.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/crashdump-x86_64.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/kexec-x86_64.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/kexec-elf-x86_64.c
diff --git a/kexec/arch/x86_64/kexec-x86_64.c b/kexec/arch/x86_64/kexec-x86_64.c
index d0b3e90..9973815 100644
--- a/kexec/arch/x86_64/kexec-x86_64.c
+++ b/kexec/arch/x86_64/kexec-x86_64.c
@@ -32,89 +32,6 @@
 #include "crashdump-x86_64.h"
 #include <arch/options.h>
 
-#define MAX_MEMORY_RANGES 64
-static struct memory_range memory_range[MAX_MEMORY_RANGES];
-
-/* Return a sorted list of memory ranges. */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-					unsigned long kexec_flags)
-{
-	const char *iomem= proc_iomem();
-	int memory_ranges = 0;
-	char line[MAX_LINE];
-	FILE *fp;
-	fp = fopen(iomem, "r");
-	if (!fp) {
-		fprintf(stderr, "Cannot open %s: %s\n",
-			iomem, strerror(errno));
-		return -1;
-	}
-	while(fgets(line, sizeof(line), fp) != 0) {
-		unsigned long long start, end;
-		char *str;
-		int type;
-		int consumed;
-		int count;
-		if (memory_ranges >= MAX_MEMORY_RANGES)
-			break;
-		count = sscanf(line, "%Lx-%Lx : %n",
-			&start, &end, &consumed);
-		if (count != 2)
-			continue;
-		str = line + consumed;
-		end = end + 1;
-#ifdef DEBUG
-		printf("%016Lx-%016Lx : %s",
-			start, end, str);
-#endif
-		if (memcmp(str, "System RAM\n", 11) == 0) {
-			type = RANGE_RAM;
-		}
-		else if (memcmp(str, "reserved\n", 9) == 0) {
-			type = RANGE_RESERVED;
-		}
-		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
-			type = RANGE_ACPI;
-		}
-		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
-			type = RANGE_ACPI_NVS;
-		}
-		else if (memcmp(str, "Crash kernel\n", 13) == 0) {
-			/* Redefine the memory region boundaries if kernel
-			 * exports the limits and if it is panic kernel.
-			 * Override user values only if kernel exported
-			 * values are subset of user defined values.
-			 */
-			if (kexec_flags & KEXEC_ON_CRASH) {
-				if (start > mem_min)
-					mem_min = start;
-				if (end < mem_max)
-					mem_max = end;
-			}
-			continue;
-		}
-		else {
-			continue;
-		}
-		/* Don't report the interrupt table as ram */
-		if (type == RANGE_RAM && (start < 0x100)) {
-			start = 0x100;
-		}
-		memory_range[memory_ranges].start = start;
-		memory_range[memory_ranges].end = end;
-		memory_range[memory_ranges].type = type;
-#ifdef DEBUG
-		printf("%016Lx-%016Lx : %x\n",
-			start, end, type);
-#endif
-		memory_ranges++;
-	}
-	fclose(fp);
-	*range = memory_range;
-	*ranges = memory_ranges;
-	return 0;
-}
-
 struct file_type file_type[] = {
 	{ "elf-x86_64", elf_x86_64_probe, elf_x86_64_load, elf_x86_64_usage },
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
-- 
1.5.6.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] Remove trailing whitespace
  2008-07-06 23:06 ` [PATCH 1/5] Remove trailing whitespace Bernhard Walle
@ 2008-07-07  7:02   ` Simon Horman
  0 siblings, 0 replies; 21+ messages in thread
From: Simon Horman @ 2008-07-07  7:02 UTC (permalink / raw)
  To: Bernhard Walle; +Cc: Bernhard Walle, kexec, vgoyal

On Mon, Jul 07, 2008 at 01:06:07AM +0200, Bernhard Walle wrote:
> From: Bernhard Walle <bernhard.walle@gmx.de>
> 
> This patch just removes trailing whitespace from kexec/arch/i386/kexec-x86.c
> before modifying something.

Thanks, applied.

-- 
Horms


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/5] Fix compiler warning in kexec-x86.c
  2008-07-06 23:06 ` [PATCH 2/5] Fix compiler warning in kexec-x86.c Bernhard Walle
@ 2008-07-07  7:03   ` Simon Horman
  0 siblings, 0 replies; 21+ messages in thread
From: Simon Horman @ 2008-07-07  7:03 UTC (permalink / raw)
  To: Bernhard Walle; +Cc: Bernhard Walle, kexec, vgoyal

On Mon, Jul 07, 2008 at 01:06:08AM +0200, Bernhard Walle wrote:
> From: Bernhard Walle <bernhard.walle@gmx.de>
> 
> This patch fixes following compiler warning:
> 
>     kexec/arch/i386/kexec-x86.c:234: \
>         warning: missing initializer
>     kexec/arch/i386/kexec-x86.c:234: \
>         warning: (near initialization for 'arches[5].arch')

Thanks, applied.

-- 
Horms


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/5] Parse /sys/firmware/memmap.
  2008-07-06 23:06 ` [PATCH 3/5] Parse /sys/firmware/memmap Bernhard Walle
@ 2008-07-07  7:06   ` Simon Horman
  2008-07-07 14:43     ` Bernhard Walle
                       ` (3 more replies)
  0 siblings, 4 replies; 21+ messages in thread
From: Simon Horman @ 2008-07-07  7:06 UTC (permalink / raw)
  To: Bernhard Walle; +Cc: Bernhard Walle, kexec, vgoyal

On Mon, Jul 07, 2008 at 01:06:09AM +0200, Bernhard Walle wrote:
> From: Bernhard Walle <bernhard.walle@gmx.de>
> 
> After the patch that provides /sys/firmware/memmap has been merged in the 'tip'
> tree by Ingo Molnar, kexec should use that interface.
> 
> This patch implements architecture-independent parsing in a new file called
> firmware_memmap.c. The x86 part is ported to use that memory map for
> kexec. We don't use that memory map for building the ELF core headers,
> that was the intention for that new interface.

Hi Bernhard,

I am seeing a build problem when compiling for i386

exec/firmware_memmap.c: In function `parse_numeric_sysfs':
kexec/firmware_memmap.c:55: error: `ULLONG_MAX' undeclared (first use in
this function)
kexec/firmware_memmap.c:55: error: (Each undeclared identifier is
reported only once
kexec/firmware_memmap.c:55: error: for each function it appears in.)
kexec/firmware_memmap.c: In function `parse_memmap_entry':
kexec/firmware_memmap.c:117: error: `ULLONG_MAX' undeclared (first use
in this function)

-- 
Horms


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Parse /sys/firmware/memmap
  2008-07-07  7:06   ` Simon Horman
@ 2008-07-07 14:43     ` Bernhard Walle
  2008-07-07 14:43     ` [PATCH 1/3] " Bernhard Walle
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-07 14:43 UTC (permalink / raw)
  To: kexec

My patch series again (without the already applied patches).
Diff to last change: Define ULLONG_MAX if not already defined.



_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/3] Parse /sys/firmware/memmap.
  2008-07-07  7:06   ` Simon Horman
  2008-07-07 14:43     ` Bernhard Walle
@ 2008-07-07 14:43     ` Bernhard Walle
  2008-07-07 14:43     ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
  2008-07-07 14:43     ` [PATCH 3/3] Use get_memory_ranges() on x86-64 Bernhard Walle
  3 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-07 14:43 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle, Bernhard Walle

From: Bernhard Walle <bernhard.walle@gmx.de>

After the patch that provides /sys/firmware/memmap has been merged in the 'tip'
tree by Ingo Molnar, kexec should use that interface.

This patch implements architecture-independent parsing in a new file called
firmware_memmap.c. The x86 part is ported to use that memory map for
kexec. We don't use that memory map for building the ELF core headers,
that was the intention for that new interface.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
 kexec/Makefile              |    1 +
 kexec/arch/i386/kexec-x86.c |  124 ++++++++++++++++++++-
 kexec/firmware_memmap.c     |  266 +++++++++++++++++++++++++++++++++++++++++++
 kexec/firmware_memmap.h     |   63 ++++++++++
 4 files changed, 451 insertions(+), 3 deletions(-)
 create mode 100644 kexec/firmware_memmap.c
 create mode 100644 kexec/firmware_memmap.h

diff --git a/kexec/Makefile b/kexec/Makefile
index a80b940..3a00114 100644
--- a/kexec/Makefile
+++ b/kexec/Makefile
@@ -18,6 +18,7 @@ KEXEC_SRCS += kexec/kexec-elf-core.c
 KEXEC_SRCS += kexec/kexec-elf-rel.c
 KEXEC_SRCS += kexec/kexec-elf-boot.c
 KEXEC_SRCS += kexec/kexec-iomem.c
+KEXEC_SRCS += kexec/firmware_memmap.c
 KEXEC_SRCS += kexec/crashdump.c
 KEXEC_SRCS += kexec/crashdump-xen.c
 KEXEC_SRCS += kexec/phys_arch.c
diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 8c8ba7f..554c154 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -28,15 +28,26 @@
 #include "../../kexec.h"
 #include "../../kexec-elf.h"
 #include "../../kexec-syscall.h"
+#include "../../firmware_memmap.h"
 #include "kexec-x86.h"
 #include "crashdump-x86.h"
 #include <arch/options.h>
 
 static struct memory_range memory_range[MAX_MEMORY_RANGES];
 
-/* Return a sorted list of memory ranges. */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-				unsigned long kexec_flags)
+/**
+ * The old /proc/iomem parsing code.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges,
+					unsigned long kexec_flags)
 {
 	const char *iomem= proc_iomem();
 	int memory_ranges = 0;
@@ -114,6 +125,113 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 	return 0;
 }
 
+/**
+ * Calls the architecture independent get_firmware_memmap_ranges() to parse
+ * /sys/firmware/memmap and then do some x86 only modifications.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
+				   unsigned long kexec_flags)
+{
+	int ret;
+	size_t i;
+	size_t range_number = MAX_MEMORY_RANGES;
+	unsigned long long start, end;
+
+	ret = get_firmware_memmap_ranges(memory_range, &range_number);
+	if (ret != 0) {
+		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
+			"Falling back to /proc/iomem.\n");
+		return get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+	}
+
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < range_number; i++) {
+		if (memory_range[i].type == RANGE_RAM &&
+				(memory_range[i].start < 0x100)) {
+			memory_range[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
+	*range = memory_range;
+	*ranges = range_number;
+
+	return 0;
+}
+
+/**
+ * Return a sorted list of memory ranges.
+ *
+ * If we have the /sys/firmware/memmap interface, then use that. If not,
+ * or if parsing of that fails, use /proc/iomem as fallback.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+int get_memory_ranges(struct memory_range **range, int *ranges,
+		      unsigned long kexec_flags)
+{
+	int ret;
+
+	if (have_sys_firmware_memmap())
+		ret = get_memory_ranges_sysfs(range, ranges,kexec_flags);
+	else
+		ret = get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+
+	/*
+	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
+	 * have already printed an error message, so fail silently here
+	 */
+	if (ret != 0)
+		return ret;
+
+	/* just set 0 to 1 to enable printing for debugging */
+#if 0
+	{
+		int i;
+		printf("MEMORY RANGES\n");
+		for (i = 0; i < *ranges; i++) {
+			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
+				(*range)[i].end, (*range)[i].type);
+		}
+	}
+#endif
+
+	return ret;
+}
+
 struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
diff --git a/kexec/firmware_memmap.c b/kexec/firmware_memmap.c
new file mode 100644
index 0000000..cdac6f3
--- /dev/null
+++ b/kexec/firmware_memmap.c
@@ -0,0 +1,266 @@
+/*
+ * firmware_memmap.c: Read /sys/firmware/memmap
+ *
+ * Created by: Bernhard Walle (bwalle@suse.de)
+ * Copyright (C) SUSE LINUX Products GmbH, 2008. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#define _GNU_SOURCE /* for ULLONG_MAX without C99 */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "firmware_memmap.h"
+#include "kexec.h"
+
+/**
+ * The full path to the sysfs interface that provides the memory map.
+ */
+#define FIRMWARE_MEMMAP_DIR  "/sys/firmware/memmap"
+
+/**
+ * Parses a file that only contains one number. Typical for sysfs files.
+ *
+ * @param[in] filename the name of the file that should be parsed
+ * @return the value that has been read or ULLONG_MAX on error.
+ */
+static unsigned long long parse_numeric_sysfs(const char *filename)
+{
+	FILE *fp;
+	char linebuffer[BUFSIZ];
+	unsigned long long retval;
+
+	fp = fopen(filename, "r");
+	if (!fp) {
+		fprintf(stderr, "Opening \"%s\" failed: %s\n",
+			filename, strerror(errno));
+		return ULLONG_MAX;
+	}
+
+	fgets(linebuffer, BUFSIZ, fp);
+	linebuffer[BUFSIZ-1] = 0;
+
+	/* let strtoll() detect the base */
+	retval = strtoll(linebuffer, NULL, 0);
+
+	fclose(fp);
+
+	return retval;
+}
+
+/**
+ * Reads the contents of a one-line sysfs file to buffer. (This function is
+ * not threadsafe.)
+ *
+ * @param[in] filename the name of the file that should be read
+ *
+ * @return NULL on failure, a pointer to a static buffer (that should be copied
+ *         with strdup() if the caller plans to use it after next function call)
+ */
+static char *parse_string_sysfs(const char *filename)
+{
+	FILE *fp;
+	static char linebuffer[BUFSIZ];
+	char *end;
+
+	fp = fopen(filename, "r");
+	if (!fp) {
+		fprintf(stderr, "Opening \"%s\" failed: %s\n",
+			filename, strerror(errno));
+		return NULL;
+	}
+
+	fgets(linebuffer, BUFSIZ, fp);
+	linebuffer[BUFSIZ-1] = 0;
+
+	/* truncate trailing newline(s) */
+	end = linebuffer + strlen(linebuffer) - 1;
+	while (*end == '\n')
+		*end-- = 0;
+
+	fclose(fp);
+
+	return linebuffer;
+
+}
+
+static int parse_memmap_entry(const char *entry, struct memory_range *range)
+{
+	char filename[PATH_MAX];
+	char *type;
+
+	/*
+	 * entry/start
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "start");
+	filename[PATH_MAX-1] = 0;
+
+	range->start = parse_numeric_sysfs(filename);
+	if (range->start == ULLONG_MAX)
+		return -1;
+
+	/*
+	 * entry/end
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "end");
+	filename[PATH_MAX-1] = 0;
+
+	range->end = parse_numeric_sysfs(filename);
+	if (range->end == ULLONG_MAX)
+		return -1;
+	range->end++; /* inclusive vs. exclusive ranges */
+
+	/*
+	 * entry/type
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "type");
+	filename[PATH_MAX-1] = 0;
+
+	type = parse_string_sysfs(filename);
+	if (!type)
+		return -1;
+
+	if (strcmp(type, "System RAM") == 0)
+		range->type = RANGE_RAM;
+	else if (strcmp(type, "ACPI Tables") == 0)
+		range->type = RANGE_ACPI;
+	else if (strcmp(type, "reserved") == 0)
+		range->type = RANGE_RESERVED;
+	else if (strcmp(type, "ACPI Non-volatile Storage") == 0)
+		range->type = RANGE_ACPI_NVS;
+	else {
+		fprintf(stderr, "Unknown type (%s) while parsing %s. Please "
+			"report this as bug. Using RANGE_RESERVED now.\n",
+			type, filename);
+		range->type = RANGE_RESERVED;
+	}
+
+	return 0;
+}
+
+/**
+ * Compares two memory ranges according to their start address. This function
+ * can be used with qsort() as @c compar function.
+ *
+ * @param[in] first a pointer to the first memory range
+ * @param[in] second a pointer to the second memory range
+ * @return 0 if @p first and @p second have the same start address,
+ *         a value less then 0 if the start address of @p first is less than
+ *         the start address of @p second, and a value greater than 0 if
+ *         the opposite is in case.
+ */
+static int compare_ranges(const void *first, const void *second)
+{
+	const struct memory_range *first_range = first;
+	const struct memory_range *second_range = second;
+
+	/*
+	 * don't use the "first_range->start - second_range->start"
+	 * notation because unsigned long long might overflow
+	 */
+	if (first_range->start > second_range->start)
+		return 1;
+	else if (first_range->start < second_range->start)
+		return -1;
+	else /* first_range->start == second_range->start */
+		return 0;
+}
+
+/* documentation: firmware_memmap.h */
+int have_sys_firmware_memmap(void)
+{
+	int ret;
+	struct stat mystat;
+
+	ret = stat(FIRMWARE_MEMMAP_DIR, &mystat);
+	if (ret != 0)
+		return 0;
+
+	return S_ISDIR(mystat.st_mode);
+}
+
+/* documentation: firmware_memmap.h */
+int get_firmware_memmap_ranges(struct memory_range *range, size_t *ranges)
+{
+	DIR *firmware_memmap_dir = NULL;
+	struct dirent *dirent;
+	int i = 0;
+
+	/* argument checking */
+	if (!range || !ranges) {
+		fprintf(stderr, "%s: Invalid arguments.\n", __FUNCTION__);
+		return -1;
+	}
+
+	/* open the directory */
+	firmware_memmap_dir = opendir(FIRMWARE_MEMMAP_DIR);
+	if (!firmware_memmap_dir) {
+		perror("Could not open \"" FIRMWARE_MEMMAP_DIR "\"");
+		goto error;
+	}
+
+	/* parse the entries */
+	while ((dirent = readdir(firmware_memmap_dir)) != NULL) {
+		int ret;
+		char full_path[PATH_MAX];
+
+		/* array overflow check */
+		if ((size_t)i >= *ranges) {
+			fprintf(stderr, "The firmware provides more entries "
+				"allowed (%d). Please report that as bug.\n",
+				*ranges);
+			goto error;
+		}
+
+		/* exclude '.' and '..' */
+		if (dirent->d_name[0] && dirent->d_name[0] == '.') {
+			continue;
+		}
+
+		snprintf(full_path, PATH_MAX, "%s/%s", FIRMWARE_MEMMAP_DIR,
+			dirent->d_name);
+		full_path[PATH_MAX-1] = 0;
+		ret = parse_memmap_entry(full_path, &range[i]);
+		if (ret < 0) {
+			goto error;
+		}
+
+		i++;
+	}
+
+	/* close the dir as we don't need it any more */
+	closedir(firmware_memmap_dir);
+
+	/* update the number of ranges for the caller */
+	*ranges = i;
+
+	/* and finally sort the entries with qsort */
+	qsort(range, *ranges, sizeof(struct memory_range), compare_ranges);
+
+	return 0;
+
+error:
+	if (firmware_memmap_dir) {
+		closedir(firmware_memmap_dir);
+	}
+	return -1;
+}
+
diff --git a/kexec/firmware_memmap.h b/kexec/firmware_memmap.h
new file mode 100644
index 0000000..41c3b3f
--- /dev/null
+++ b/kexec/firmware_memmap.h
@@ -0,0 +1,63 @@
+/*
+ * firmware_memmap.c: Read /sys/firmware/memmap
+ *
+ * Created by: Bernhard Walle (bwalle@suse.de)
+ * Copyright (C) SUSE LINUX Products GmbH, 2008. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef FIRMWARE_MEMMAP_H
+#define FIRMWARE_MEMMAP_H
+
+#include "kexec.h"
+
+/**
+ * Reads the /sys/firmware/memmap interface, documented in
+ * Documentation/ABI/testing/sysfs-firmware-memmap (kernel tree).
+ *
+ * The difference between /proc/iomem and /sys/firmware/memmap is that
+ * /sys/firmware/memmap provides the raw memory map, provided by the
+ * firmware of the system. That memory map should be passed to a kexec'd
+ * kernel because the behaviour should be the same as a normal booted kernel,
+ * so any limitation (e.g. by the user providing the mem command line option)
+ * should not be passed to the kexec'd kernel.
+ *
+ * The parsing of the code is independent of the architecture. However, the
+ * actual architecture-specific code might postprocess the code a bit, like
+ * x86 does.
+ */
+
+/**
+ * Checks if the kernel provides the /sys/firmware/memmap interface.
+ * It makes sense to use that function in advance before calling
+ * get_firmware_memmap_ranges() because the latter function prints an error
+ * if it cannot open the directory. If have_sys_firmware_memmap() returns
+ * false, then one can use the old /proc/iomem interface (for older kernels).
+ */
+int have_sys_firmware_memmap(void);
+
+/**
+ * Parses the /sys/firmware/memmap memory map.
+ *
+ * @param[out] range a pointer to an array of type struct memory_range with
+ *             at least *range entries
+ * @param[in,out] ranges a pointer to an integer that holds the number of
+ *        	  entries which range contains (at least). After successful
+ *        	  return, the number of actual entries will be written.
+ * @return 0 on success, -1 on failure.
+ */
+int get_firmware_memmap_ranges(struct memory_range *range, size_t *ranges);
+
+
+#endif /* FIRMWARE_MEMMAP_H */
-- 
1.5.6


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs()
  2008-07-07  7:06   ` Simon Horman
  2008-07-07 14:43     ` Bernhard Walle
  2008-07-07 14:43     ` [PATCH 1/3] " Bernhard Walle
@ 2008-07-07 14:43     ` Bernhard Walle
  2008-07-09  0:41       ` Simon Horman
  2008-07-07 14:43     ` [PATCH 3/3] Use get_memory_ranges() on x86-64 Bernhard Walle
  3 siblings, 1 reply; 21+ messages in thread
From: Bernhard Walle @ 2008-07-07 14:43 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle

With the previous patch, we have a duplication between that both functions
for following tasks:

 - don't report the interrupt table as RAM,
 - set the mem_min and mem_max limits for kdump.

This patch removes that redundancy into the function get_memory_ranges()
that calls both functions internally.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
 kexec/arch/i386/kexec-x86.c |   96 ++++++++++++++++---------------------------
 kexec/firmware_memmap.c     |    7 +++
 2 files changed, 43 insertions(+), 60 deletions(-)

diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 554c154..d5b6737 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -41,13 +41,10 @@ static struct memory_range memory_range[MAX_MEMORY_RANGES];
  * @param[out] range pointer that will be set to an array that holds the
  *             memory ranges
  * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
  *
  * @return 0 on success, any other value on failure.
  */
-static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges,
-					unsigned long kexec_flags)
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
 {
 	const char *iomem= proc_iomem();
 	int memory_ranges = 0;
@@ -89,27 +86,9 @@ static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges
 		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
 			type = RANGE_ACPI_NVS;
 		}
-		else if (memcmp(str, "Crash kernel\n", 13) == 0) {
-		/* Redefine the memory region boundaries if kernel
-		 * exports the limits and if it is panic kernel.
-		 * Override user values only if kernel exported values are
-		 * subset of user defined values.
-		 */
-			if (kexec_flags & KEXEC_ON_CRASH) {
-				if (start > mem_min)
-					mem_min = start;
-				if (end < mem_max)
-					mem_max = end;
-			}
-			continue;
-		}
 		else {
 			continue;
 		}
-		/* Don't report the interrupt table as ram */
-		if (type == RANGE_RAM && (start < 0x100)) {
-			start = 0x100;
-		}
 		memory_range[memory_ranges].start = start;
 		memory_range[memory_ranges].end = end;
 		memory_range[memory_ranges].type = type;
@@ -132,52 +111,19 @@ static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges
  * @param[out] range pointer that will be set to an array that holds the
  *             memory ranges
  * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
  *
  * @return 0 on success, any other value on failure.
  */
-static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
-				   unsigned long kexec_flags)
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
 {
 	int ret;
-	size_t i;
 	size_t range_number = MAX_MEMORY_RANGES;
-	unsigned long long start, end;
 
 	ret = get_firmware_memmap_ranges(memory_range, &range_number);
 	if (ret != 0) {
 		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
 			"Falling back to /proc/iomem.\n");
-		return get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
-	}
-
-	/* Don't report the interrupt table as ram */
-	for (i = 0; i < range_number; i++) {
-		if (memory_range[i].type == RANGE_RAM &&
-				(memory_range[i].start < 0x100)) {
-			memory_range[i].start = 0x100;
-			break;
-		}
-	}
-
-	/*
-	 * Redefine the memory region boundaries if kernel
-	 * exports the limits and if it is panic kernel.
-	 * Override user values only if kernel exported values are
-	 * subset of user defined values.
-	 */
-	if (kexec_flags & KEXEC_ON_CRASH) {
-		ret = parse_iomem_single("Crash kernel\n", &start, &end);
-		if (ret != 0) {
-			fprintf(stderr, "parse_iomem_single failed.\n");
-			return -1;
-		}
-
-		if (start > mem_min)
-			mem_min = start;
-		if (end < mem_max)
-			mem_max = end;
+		return get_memory_ranges_proc_iomem(range, ranges);
 	}
 
 	*range = memory_range;
@@ -203,12 +149,12 @@ static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
 int get_memory_ranges(struct memory_range **range, int *ranges,
 		      unsigned long kexec_flags)
 {
-	int ret;
+	int ret, i;
 
 	if (have_sys_firmware_memmap())
-		ret = get_memory_ranges_sysfs(range, ranges,kexec_flags);
+		ret = get_memory_ranges_sysfs(range, ranges);
 	else
-		ret = get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+		ret = get_memory_ranges_proc_iomem(range, ranges);
 
 	/*
 	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
@@ -217,6 +163,36 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 	if (ret != 0)
 		return ret;
 
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < *ranges; i++) {
+		if ((*range)[i].type == RANGE_RAM &&
+				((*range)[i].start < 0x100)) {
+			(*range)[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		unsigned long long start, end;
+
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
 	/* just set 0 to 1 to enable printing for debugging */
 #if 0
 	{
diff --git a/kexec/firmware_memmap.c b/kexec/firmware_memmap.c
index cdac6f3..2ad450d 100644
--- a/kexec/firmware_memmap.c
+++ b/kexec/firmware_memmap.c
@@ -31,6 +31,13 @@
 #include "firmware_memmap.h"
 #include "kexec.h"
 
+/*
+ * If the system is too old for ULLONG_MAX, define it here.
+ */
+#ifndef ULLONG_MAX
+#    define ULLONG_MAX (~0ULL)
+#endif
+
 /**
  * The full path to the sysfs interface that provides the memory map.
  */
-- 
1.5.6


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/3] Use get_memory_ranges() on x86-64.
  2008-07-07  7:06   ` Simon Horman
                       ` (2 preceding siblings ...)
  2008-07-07 14:43     ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
@ 2008-07-07 14:43     ` Bernhard Walle
  3 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-07 14:43 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle

Because the get_memory_ranges() function was the same on i386 and x86_64, and
because that /sys/firmware/memmap interface should also be used for x86_64
without *new* code duplication, that part was moved out in a new file called
kexec-x86-common.c. That file only contains the memory map parsing for both the
"old" /proc/iomem interface and the new /sys/firmware/memmap interface.

That file is now built for i386 and x86_64.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
 kexec/arch/i386/Makefile           |    1 +
 kexec/arch/i386/kexec-x86-common.c |  207 ++++++++++++++++++++++++++++++++++++
 kexec/arch/i386/kexec-x86.c        |  175 ------------------------------
 kexec/arch/x86_64/Makefile         |    1 +
 kexec/arch/x86_64/kexec-x86_64.c   |   83 --------------
 5 files changed, 209 insertions(+), 258 deletions(-)
 create mode 100644 kexec/arch/i386/kexec-x86-common.c

diff --git a/kexec/arch/i386/Makefile b/kexec/arch/i386/Makefile
index f2d9636..d52a2f5 100644
--- a/kexec/arch/i386/Makefile
+++ b/kexec/arch/i386/Makefile
@@ -2,6 +2,7 @@
 # kexec i386 (linux booting linux)
 #
 i386_KEXEC_SRCS =  kexec/arch/i386/kexec-x86.c
+i386_KEXEC_SRCS += kexec/arch/i386/kexec-x86-common.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-elf-x86.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-elf-rel-x86.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-bzImage.c
diff --git a/kexec/arch/i386/kexec-x86-common.c b/kexec/arch/i386/kexec-x86-common.c
new file mode 100644
index 0000000..4533425
--- /dev/null
+++ b/kexec/arch/i386/kexec-x86-common.c
@@ -0,0 +1,207 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "../../kexec.h"
+#include "../../kexec-syscall.h"
+#include "../../firmware_memmap.h"
+#include "kexec-x86.h"
+
+static struct memory_range memory_range[MAX_MEMORY_RANGES];
+
+/**
+ * The old /proc/iomem parsing code.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
+{
+	const char *iomem= proc_iomem();
+	int memory_ranges = 0;
+	char line[MAX_LINE];
+	FILE *fp;
+	fp = fopen(iomem, "r");
+	if (!fp) {
+		fprintf(stderr, "Cannot open %s: %s\n",
+			iomem, strerror(errno));
+		return -1;
+	}
+	while(fgets(line, sizeof(line), fp) != 0) {
+		unsigned long long start, end;
+		char *str;
+		int type;
+		int consumed;
+		int count;
+		if (memory_ranges >= MAX_MEMORY_RANGES)
+			break;
+		count = sscanf(line, "%Lx-%Lx : %n",
+			&start, &end, &consumed);
+		if (count != 2)
+			continue;
+		str = line + consumed;
+		end = end + 1;
+#if 0
+		printf("%016Lx-%016Lx : %s",
+			start, end, str);
+#endif
+		if (memcmp(str, "System RAM\n", 11) == 0) {
+			type = RANGE_RAM;
+		}
+		else if (memcmp(str, "reserved\n", 9) == 0) {
+			type = RANGE_RESERVED;
+		}
+		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
+			type = RANGE_ACPI;
+		}
+		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
+			type = RANGE_ACPI_NVS;
+		}
+		else {
+			continue;
+		}
+		memory_range[memory_ranges].start = start;
+		memory_range[memory_ranges].end = end;
+		memory_range[memory_ranges].type = type;
+#if 0
+		printf("%016Lx-%016Lx : %x\n",
+			start, end, type);
+#endif
+		memory_ranges++;
+	}
+	fclose(fp);
+	*range = memory_range;
+	*ranges = memory_ranges;
+	return 0;
+}
+
+/**
+ * Calls the architecture independent get_firmware_memmap_ranges() to parse
+ * /sys/firmware/memmap and then do some x86 only modifications.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
+{
+	int ret;
+	size_t range_number = MAX_MEMORY_RANGES;
+
+	ret = get_firmware_memmap_ranges(memory_range, &range_number);
+	if (ret != 0) {
+		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
+			"Falling back to /proc/iomem.\n");
+		return get_memory_ranges_proc_iomem(range, ranges);
+	}
+
+	*range = memory_range;
+	*ranges = range_number;
+
+	return 0;
+}
+
+/**
+ * Return a sorted list of memory ranges.
+ *
+ * If we have the /sys/firmware/memmap interface, then use that. If not,
+ * or if parsing of that fails, use /proc/iomem as fallback.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+int get_memory_ranges(struct memory_range **range, int *ranges,
+		      unsigned long kexec_flags)
+{
+	int ret, i;
+
+	if (have_sys_firmware_memmap())
+		ret = get_memory_ranges_sysfs(range, ranges);
+	else
+		ret = get_memory_ranges_proc_iomem(range, ranges);
+
+	/*
+	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
+	 * have already printed an error message, so fail silently here
+	 */
+	if (ret != 0)
+		return ret;
+
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < *ranges; i++) {
+		if ((*range)[i].type == RANGE_RAM &&
+				((*range)[i].start < 0x100)) {
+			(*range)[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		unsigned long long start, end;
+
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
+	/* just set 0 to 1 to enable printing for debugging */
+#if 0
+	{
+		int i;
+		printf("MEMORY RANGES\n");
+		for (i = 0; i < *ranges; i++) {
+			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
+				(*range)[i].end, (*range)[i].type);
+		}
+	}
+#endif
+
+	return ret;
+}
+
+
diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index d5b6737..d33a14b 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -33,181 +33,6 @@
 #include "crashdump-x86.h"
 #include <arch/options.h>
 
-static struct memory_range memory_range[MAX_MEMORY_RANGES];
-
-/**
- * The old /proc/iomem parsing code.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- *
- * @return 0 on success, any other value on failure.
- */
-static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
-{
-	const char *iomem= proc_iomem();
-	int memory_ranges = 0;
-	char line[MAX_LINE];
-	FILE *fp;
-	fp = fopen(iomem, "r");
-	if (!fp) {
-		fprintf(stderr, "Cannot open %s: %s\n",
-			iomem, strerror(errno));
-		return -1;
-	}
-	while(fgets(line, sizeof(line), fp) != 0) {
-		unsigned long long start, end;
-		char *str;
-		int type;
-		int consumed;
-		int count;
-		if (memory_ranges >= MAX_MEMORY_RANGES)
-			break;
-		count = sscanf(line, "%Lx-%Lx : %n",
-			&start, &end, &consumed);
-		if (count != 2)
-			continue;
-		str = line + consumed;
-		end = end + 1;
-#if 0
-		printf("%016Lx-%016Lx : %s",
-			start, end, str);
-#endif
-		if (memcmp(str, "System RAM\n", 11) == 0) {
-			type = RANGE_RAM;
-		}
-		else if (memcmp(str, "reserved\n", 9) == 0) {
-			type = RANGE_RESERVED;
-		}
-		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
-			type = RANGE_ACPI;
-		}
-		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
-			type = RANGE_ACPI_NVS;
-		}
-		else {
-			continue;
-		}
-		memory_range[memory_ranges].start = start;
-		memory_range[memory_ranges].end = end;
-		memory_range[memory_ranges].type = type;
-#if 0
-		printf("%016Lx-%016Lx : %x\n",
-			start, end, type);
-#endif
-		memory_ranges++;
-	}
-	fclose(fp);
-	*range = memory_range;
-	*ranges = memory_ranges;
-	return 0;
-}
-
-/**
- * Calls the architecture independent get_firmware_memmap_ranges() to parse
- * /sys/firmware/memmap and then do some x86 only modifications.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- *
- * @return 0 on success, any other value on failure.
- */
-static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
-{
-	int ret;
-	size_t range_number = MAX_MEMORY_RANGES;
-
-	ret = get_firmware_memmap_ranges(memory_range, &range_number);
-	if (ret != 0) {
-		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
-			"Falling back to /proc/iomem.\n");
-		return get_memory_ranges_proc_iomem(range, ranges);
-	}
-
-	*range = memory_range;
-	*ranges = range_number;
-
-	return 0;
-}
-
-/**
- * Return a sorted list of memory ranges.
- *
- * If we have the /sys/firmware/memmap interface, then use that. If not,
- * or if parsing of that fails, use /proc/iomem as fallback.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
- *
- * @return 0 on success, any other value on failure.
- */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-		      unsigned long kexec_flags)
-{
-	int ret, i;
-
-	if (have_sys_firmware_memmap())
-		ret = get_memory_ranges_sysfs(range, ranges);
-	else
-		ret = get_memory_ranges_proc_iomem(range, ranges);
-
-	/*
-	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
-	 * have already printed an error message, so fail silently here
-	 */
-	if (ret != 0)
-		return ret;
-
-	/* Don't report the interrupt table as ram */
-	for (i = 0; i < *ranges; i++) {
-		if ((*range)[i].type == RANGE_RAM &&
-				((*range)[i].start < 0x100)) {
-			(*range)[i].start = 0x100;
-			break;
-		}
-	}
-
-	/*
-	 * Redefine the memory region boundaries if kernel
-	 * exports the limits and if it is panic kernel.
-	 * Override user values only if kernel exported values are
-	 * subset of user defined values.
-	 */
-	if (kexec_flags & KEXEC_ON_CRASH) {
-		unsigned long long start, end;
-
-		ret = parse_iomem_single("Crash kernel\n", &start, &end);
-		if (ret != 0) {
-			fprintf(stderr, "parse_iomem_single failed.\n");
-			return -1;
-		}
-
-		if (start > mem_min)
-			mem_min = start;
-		if (end < mem_max)
-			mem_max = end;
-	}
-
-	/* just set 0 to 1 to enable printing for debugging */
-#if 0
-	{
-		int i;
-		printf("MEMORY RANGES\n");
-		for (i = 0; i < *ranges; i++) {
-			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
-				(*range)[i].end, (*range)[i].type);
-		}
-	}
-#endif
-
-	return ret;
-}
-
 struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
diff --git a/kexec/arch/x86_64/Makefile b/kexec/arch/x86_64/Makefile
index c59c41f..7ca3e7e 100644
--- a/kexec/arch/x86_64/Makefile
+++ b/kexec/arch/x86_64/Makefile
@@ -7,6 +7,7 @@ x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-multiboot-x86.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-beoboot-x86.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-nbi.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/x86-linux-setup.c
+x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-x86-common.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/crashdump-x86_64.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/kexec-x86_64.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/kexec-elf-x86_64.c
diff --git a/kexec/arch/x86_64/kexec-x86_64.c b/kexec/arch/x86_64/kexec-x86_64.c
index d0b3e90..9973815 100644
--- a/kexec/arch/x86_64/kexec-x86_64.c
+++ b/kexec/arch/x86_64/kexec-x86_64.c
@@ -32,89 +32,6 @@
 #include "crashdump-x86_64.h"
 #include <arch/options.h>
 
-#define MAX_MEMORY_RANGES 64
-static struct memory_range memory_range[MAX_MEMORY_RANGES];
-
-/* Return a sorted list of memory ranges. */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-					unsigned long kexec_flags)
-{
-	const char *iomem= proc_iomem();
-	int memory_ranges = 0;
-	char line[MAX_LINE];
-	FILE *fp;
-	fp = fopen(iomem, "r");
-	if (!fp) {
-		fprintf(stderr, "Cannot open %s: %s\n",
-			iomem, strerror(errno));
-		return -1;
-	}
-	while(fgets(line, sizeof(line), fp) != 0) {
-		unsigned long long start, end;
-		char *str;
-		int type;
-		int consumed;
-		int count;
-		if (memory_ranges >= MAX_MEMORY_RANGES)
-			break;
-		count = sscanf(line, "%Lx-%Lx : %n",
-			&start, &end, &consumed);
-		if (count != 2)
-			continue;
-		str = line + consumed;
-		end = end + 1;
-#ifdef DEBUG
-		printf("%016Lx-%016Lx : %s",
-			start, end, str);
-#endif
-		if (memcmp(str, "System RAM\n", 11) == 0) {
-			type = RANGE_RAM;
-		}
-		else if (memcmp(str, "reserved\n", 9) == 0) {
-			type = RANGE_RESERVED;
-		}
-		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
-			type = RANGE_ACPI;
-		}
-		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
-			type = RANGE_ACPI_NVS;
-		}
-		else if (memcmp(str, "Crash kernel\n", 13) == 0) {
-			/* Redefine the memory region boundaries if kernel
-			 * exports the limits and if it is panic kernel.
-			 * Override user values only if kernel exported
-			 * values are subset of user defined values.
-			 */
-			if (kexec_flags & KEXEC_ON_CRASH) {
-				if (start > mem_min)
-					mem_min = start;
-				if (end < mem_max)
-					mem_max = end;
-			}
-			continue;
-		}
-		else {
-			continue;
-		}
-		/* Don't report the interrupt table as ram */
-		if (type == RANGE_RAM && (start < 0x100)) {
-			start = 0x100;
-		}
-		memory_range[memory_ranges].start = start;
-		memory_range[memory_ranges].end = end;
-		memory_range[memory_ranges].type = type;
-#ifdef DEBUG
-		printf("%016Lx-%016Lx : %x\n",
-			start, end, type);
-#endif
-		memory_ranges++;
-	}
-	fclose(fp);
-	*range = memory_range;
-	*ranges = memory_ranges;
-	return 0;
-}
-
 struct file_type file_type[] = {
 	{ "elf-x86_64", elf_x86_64_probe, elf_x86_64_load, elf_x86_64_usage },
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
-- 
1.5.6


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs()
  2008-07-07 14:43     ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
@ 2008-07-09  0:41       ` Simon Horman
  2008-07-09 11:10         ` Parse /sys/firmware/memmap Bernhard Walle
                           ` (4 more replies)
  0 siblings, 5 replies; 21+ messages in thread
From: Simon Horman @ 2008-07-09  0:41 UTC (permalink / raw)
  To: Bernhard Walle; +Cc: kexec

On Mon, Jul 07, 2008 at 04:43:41PM +0200, Bernhard Walle wrote:
> With the previous patch, we have a duplication between that both functions
> for following tasks:
> 
>  - don't report the interrupt table as RAM,
>  - set the mem_min and mem_max limits for kdump.
> 
> This patch removes that redundancy into the function get_memory_ranges()
> that calls both functions internally.

Hi Bernhard,

these patches seem fine to me, but I am still having minor troubles
with missing defines. For the record, I am seeing the problems with
gcc-3.4.5 + glibc-2.3.6. Yes, I know this is old, but it would
be nice if this minor issue didn't break it.

1. The snippet below looks good, but it needs to be included
   in or berfore " [PATCH 1/3] Parse /sys/firmware/memmap".

> diff --git a/kexec/firmware_memmap.c b/kexec/firmware_memmap.c
> index cdac6f3..2ad450d 100644
> --- a/kexec/firmware_memmap.c
> +++ b/kexec/firmware_memmap.c
> @@ -31,6 +31,13 @@
>  #include "firmware_memmap.h"
>  #include "kexec.h"
>  
> +/*
> + * If the system is too old for ULLONG_MAX, define it here.
> + */
> +#ifndef ULLONG_MAX
> +#    define ULLONG_MAX (~0ULL)
> +#endif
> +
>  /**
>   * The full path to the sysfs interface that provides the memory map.
>   */

2. I did not realise this at the time that I sent my previous response,
   but LLONG_MAX is also a problem. I believe that the following
   code, based on your code above, fixes the problem.

/*
 * If the system is too old for LLONG_MAX, define it here.
 */
#ifndef LLONG_MAX
#define LLONG_MAX     (~0ULL >> 1)
#endif

I have verified on i386 using gcc-3.4.5 + glibc-2.3.6 and gcc-4.3.1 +
glibc-2.7 that this value is 9223372036854775807 (=2^63-1), which is
what the latter provides as LLONG_MAX.

Just for good measure, I have also verified, using the same method, that
your code gives 18446744073709551615 (=2^64-1), which matches the value
internally provided by gcc-4.3.1 + glibc-2.7.

-- 
Horms


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Parse /sys/firmware/memmap
  2008-07-09  0:41       ` Simon Horman
@ 2008-07-09 11:10         ` Bernhard Walle
  2008-07-09 11:11         ` [PATCH 1/3] " Bernhard Walle
                           ` (3 subsequent siblings)
  4 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-09 11:10 UTC (permalink / raw)
  To: kexec

Define ULLONG_MAX and define LLONG_MAX. Both now in the first patch.  The rest
is the same.



_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/3] Parse /sys/firmware/memmap.
  2008-07-09  0:41       ` Simon Horman
  2008-07-09 11:10         ` Parse /sys/firmware/memmap Bernhard Walle
@ 2008-07-09 11:11         ` Bernhard Walle
  2008-07-10 23:29           ` Simon Horman
  2008-07-09 11:11         ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
                           ` (2 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: Bernhard Walle @ 2008-07-09 11:11 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle

After the patch that provides /sys/firmware/memmap has been merged in the 'tip'
tree by Ingo Molnar, kexec should use that interface.

This patch implements architecture-independent parsing in a new file called
firmware_memmap.c. The x86 part is ported to use that memory map for
kexec. We don't use that memory map for building the ELF core headers,
that was the intention for that new interface.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
 kexec/Makefile              |    1 +
 kexec/arch/i386/kexec-x86.c |  124 +++++++++++++++++++-
 kexec/firmware_memmap.c     |  278 +++++++++++++++++++++++++++++++++++++++++++
 kexec/firmware_memmap.h     |   63 ++++++++++
 4 files changed, 463 insertions(+), 3 deletions(-)
 create mode 100644 kexec/firmware_memmap.c
 create mode 100644 kexec/firmware_memmap.h

diff --git a/kexec/Makefile b/kexec/Makefile
index a80b940..3a00114 100644
--- a/kexec/Makefile
+++ b/kexec/Makefile
@@ -18,6 +18,7 @@ KEXEC_SRCS += kexec/kexec-elf-core.c
 KEXEC_SRCS += kexec/kexec-elf-rel.c
 KEXEC_SRCS += kexec/kexec-elf-boot.c
 KEXEC_SRCS += kexec/kexec-iomem.c
+KEXEC_SRCS += kexec/firmware_memmap.c
 KEXEC_SRCS += kexec/crashdump.c
 KEXEC_SRCS += kexec/crashdump-xen.c
 KEXEC_SRCS += kexec/phys_arch.c
diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 8c8ba7f..554c154 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -28,15 +28,26 @@
 #include "../../kexec.h"
 #include "../../kexec-elf.h"
 #include "../../kexec-syscall.h"
+#include "../../firmware_memmap.h"
 #include "kexec-x86.h"
 #include "crashdump-x86.h"
 #include <arch/options.h>
 
 static struct memory_range memory_range[MAX_MEMORY_RANGES];
 
-/* Return a sorted list of memory ranges. */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-				unsigned long kexec_flags)
+/**
+ * The old /proc/iomem parsing code.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges,
+					unsigned long kexec_flags)
 {
 	const char *iomem= proc_iomem();
 	int memory_ranges = 0;
@@ -114,6 +125,113 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 	return 0;
 }
 
+/**
+ * Calls the architecture independent get_firmware_memmap_ranges() to parse
+ * /sys/firmware/memmap and then do some x86 only modifications.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
+				   unsigned long kexec_flags)
+{
+	int ret;
+	size_t i;
+	size_t range_number = MAX_MEMORY_RANGES;
+	unsigned long long start, end;
+
+	ret = get_firmware_memmap_ranges(memory_range, &range_number);
+	if (ret != 0) {
+		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
+			"Falling back to /proc/iomem.\n");
+		return get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+	}
+
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < range_number; i++) {
+		if (memory_range[i].type == RANGE_RAM &&
+				(memory_range[i].start < 0x100)) {
+			memory_range[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
+	*range = memory_range;
+	*ranges = range_number;
+
+	return 0;
+}
+
+/**
+ * Return a sorted list of memory ranges.
+ *
+ * If we have the /sys/firmware/memmap interface, then use that. If not,
+ * or if parsing of that fails, use /proc/iomem as fallback.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+int get_memory_ranges(struct memory_range **range, int *ranges,
+		      unsigned long kexec_flags)
+{
+	int ret;
+
+	if (have_sys_firmware_memmap())
+		ret = get_memory_ranges_sysfs(range, ranges,kexec_flags);
+	else
+		ret = get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+
+	/*
+	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
+	 * have already printed an error message, so fail silently here
+	 */
+	if (ret != 0)
+		return ret;
+
+	/* just set 0 to 1 to enable printing for debugging */
+#if 0
+	{
+		int i;
+		printf("MEMORY RANGES\n");
+		for (i = 0; i < *ranges; i++) {
+			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
+				(*range)[i].end, (*range)[i].type);
+		}
+	}
+#endif
+
+	return ret;
+}
+
 struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
diff --git a/kexec/firmware_memmap.c b/kexec/firmware_memmap.c
new file mode 100644
index 0000000..b0d4f62
--- /dev/null
+++ b/kexec/firmware_memmap.c
@@ -0,0 +1,278 @@
+/*
+ * firmware_memmap.c: Read /sys/firmware/memmap
+ *
+ * Created by: Bernhard Walle (bwalle@suse.de)
+ * Copyright (C) SUSE LINUX Products GmbH, 2008. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#define _GNU_SOURCE /* for ULLONG_MAX without C99 */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "firmware_memmap.h"
+#include "kexec.h"
+
+/*
+ * If the system is too old for ULLONG_MAX or LLONG_MAX, define it here.
+ */
+#ifndef ULLONG_MAX
+#    define ULLONG_MAX (~0ULL)
+#endif /* ULLONG_MAX */
+
+#ifndef LLONG_MAX
+#    define LLONG_MAX (~0ULL >> 1)
+#endif /* LLONG_MAX */
+
+
+/**
+ * The full path to the sysfs interface that provides the memory map.
+ */
+#define FIRMWARE_MEMMAP_DIR  "/sys/firmware/memmap"
+
+/**
+ * Parses a file that only contains one number. Typical for sysfs files.
+ *
+ * @param[in] filename the name of the file that should be parsed
+ * @return the value that has been read or ULLONG_MAX on error.
+ */
+static unsigned long long parse_numeric_sysfs(const char *filename)
+{
+	FILE *fp;
+	char linebuffer[BUFSIZ];
+	unsigned long long retval;
+
+	fp = fopen(filename, "r");
+	if (!fp) {
+		fprintf(stderr, "Opening \"%s\" failed: %s\n",
+			filename, strerror(errno));
+		return ULLONG_MAX;
+	}
+
+	fgets(linebuffer, BUFSIZ, fp);
+	linebuffer[BUFSIZ-1] = 0;
+
+	/* let strtoll() detect the base */
+	retval = strtoll(linebuffer, NULL, 0);
+
+	fclose(fp);
+
+	return retval;
+}
+
+/**
+ * Reads the contents of a one-line sysfs file to buffer. (This function is
+ * not threadsafe.)
+ *
+ * @param[in] filename the name of the file that should be read
+ *
+ * @return NULL on failure, a pointer to a static buffer (that should be copied
+ *         with strdup() if the caller plans to use it after next function call)
+ */
+static char *parse_string_sysfs(const char *filename)
+{
+	FILE *fp;
+	static char linebuffer[BUFSIZ];
+	char *end;
+
+	fp = fopen(filename, "r");
+	if (!fp) {
+		fprintf(stderr, "Opening \"%s\" failed: %s\n",
+			filename, strerror(errno));
+		return NULL;
+	}
+
+	fgets(linebuffer, BUFSIZ, fp);
+	linebuffer[BUFSIZ-1] = 0;
+
+	/* truncate trailing newline(s) */
+	end = linebuffer + strlen(linebuffer) - 1;
+	while (*end == '\n')
+		*end-- = 0;
+
+	fclose(fp);
+
+	return linebuffer;
+
+}
+
+static int parse_memmap_entry(const char *entry, struct memory_range *range)
+{
+	char filename[PATH_MAX];
+	char *type;
+
+	/*
+	 * entry/start
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "start");
+	filename[PATH_MAX-1] = 0;
+
+	range->start = parse_numeric_sysfs(filename);
+	if (range->start == ULLONG_MAX)
+		return -1;
+
+	/*
+	 * entry/end
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "end");
+	filename[PATH_MAX-1] = 0;
+
+	range->end = parse_numeric_sysfs(filename);
+	if (range->end == ULLONG_MAX)
+		return -1;
+	range->end++; /* inclusive vs. exclusive ranges */
+
+	/*
+	 * entry/type
+	 */
+	snprintf(filename, PATH_MAX, "%s/%s", entry, "type");
+	filename[PATH_MAX-1] = 0;
+
+	type = parse_string_sysfs(filename);
+	if (!type)
+		return -1;
+
+	if (strcmp(type, "System RAM") == 0)
+		range->type = RANGE_RAM;
+	else if (strcmp(type, "ACPI Tables") == 0)
+		range->type = RANGE_ACPI;
+	else if (strcmp(type, "reserved") == 0)
+		range->type = RANGE_RESERVED;
+	else if (strcmp(type, "ACPI Non-volatile Storage") == 0)
+		range->type = RANGE_ACPI_NVS;
+	else {
+		fprintf(stderr, "Unknown type (%s) while parsing %s. Please "
+			"report this as bug. Using RANGE_RESERVED now.\n",
+			type, filename);
+		range->type = RANGE_RESERVED;
+	}
+
+	return 0;
+}
+
+/**
+ * Compares two memory ranges according to their start address. This function
+ * can be used with qsort() as @c compar function.
+ *
+ * @param[in] first a pointer to the first memory range
+ * @param[in] second a pointer to the second memory range
+ * @return 0 if @p first and @p second have the same start address,
+ *         a value less then 0 if the start address of @p first is less than
+ *         the start address of @p second, and a value greater than 0 if
+ *         the opposite is in case.
+ */
+static int compare_ranges(const void *first, const void *second)
+{
+	const struct memory_range *first_range = first;
+	const struct memory_range *second_range = second;
+
+	/*
+	 * don't use the "first_range->start - second_range->start"
+	 * notation because unsigned long long might overflow
+	 */
+	if (first_range->start > second_range->start)
+		return 1;
+	else if (first_range->start < second_range->start)
+		return -1;
+	else /* first_range->start == second_range->start */
+		return 0;
+}
+
+/* documentation: firmware_memmap.h */
+int have_sys_firmware_memmap(void)
+{
+	int ret;
+	struct stat mystat;
+
+	ret = stat(FIRMWARE_MEMMAP_DIR, &mystat);
+	if (ret != 0)
+		return 0;
+
+	return S_ISDIR(mystat.st_mode);
+}
+
+/* documentation: firmware_memmap.h */
+int get_firmware_memmap_ranges(struct memory_range *range, size_t *ranges)
+{
+	DIR *firmware_memmap_dir = NULL;
+	struct dirent *dirent;
+	int i = 0;
+
+	/* argument checking */
+	if (!range || !ranges) {
+		fprintf(stderr, "%s: Invalid arguments.\n", __FUNCTION__);
+		return -1;
+	}
+
+	/* open the directory */
+	firmware_memmap_dir = opendir(FIRMWARE_MEMMAP_DIR);
+	if (!firmware_memmap_dir) {
+		perror("Could not open \"" FIRMWARE_MEMMAP_DIR "\"");
+		goto error;
+	}
+
+	/* parse the entries */
+	while ((dirent = readdir(firmware_memmap_dir)) != NULL) {
+		int ret;
+		char full_path[PATH_MAX];
+
+		/* array overflow check */
+		if ((size_t)i >= *ranges) {
+			fprintf(stderr, "The firmware provides more entries "
+				"allowed (%d). Please report that as bug.\n",
+				*ranges);
+			goto error;
+		}
+
+		/* exclude '.' and '..' */
+		if (dirent->d_name[0] && dirent->d_name[0] == '.') {
+			continue;
+		}
+
+		snprintf(full_path, PATH_MAX, "%s/%s", FIRMWARE_MEMMAP_DIR,
+			dirent->d_name);
+		full_path[PATH_MAX-1] = 0;
+		ret = parse_memmap_entry(full_path, &range[i]);
+		if (ret < 0) {
+			goto error;
+		}
+
+		i++;
+	}
+
+	/* close the dir as we don't need it any more */
+	closedir(firmware_memmap_dir);
+
+	/* update the number of ranges for the caller */
+	*ranges = i;
+
+	/* and finally sort the entries with qsort */
+	qsort(range, *ranges, sizeof(struct memory_range), compare_ranges);
+
+	return 0;
+
+error:
+	if (firmware_memmap_dir) {
+		closedir(firmware_memmap_dir);
+	}
+	return -1;
+}
+
diff --git a/kexec/firmware_memmap.h b/kexec/firmware_memmap.h
new file mode 100644
index 0000000..41c3b3f
--- /dev/null
+++ b/kexec/firmware_memmap.h
@@ -0,0 +1,63 @@
+/*
+ * firmware_memmap.c: Read /sys/firmware/memmap
+ *
+ * Created by: Bernhard Walle (bwalle@suse.de)
+ * Copyright (C) SUSE LINUX Products GmbH, 2008. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef FIRMWARE_MEMMAP_H
+#define FIRMWARE_MEMMAP_H
+
+#include "kexec.h"
+
+/**
+ * Reads the /sys/firmware/memmap interface, documented in
+ * Documentation/ABI/testing/sysfs-firmware-memmap (kernel tree).
+ *
+ * The difference between /proc/iomem and /sys/firmware/memmap is that
+ * /sys/firmware/memmap provides the raw memory map, provided by the
+ * firmware of the system. That memory map should be passed to a kexec'd
+ * kernel because the behaviour should be the same as a normal booted kernel,
+ * so any limitation (e.g. by the user providing the mem command line option)
+ * should not be passed to the kexec'd kernel.
+ *
+ * The parsing of the code is independent of the architecture. However, the
+ * actual architecture-specific code might postprocess the code a bit, like
+ * x86 does.
+ */
+
+/**
+ * Checks if the kernel provides the /sys/firmware/memmap interface.
+ * It makes sense to use that function in advance before calling
+ * get_firmware_memmap_ranges() because the latter function prints an error
+ * if it cannot open the directory. If have_sys_firmware_memmap() returns
+ * false, then one can use the old /proc/iomem interface (for older kernels).
+ */
+int have_sys_firmware_memmap(void);
+
+/**
+ * Parses the /sys/firmware/memmap memory map.
+ *
+ * @param[out] range a pointer to an array of type struct memory_range with
+ *             at least *range entries
+ * @param[in,out] ranges a pointer to an integer that holds the number of
+ *        	  entries which range contains (at least). After successful
+ *        	  return, the number of actual entries will be written.
+ * @return 0 on success, -1 on failure.
+ */
+int get_firmware_memmap_ranges(struct memory_range *range, size_t *ranges);
+
+
+#endif /* FIRMWARE_MEMMAP_H */
-- 
1.5.6


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs()
  2008-07-09  0:41       ` Simon Horman
  2008-07-09 11:10         ` Parse /sys/firmware/memmap Bernhard Walle
  2008-07-09 11:11         ` [PATCH 1/3] " Bernhard Walle
@ 2008-07-09 11:11         ` Bernhard Walle
  2008-07-09 11:11         ` [PATCH 3/3] Use get_memory_ranges() on x86-64 Bernhard Walle
  2008-07-09 11:12         ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
  4 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-09 11:11 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle

With the previous patch, we have a duplication between that both functions
for following tasks:

 - don't report the interrupt table as RAM,
 - set the mem_min and mem_max limits for kdump.

This patch removes that redundancy into the function get_memory_ranges()
that calls both functions internally.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
 kexec/arch/i386/kexec-x86.c |   96 ++++++++++++++++---------------------------
 1 files changed, 36 insertions(+), 60 deletions(-)

diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index 554c154..d5b6737 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -41,13 +41,10 @@ static struct memory_range memory_range[MAX_MEMORY_RANGES];
  * @param[out] range pointer that will be set to an array that holds the
  *             memory ranges
  * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
  *
  * @return 0 on success, any other value on failure.
  */
-static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges,
-					unsigned long kexec_flags)
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
 {
 	const char *iomem= proc_iomem();
 	int memory_ranges = 0;
@@ -89,27 +86,9 @@ static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges
 		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
 			type = RANGE_ACPI_NVS;
 		}
-		else if (memcmp(str, "Crash kernel\n", 13) == 0) {
-		/* Redefine the memory region boundaries if kernel
-		 * exports the limits and if it is panic kernel.
-		 * Override user values only if kernel exported values are
-		 * subset of user defined values.
-		 */
-			if (kexec_flags & KEXEC_ON_CRASH) {
-				if (start > mem_min)
-					mem_min = start;
-				if (end < mem_max)
-					mem_max = end;
-			}
-			continue;
-		}
 		else {
 			continue;
 		}
-		/* Don't report the interrupt table as ram */
-		if (type == RANGE_RAM && (start < 0x100)) {
-			start = 0x100;
-		}
 		memory_range[memory_ranges].start = start;
 		memory_range[memory_ranges].end = end;
 		memory_range[memory_ranges].type = type;
@@ -132,52 +111,19 @@ static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges
  * @param[out] range pointer that will be set to an array that holds the
  *             memory ranges
  * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
  *
  * @return 0 on success, any other value on failure.
  */
-static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
-				   unsigned long kexec_flags)
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
 {
 	int ret;
-	size_t i;
 	size_t range_number = MAX_MEMORY_RANGES;
-	unsigned long long start, end;
 
 	ret = get_firmware_memmap_ranges(memory_range, &range_number);
 	if (ret != 0) {
 		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
 			"Falling back to /proc/iomem.\n");
-		return get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
-	}
-
-	/* Don't report the interrupt table as ram */
-	for (i = 0; i < range_number; i++) {
-		if (memory_range[i].type == RANGE_RAM &&
-				(memory_range[i].start < 0x100)) {
-			memory_range[i].start = 0x100;
-			break;
-		}
-	}
-
-	/*
-	 * Redefine the memory region boundaries if kernel
-	 * exports the limits and if it is panic kernel.
-	 * Override user values only if kernel exported values are
-	 * subset of user defined values.
-	 */
-	if (kexec_flags & KEXEC_ON_CRASH) {
-		ret = parse_iomem_single("Crash kernel\n", &start, &end);
-		if (ret != 0) {
-			fprintf(stderr, "parse_iomem_single failed.\n");
-			return -1;
-		}
-
-		if (start > mem_min)
-			mem_min = start;
-		if (end < mem_max)
-			mem_max = end;
+		return get_memory_ranges_proc_iomem(range, ranges);
 	}
 
 	*range = memory_range;
@@ -203,12 +149,12 @@ static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges,
 int get_memory_ranges(struct memory_range **range, int *ranges,
 		      unsigned long kexec_flags)
 {
-	int ret;
+	int ret, i;
 
 	if (have_sys_firmware_memmap())
-		ret = get_memory_ranges_sysfs(range, ranges,kexec_flags);
+		ret = get_memory_ranges_sysfs(range, ranges);
 	else
-		ret = get_memory_ranges_proc_iomem(range, ranges, kexec_flags);
+		ret = get_memory_ranges_proc_iomem(range, ranges);
 
 	/*
 	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
@@ -217,6 +163,36 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
 	if (ret != 0)
 		return ret;
 
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < *ranges; i++) {
+		if ((*range)[i].type == RANGE_RAM &&
+				((*range)[i].start < 0x100)) {
+			(*range)[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		unsigned long long start, end;
+
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
 	/* just set 0 to 1 to enable printing for debugging */
 #if 0
 	{
-- 
1.5.6


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/3] Use get_memory_ranges() on x86-64.
  2008-07-09  0:41       ` Simon Horman
                           ` (2 preceding siblings ...)
  2008-07-09 11:11         ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
@ 2008-07-09 11:11         ` Bernhard Walle
  2008-07-09 11:12         ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
  4 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-09 11:11 UTC (permalink / raw)
  To: kexec; +Cc: Bernhard Walle

Because the get_memory_ranges() function was the same on i386 and x86_64, and
because that /sys/firmware/memmap interface should also be used for x86_64
without *new* code duplication, that part was moved out in a new file called
kexec-x86-common.c. That file only contains the memory map parsing for both the
"old" /proc/iomem interface and the new /sys/firmware/memmap interface.

That file is now built for i386 and x86_64.


Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
 kexec/arch/i386/Makefile           |    1 +
 kexec/arch/i386/kexec-x86-common.c |  207 ++++++++++++++++++++++++++++++++++++
 kexec/arch/i386/kexec-x86.c        |  175 ------------------------------
 kexec/arch/x86_64/Makefile         |    1 +
 kexec/arch/x86_64/kexec-x86_64.c   |   83 --------------
 5 files changed, 209 insertions(+), 258 deletions(-)
 create mode 100644 kexec/arch/i386/kexec-x86-common.c

diff --git a/kexec/arch/i386/Makefile b/kexec/arch/i386/Makefile
index f2d9636..d52a2f5 100644
--- a/kexec/arch/i386/Makefile
+++ b/kexec/arch/i386/Makefile
@@ -2,6 +2,7 @@
 # kexec i386 (linux booting linux)
 #
 i386_KEXEC_SRCS =  kexec/arch/i386/kexec-x86.c
+i386_KEXEC_SRCS += kexec/arch/i386/kexec-x86-common.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-elf-x86.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-elf-rel-x86.c
 i386_KEXEC_SRCS += kexec/arch/i386/kexec-bzImage.c
diff --git a/kexec/arch/i386/kexec-x86-common.c b/kexec/arch/i386/kexec-x86-common.c
new file mode 100644
index 0000000..4533425
--- /dev/null
+++ b/kexec/arch/i386/kexec-x86-common.c
@@ -0,0 +1,207 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "../../kexec.h"
+#include "../../kexec-syscall.h"
+#include "../../firmware_memmap.h"
+#include "kexec-x86.h"
+
+static struct memory_range memory_range[MAX_MEMORY_RANGES];
+
+/**
+ * The old /proc/iomem parsing code.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
+{
+	const char *iomem= proc_iomem();
+	int memory_ranges = 0;
+	char line[MAX_LINE];
+	FILE *fp;
+	fp = fopen(iomem, "r");
+	if (!fp) {
+		fprintf(stderr, "Cannot open %s: %s\n",
+			iomem, strerror(errno));
+		return -1;
+	}
+	while(fgets(line, sizeof(line), fp) != 0) {
+		unsigned long long start, end;
+		char *str;
+		int type;
+		int consumed;
+		int count;
+		if (memory_ranges >= MAX_MEMORY_RANGES)
+			break;
+		count = sscanf(line, "%Lx-%Lx : %n",
+			&start, &end, &consumed);
+		if (count != 2)
+			continue;
+		str = line + consumed;
+		end = end + 1;
+#if 0
+		printf("%016Lx-%016Lx : %s",
+			start, end, str);
+#endif
+		if (memcmp(str, "System RAM\n", 11) == 0) {
+			type = RANGE_RAM;
+		}
+		else if (memcmp(str, "reserved\n", 9) == 0) {
+			type = RANGE_RESERVED;
+		}
+		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
+			type = RANGE_ACPI;
+		}
+		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
+			type = RANGE_ACPI_NVS;
+		}
+		else {
+			continue;
+		}
+		memory_range[memory_ranges].start = start;
+		memory_range[memory_ranges].end = end;
+		memory_range[memory_ranges].type = type;
+#if 0
+		printf("%016Lx-%016Lx : %x\n",
+			start, end, type);
+#endif
+		memory_ranges++;
+	}
+	fclose(fp);
+	*range = memory_range;
+	*ranges = memory_ranges;
+	return 0;
+}
+
+/**
+ * Calls the architecture independent get_firmware_memmap_ranges() to parse
+ * /sys/firmware/memmap and then do some x86 only modifications.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ *
+ * @return 0 on success, any other value on failure.
+ */
+static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
+{
+	int ret;
+	size_t range_number = MAX_MEMORY_RANGES;
+
+	ret = get_firmware_memmap_ranges(memory_range, &range_number);
+	if (ret != 0) {
+		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
+			"Falling back to /proc/iomem.\n");
+		return get_memory_ranges_proc_iomem(range, ranges);
+	}
+
+	*range = memory_range;
+	*ranges = range_number;
+
+	return 0;
+}
+
+/**
+ * Return a sorted list of memory ranges.
+ *
+ * If we have the /sys/firmware/memmap interface, then use that. If not,
+ * or if parsing of that fails, use /proc/iomem as fallback.
+ *
+ * @param[out] range pointer that will be set to an array that holds the
+ *             memory ranges
+ * @param[out] ranges number of ranges valid in @p range
+ * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
+ *             or a crashdump kernel
+ *
+ * @return 0 on success, any other value on failure.
+ */
+int get_memory_ranges(struct memory_range **range, int *ranges,
+		      unsigned long kexec_flags)
+{
+	int ret, i;
+
+	if (have_sys_firmware_memmap())
+		ret = get_memory_ranges_sysfs(range, ranges);
+	else
+		ret = get_memory_ranges_proc_iomem(range, ranges);
+
+	/*
+	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
+	 * have already printed an error message, so fail silently here
+	 */
+	if (ret != 0)
+		return ret;
+
+	/* Don't report the interrupt table as ram */
+	for (i = 0; i < *ranges; i++) {
+		if ((*range)[i].type == RANGE_RAM &&
+				((*range)[i].start < 0x100)) {
+			(*range)[i].start = 0x100;
+			break;
+		}
+	}
+
+	/*
+	 * Redefine the memory region boundaries if kernel
+	 * exports the limits and if it is panic kernel.
+	 * Override user values only if kernel exported values are
+	 * subset of user defined values.
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		unsigned long long start, end;
+
+		ret = parse_iomem_single("Crash kernel\n", &start, &end);
+		if (ret != 0) {
+			fprintf(stderr, "parse_iomem_single failed.\n");
+			return -1;
+		}
+
+		if (start > mem_min)
+			mem_min = start;
+		if (end < mem_max)
+			mem_max = end;
+	}
+
+	/* just set 0 to 1 to enable printing for debugging */
+#if 0
+	{
+		int i;
+		printf("MEMORY RANGES\n");
+		for (i = 0; i < *ranges; i++) {
+			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
+				(*range)[i].end, (*range)[i].type);
+		}
+	}
+#endif
+
+	return ret;
+}
+
+
diff --git a/kexec/arch/i386/kexec-x86.c b/kexec/arch/i386/kexec-x86.c
index d5b6737..d33a14b 100644
--- a/kexec/arch/i386/kexec-x86.c
+++ b/kexec/arch/i386/kexec-x86.c
@@ -33,181 +33,6 @@
 #include "crashdump-x86.h"
 #include <arch/options.h>
 
-static struct memory_range memory_range[MAX_MEMORY_RANGES];
-
-/**
- * The old /proc/iomem parsing code.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- *
- * @return 0 on success, any other value on failure.
- */
-static int get_memory_ranges_proc_iomem(struct memory_range **range, int *ranges)
-{
-	const char *iomem= proc_iomem();
-	int memory_ranges = 0;
-	char line[MAX_LINE];
-	FILE *fp;
-	fp = fopen(iomem, "r");
-	if (!fp) {
-		fprintf(stderr, "Cannot open %s: %s\n",
-			iomem, strerror(errno));
-		return -1;
-	}
-	while(fgets(line, sizeof(line), fp) != 0) {
-		unsigned long long start, end;
-		char *str;
-		int type;
-		int consumed;
-		int count;
-		if (memory_ranges >= MAX_MEMORY_RANGES)
-			break;
-		count = sscanf(line, "%Lx-%Lx : %n",
-			&start, &end, &consumed);
-		if (count != 2)
-			continue;
-		str = line + consumed;
-		end = end + 1;
-#if 0
-		printf("%016Lx-%016Lx : %s",
-			start, end, str);
-#endif
-		if (memcmp(str, "System RAM\n", 11) == 0) {
-			type = RANGE_RAM;
-		}
-		else if (memcmp(str, "reserved\n", 9) == 0) {
-			type = RANGE_RESERVED;
-		}
-		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
-			type = RANGE_ACPI;
-		}
-		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
-			type = RANGE_ACPI_NVS;
-		}
-		else {
-			continue;
-		}
-		memory_range[memory_ranges].start = start;
-		memory_range[memory_ranges].end = end;
-		memory_range[memory_ranges].type = type;
-#if 0
-		printf("%016Lx-%016Lx : %x\n",
-			start, end, type);
-#endif
-		memory_ranges++;
-	}
-	fclose(fp);
-	*range = memory_range;
-	*ranges = memory_ranges;
-	return 0;
-}
-
-/**
- * Calls the architecture independent get_firmware_memmap_ranges() to parse
- * /sys/firmware/memmap and then do some x86 only modifications.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- *
- * @return 0 on success, any other value on failure.
- */
-static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges)
-{
-	int ret;
-	size_t range_number = MAX_MEMORY_RANGES;
-
-	ret = get_firmware_memmap_ranges(memory_range, &range_number);
-	if (ret != 0) {
-		fprintf(stderr, "Parsing the /sys/firmware memory map failed. "
-			"Falling back to /proc/iomem.\n");
-		return get_memory_ranges_proc_iomem(range, ranges);
-	}
-
-	*range = memory_range;
-	*ranges = range_number;
-
-	return 0;
-}
-
-/**
- * Return a sorted list of memory ranges.
- *
- * If we have the /sys/firmware/memmap interface, then use that. If not,
- * or if parsing of that fails, use /proc/iomem as fallback.
- *
- * @param[out] range pointer that will be set to an array that holds the
- *             memory ranges
- * @param[out] ranges number of ranges valid in @p range
- * @param[in]  kexec_flags the kexec_flags to determine if we load a normal
- *             or a crashdump kernel
- *
- * @return 0 on success, any other value on failure.
- */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-		      unsigned long kexec_flags)
-{
-	int ret, i;
-
-	if (have_sys_firmware_memmap())
-		ret = get_memory_ranges_sysfs(range, ranges);
-	else
-		ret = get_memory_ranges_proc_iomem(range, ranges);
-
-	/*
-	 * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem()
-	 * have already printed an error message, so fail silently here
-	 */
-	if (ret != 0)
-		return ret;
-
-	/* Don't report the interrupt table as ram */
-	for (i = 0; i < *ranges; i++) {
-		if ((*range)[i].type == RANGE_RAM &&
-				((*range)[i].start < 0x100)) {
-			(*range)[i].start = 0x100;
-			break;
-		}
-	}
-
-	/*
-	 * Redefine the memory region boundaries if kernel
-	 * exports the limits and if it is panic kernel.
-	 * Override user values only if kernel exported values are
-	 * subset of user defined values.
-	 */
-	if (kexec_flags & KEXEC_ON_CRASH) {
-		unsigned long long start, end;
-
-		ret = parse_iomem_single("Crash kernel\n", &start, &end);
-		if (ret != 0) {
-			fprintf(stderr, "parse_iomem_single failed.\n");
-			return -1;
-		}
-
-		if (start > mem_min)
-			mem_min = start;
-		if (end < mem_max)
-			mem_max = end;
-	}
-
-	/* just set 0 to 1 to enable printing for debugging */
-#if 0
-	{
-		int i;
-		printf("MEMORY RANGES\n");
-		for (i = 0; i < *ranges; i++) {
-			printf("%016Lx-%016Lx (%d)\n", (*range)[i].start,
-				(*range)[i].end, (*range)[i].type);
-		}
-	}
-#endif
-
-	return ret;
-}
-
 struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
diff --git a/kexec/arch/x86_64/Makefile b/kexec/arch/x86_64/Makefile
index c59c41f..7ca3e7e 100644
--- a/kexec/arch/x86_64/Makefile
+++ b/kexec/arch/x86_64/Makefile
@@ -7,6 +7,7 @@ x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-multiboot-x86.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-beoboot-x86.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-nbi.c
 x86_64_KEXEC_SRCS += kexec/arch/i386/x86-linux-setup.c
+x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-x86-common.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/crashdump-x86_64.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/kexec-x86_64.c
 x86_64_KEXEC_SRCS += kexec/arch/x86_64/kexec-elf-x86_64.c
diff --git a/kexec/arch/x86_64/kexec-x86_64.c b/kexec/arch/x86_64/kexec-x86_64.c
index d0b3e90..9973815 100644
--- a/kexec/arch/x86_64/kexec-x86_64.c
+++ b/kexec/arch/x86_64/kexec-x86_64.c
@@ -32,89 +32,6 @@
 #include "crashdump-x86_64.h"
 #include <arch/options.h>
 
-#define MAX_MEMORY_RANGES 64
-static struct memory_range memory_range[MAX_MEMORY_RANGES];
-
-/* Return a sorted list of memory ranges. */
-int get_memory_ranges(struct memory_range **range, int *ranges,
-					unsigned long kexec_flags)
-{
-	const char *iomem= proc_iomem();
-	int memory_ranges = 0;
-	char line[MAX_LINE];
-	FILE *fp;
-	fp = fopen(iomem, "r");
-	if (!fp) {
-		fprintf(stderr, "Cannot open %s: %s\n",
-			iomem, strerror(errno));
-		return -1;
-	}
-	while(fgets(line, sizeof(line), fp) != 0) {
-		unsigned long long start, end;
-		char *str;
-		int type;
-		int consumed;
-		int count;
-		if (memory_ranges >= MAX_MEMORY_RANGES)
-			break;
-		count = sscanf(line, "%Lx-%Lx : %n",
-			&start, &end, &consumed);
-		if (count != 2)
-			continue;
-		str = line + consumed;
-		end = end + 1;
-#ifdef DEBUG
-		printf("%016Lx-%016Lx : %s",
-			start, end, str);
-#endif
-		if (memcmp(str, "System RAM\n", 11) == 0) {
-			type = RANGE_RAM;
-		}
-		else if (memcmp(str, "reserved\n", 9) == 0) {
-			type = RANGE_RESERVED;
-		}
-		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
-			type = RANGE_ACPI;
-		}
-		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
-			type = RANGE_ACPI_NVS;
-		}
-		else if (memcmp(str, "Crash kernel\n", 13) == 0) {
-			/* Redefine the memory region boundaries if kernel
-			 * exports the limits and if it is panic kernel.
-			 * Override user values only if kernel exported
-			 * values are subset of user defined values.
-			 */
-			if (kexec_flags & KEXEC_ON_CRASH) {
-				if (start > mem_min)
-					mem_min = start;
-				if (end < mem_max)
-					mem_max = end;
-			}
-			continue;
-		}
-		else {
-			continue;
-		}
-		/* Don't report the interrupt table as ram */
-		if (type == RANGE_RAM && (start < 0x100)) {
-			start = 0x100;
-		}
-		memory_range[memory_ranges].start = start;
-		memory_range[memory_ranges].end = end;
-		memory_range[memory_ranges].type = type;
-#ifdef DEBUG
-		printf("%016Lx-%016Lx : %x\n",
-			start, end, type);
-#endif
-		memory_ranges++;
-	}
-	fclose(fp);
-	*range = memory_range;
-	*ranges = memory_ranges;
-	return 0;
-}
-
 struct file_type file_type[] = {
 	{ "elf-x86_64", elf_x86_64_probe, elf_x86_64_load, elf_x86_64_usage },
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
-- 
1.5.6


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs()
  2008-07-09  0:41       ` Simon Horman
                           ` (3 preceding siblings ...)
  2008-07-09 11:11         ` [PATCH 3/3] Use get_memory_ranges() on x86-64 Bernhard Walle
@ 2008-07-09 11:12         ` Bernhard Walle
       [not found]           ` <20080710232834.GG11227@verge.net.au>
  4 siblings, 1 reply; 21+ messages in thread
From: Bernhard Walle @ 2008-07-09 11:12 UTC (permalink / raw)
  To: Simon Horman

Hi,

* Simon Horman [2008-07-09 10:41]:
>
> On Mon, Jul 07, 2008 at 04:43:41PM +0200, Bernhard Walle wrote:
> > With the previous patch, we have a duplication between that both functions
> > for following tasks:
> > 
> >  - don't report the interrupt table as RAM,
> >  - set the mem_min and mem_max limits for kdump.
> > 
> > This patch removes that redundancy into the function get_memory_ranges()
> > that calls both functions internally.
> 
> these patches seem fine to me, but I am still having minor troubles
> with missing defines. For the record, I am seeing the problems with
> gcc-3.4.5 + glibc-2.3.6. Yes, I know this is old, but it would
> be nice if this minor issue didn't break it.

Yes, of course, I just cannot reproduce it, even with current Debian
and gcc 3.4 ...

> 1. The snippet below looks good, but it needs to be included
>    in or berfore " [PATCH 1/3] Parse /sys/firmware/memmap".

Should be fixed now.

> > diff --git a/kexec/firmware_memmap.c b/kexec/firmware_memmap.c
> > index cdac6f3..2ad450d 100644
> > --- a/kexec/firmware_memmap.c
> > +++ b/kexec/firmware_memmap.c
> > @@ -31,6 +31,13 @@
> >  #include "firmware_memmap.h"
> >  #include "kexec.h"
> >  
> > +/*
> > + * If the system is too old for ULLONG_MAX, define it here.
> > + */
> > +#ifndef ULLONG_MAX
> > +#    define ULLONG_MAX (~0ULL)
> > +#endif
> > +
> >  /**
> >   * The full path to the sysfs interface that provides the memory map.
> >   */
> 
> 2. I did not realise this at the time that I sent my previous response,
>    but LLONG_MAX is also a problem. I believe that the following
>    code, based on your code above, fixes the problem.

Should also be fixed now.

> Just for good measure, I have also verified, using the same method, that
> your code gives 18446744073709551615 (=2^64-1), which matches the value
> internally provided by gcc-4.3.1 + glibc-2.7.

Thanks for your testing!


Bernhard
-- 
Bernhard Walle, SUSE LINUX Products GmbH, Architecture Development

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/3] Parse /sys/firmware/memmap.
  2008-07-09 11:11         ` [PATCH 1/3] " Bernhard Walle
@ 2008-07-10 23:29           ` Simon Horman
  0 siblings, 0 replies; 21+ messages in thread
From: Simon Horman @ 2008-07-10 23:29 UTC (permalink / raw)
  To: Bernhard Walle; +Cc: kexec

On Wed, Jul 09, 2008 at 01:11:00PM +0200, Bernhard Walle wrote:
> After the patch that provides /sys/firmware/memmap has been merged in the 'tip'
> tree by Ingo Molnar, kexec should use that interface.
> 
> This patch implements architecture-independent parsing in a new file called
> firmware_memmap.c. The x86 part is ported to use that memory map for
> kexec. We don't use that memory map for building the ELF core headers,
> that was the intention for that new interface.
> 
> 
> Signed-off-by: Bernhard Walle <bwalle@suse.de>

Thanks, applied. Ditto for the following two patches.

[PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem()
        and get_memory_ranges_sysfs()
[PATCH 3/3] Use get_memory_ranges() on x86-64.

-- 
Horms


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs()
       [not found]           ` <20080710232834.GG11227@verge.net.au>
@ 2008-07-11 15:09             ` Bernhard Walle
  0 siblings, 0 replies; 21+ messages in thread
From: Bernhard Walle @ 2008-07-11 15:09 UTC (permalink / raw)
  To: Simon Horman; +Cc: kexec

* Simon Horman [2008-07-11 09:28]:
> 
> I'm using crosstool. I guess its crazy enough to show up things like this.

Ah! Maybe I should install that too, but since we have 5
architectures in our build system natively, I always use that infra
structure to test my builds ...

> These problems do indeed seem to be fixed now, I have applied all
> three patches.

Thanks!




Bernhard
-- 
Bernhard Walle, SUSE LINUX Products GmbH, Architecture Development

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2008-07-11 15:08 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-06 23:06 Use /sys/firmware/memmap in kexec Bernhard Walle
2008-07-06 23:06 ` [PATCH 1/5] Remove trailing whitespace Bernhard Walle
2008-07-07  7:02   ` Simon Horman
2008-07-06 23:06 ` [PATCH 2/5] Fix compiler warning in kexec-x86.c Bernhard Walle
2008-07-07  7:03   ` Simon Horman
2008-07-06 23:06 ` [PATCH 3/5] Parse /sys/firmware/memmap Bernhard Walle
2008-07-07  7:06   ` Simon Horman
2008-07-07 14:43     ` Bernhard Walle
2008-07-07 14:43     ` [PATCH 1/3] " Bernhard Walle
2008-07-07 14:43     ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
2008-07-09  0:41       ` Simon Horman
2008-07-09 11:10         ` Parse /sys/firmware/memmap Bernhard Walle
2008-07-09 11:11         ` [PATCH 1/3] " Bernhard Walle
2008-07-10 23:29           ` Simon Horman
2008-07-09 11:11         ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
2008-07-09 11:11         ` [PATCH 3/3] Use get_memory_ranges() on x86-64 Bernhard Walle
2008-07-09 11:12         ` [PATCH 2/3] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
     [not found]           ` <20080710232834.GG11227@verge.net.au>
2008-07-11 15:09             ` Bernhard Walle
2008-07-07 14:43     ` [PATCH 3/3] Use get_memory_ranges() on x86-64 Bernhard Walle
2008-07-06 23:06 ` [PATCH 4/5] Remove redundancy between get_memory_ranges_proc_iomem() and get_memory_ranges_sysfs() Bernhard Walle
2008-07-06 23:06 ` [PATCH 5/5] Use get_memory_ranges() on x86-64 Bernhard Walle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox