[PATCH 4/6] ppc64-kdump-crash-segments-support.patch

R Sharada sharada at in.ibm.com
Tue Jan 17 02:12:45 EST 2006



This patch provides the basic functionality for
loading crash dump segment and required features.
- Code for loading the crashdump segments
- It modifies the crash dump cmdline parameter to
add the new parameters, elfcorehdr and savemaxmem
- other miscellaneous cleanups and re-ordering
of some existing code in kexec-elf-ppc64.c

Signed-off-by: R Sharada <sharada at in.ibm.com>
---


diff -puN kexec/arch/ppc64/kexec-elf-ppc64.c~ppc64-kdump-crash-segments-support kexec/arch/ppc64/kexec-elf-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-ppc64.c~ppc64-kdump-crash-segments-support	2006-01-15 08:11:27.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-elf-ppc64.c	2006-01-15 08:38:42.000000000 +0530
@@ -33,18 +33,18 @@
 #include <linux/elf.h>
 #include "../../kexec.h"
 #include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
 #include "kexec-ppc64.h"
+#include "crashdump-ppc64.h"
 #include <arch/options.h>
 
 #define BOOTLOADER         "kexec"
 #define BOOTLOADER_VERSION VERSION
-#define MAX_COMMAND_LINE   256
 
 unsigned long initrd_base, initrd_size;
 
-int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *);
-int parse_options(char *);
-int setup_memory_ranges(void);
+int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *,
+			char *);
 
 int elf_ppc64_probe(const char *buf, off_t len)
 {
@@ -68,23 +68,29 @@ int elf_ppc64_probe(const char *buf, off
 }
 
 int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
-	struct kexec_info *info)
+			struct kexec_info *info)
 {
 	struct mem_ehdr ehdr;
-	const char *command_line;
-	const char *input_options;
-	int command_line_len;
-	const char *ramdisk;
-	const char *devicetreeblob;
-	unsigned long *lp;
-	int result;
-	int opt;
+	char *cmdline, *modified_cmdline;
+	const char *ramdisk, *devicetreeblob;
+	int cmdline_len, modified_cmdline_len;
+	unsigned long long max_addr, hole_addr;
+	unsigned char *seg_buf = NULL;
+	off_t seg_size = 0;
+	struct mem_phdr *phdr;
+	size_t size;
+	unsigned long long *rsvmap_ptr;
+	struct bootblock *bb_ptr;
+	unsigned int nr_segments, i;
+	int result, opt;
+
 #define OPT_APPEND     (OPT_ARCH_MAX+0)
 #define OPT_RAMDISK     (OPT_ARCH_MAX+1)
 #define OPT_DEVICETREEBLOB     (OPT_ARCH_MAX+2)
 
 	static const struct option options[] = {
 		KEXEC_ARCH_OPTIONS
+		{ "command-line",       1, NULL, OPT_APPEND },
 		{ "append",             1, NULL, OPT_APPEND },
 		{ "ramdisk",            1, NULL, OPT_RAMDISK },
 		{ "devicetreeblob",     1, NULL, OPT_DEVICETREEBLOB },
@@ -96,23 +102,24 @@ int elf_ppc64_load(int argc, char **argv
 	/* Parse command line arguments */
 	initrd_base = 0;
 	initrd_size = 0;
-	command_line = 0;
-	input_options = 0;
+	cmdline = 0;
 	ramdisk = 0;
 	devicetreeblob = 0;
+	max_addr = 0xFFFFFFFFFFFFFFFFUL;
+	hole_addr = 0;
 
-	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
+	while ((opt = getopt_long(argc, argv, short_options,
+					options, 0)) != -1) {
 		switch (opt) {
 		default:
 			/* Ignore core options */
-			if (opt < OPT_ARCH_MAX) {
+			if (opt < OPT_ARCH_MAX)
 				break;
-			}
 		case '?':
 			usage();
 			return -1;
 		case OPT_APPEND:
-			input_options = optarg;
+			cmdline = optarg;
 			break;
 		case OPT_RAMDISK:
 			ramdisk = optarg;
@@ -123,13 +130,24 @@ int elf_ppc64_load(int argc, char **argv
 		}
 	}
 
-	command_line_len = 0;
-	if (command_line) {
-		command_line_len = strlen(command_line) + 1;
-	}
+	cmdline_len = 0;
+	if (cmdline)
+		cmdline_len = strlen(cmdline) + 1;
+
+	setup_memory_ranges(info->kexec_flags);
 
-	if (input_options)
-		parse_options(input_options);
+	/* Need to append some command line parameters internally in case of
+	 * taking crash dumps.
+	 */
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
+		memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
+		if (cmdline) {
+			strncpy(modified_cmdline, cmdline, COMMAND_LINE_SIZE);
+			modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+		}
+		modified_cmdline_len = strlen(modified_cmdline);
+	}
 
 	/* Parse the Elf file */
 	result = build_elf_exec_info(buf, len, &ehdr);
@@ -138,25 +156,19 @@ int elf_ppc64_load(int argc, char **argv
 		return result;
 	}
 
-	/* Load the Elf data */
-	setup_memory_ranges();
 	/* Load the Elf data. Physical load addresses in elf64 header do not
 	 * show up correctly. Use user supplied address for now to patch the
 	 * elf header
 	 */
-	unsigned long long base_addr;
-	struct mem_phdr *phdr;
-	size_t size;
 
 	phdr = &ehdr.e_phdr[0];
 	size = phdr->p_filesz;
-	if (size > phdr->p_memsz) {
+	if (size > phdr->p_memsz)
 		size = phdr->p_memsz;
-	}
 
-	base_addr = (unsigned long)locate_hole(info, size, 0, 0,
+	hole_addr = (unsigned long)locate_hole(info, size, 0, 0,
 			0xFFFFFFFFFFFFFFFFUL, 1);
-	ehdr.e_phdr[0].p_paddr = base_addr;
+	ehdr.e_phdr[0].p_paddr = hole_addr;
 	result = elf_exec_load(&ehdr, info);
 	if (result < 0) {
 		free_elf_info(&ehdr);
@@ -165,10 +177,10 @@ int elf_ppc64_load(int argc, char **argv
 
 	/* Add a ram-disk to the current image */
 	if (ramdisk) {
-	  if (devicetreeblob) {
-	    fprintf(stderr, "Can't use ramdisk with device tree blob input\n");
-	    return -1;
-	  }
+		if (devicetreeblob) {
+			fprintf(stderr, "Can't use ramdisk with device tree blob input\n");
+			return -1;
+		}
 		unsigned char *ramdisk_buf = NULL;
 		off_t ramdisk_size = 0;
 		unsigned long long ramdisk_addr;
@@ -181,6 +193,19 @@ int elf_ppc64_load(int argc, char **argv
 		initrd_size = ramdisk_size;
 	}
 
+	/* If panic kernel is being loaded, additional segments need
+	 * to be created.
+	 */
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		result = load_crashdump_segments(info, modified_cmdline,
+						max_addr, 0);
+		if (result < 0)
+			return -1;
+		/* Use new command line. */
+		cmdline = modified_cmdline;
+		cmdline_len = strlen(modified_cmdline) + 1;
+	}
+
 	/* Add v2wrap to the current image */
 	unsigned char *v2wrap_buf = NULL;
 	off_t v2wrap_size = 0;
@@ -229,7 +254,7 @@ int elf_ppc64_load(int argc, char **argv
 		rsvmap_ptr += 2;
 	}
 	rsvmap_ptr -= 2;
- 	*rsvmap_ptr = (unsigned long long)(
+	*rsvmap_ptr = (unsigned long long)(
 		info->segment[(info->nr_segments)-1].mem + 0x100);
  	rsvmap_ptr++;
  	*rsvmap_ptr = (unsigned long long)bb_ptr->totalsize;
@@ -252,67 +277,3 @@ void elf_ppc64_usage(void)
 {
 	fprintf(stderr, "elf support is still broken\n");
 }
-
-struct param_struct {
-	const char *name;
-	void *val;
-};
-struct param_struct params;
-
-static char *next_arg(char *args, char **param, char **val)
-{
-	unsigned int i, equals = 0;
-	char *next;
-
-	/* Chew any extra spaces */
-	while (*args == ' ') args++;
-	for (i = 0; args[i]; i++) {
-		if (args[i] == ' ')
-			break;
-		if (equals == 0) {
-			if (args[i] == '=')
-				equals = i;
-		}
-	}
-	*param = args;
-	if (!equals)
-		*val = NULL;
-	else {
-		args[equals] = '\0';
-		*val = args + equals + 1;
-	}
-
-	if (args[i]) {
-		args[i] = '\0';
-		next = args + i + 1;
-	} else
-		next = args + i;
-	return next;
-}
-
-static int add_arg(char *param, char*val)
-{
-	int ret = 0;
-	if (strcmp(param, "initrd-base")==0)
-		initrd_base=strtoul(val, NULL, 0);
-	else if (strcmp(param, "initrd-size")==0)
-		initrd_size=strtoul(val, NULL, 0);
-	else {
-		printf("invalid option\n");
-		ret = 1;
-	}
-	return ret;
-}
-
-int parse_options(char *options)
-{
-	char *param, *val;
-	/* initrd-addr , initrd-size */
-	while (*options) {
-		int ret;
-		options = next_arg(options, &param, &val);
-		ret = add_arg(param, val);
-	}
-	/* All parsed OK */
-	return 0;
-}
diff -puN kexec/arch/ppc64/Makefile~ppc64-kdump-crash-segments-support kexec/arch/ppc64/Makefile
--- kexec-tools-1.101/kexec/arch/ppc64/Makefile~ppc64-kdump-crash-segments-support	2006-01-15 08:14:47.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/Makefile	2006-01-15 08:15:40.000000000 +0530
@@ -6,5 +6,6 @@ KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-zI
 KEXEC_C_SRCS+= kexec/arch/ppc64/fs2dt.c
 KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-elf-ppc64.c
 KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-ppc64.c
+KEXEC_C_SRCS+= kexec/arch/ppc64/crashdump-ppc64.c
 
 KEXEC_S_SRCS+=
diff -puN kexec/arch/ppc64/crashdump-ppc64.c~ppc64-kdump-crash-segments-support kexec/arch/ppc64/crashdump-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/crashdump-ppc64.c~ppc64-kdump-crash-segments-support	2006-01-15 08:40:23.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/crashdump-ppc64.c	2006-01-15 09:11:45.000000000 +0530
@@ -31,6 +31,8 @@
 #include "kexec-ppc64.h"
 #include "crashdump-ppc64.h"
 
+extern struct arch_options_t arch_options;
+
 /* Stores a sorted list of RAM memory ranges for which to create elf headers.
  * A separate program header is created for backup region
  */
@@ -45,6 +47,17 @@ mem_rgns_t usablemem_rgns = {0, };
 /* array to store memory regions to be excluded from elf header creation */
 mem_rgns_t exclude_rgns = {0, };
 
+/*
+ * To store the memory size of the first kernel and this value will be
+ * passed to the second kernel as command line (savemaxmem=xM).
+ * The second kernel will be calculated saved_max_pfn based on this
+ * variable.
+ * Since we are creating/using usable-memory property, there is no way
+ * we can determine the RAM size unless parsing the device-tree/memoy@/reg
+ * property in the kernel.
+ */
+unsigned long saved_max_mem = 0;
+
 static int sort_regions(mem_rgns_t *rgn);
 
 /* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
@@ -192,6 +205,116 @@ static int get_crash_memory_ranges(struc
 	return 0;
 }
 
+/* Converts unsigned long to ascii string. */
+static void ultoa(unsigned long i, char *str)
+{
+	int j = 0, k;
+	char tmp;
+
+	do {
+		str[j++] = i % 10 + '0';
+	} while ((i /=10) > 0);
+	str[j] = '\0';
+
+	/* Reverse the string. */
+	for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
+		tmp = str[k];
+		str[k] = str[j];
+		str[j] = tmp;
+	}
+}
+
+static int add_cmdline_param(char *cmdline, unsigned long addr,
+				char *cmdstr, char *byte)
+{
+	int cmdlen, len, align = 1024;
+	char str[COMMAND_LINE_SIZE], *ptr;
+
+	/* Passing in =xxxK / =xxxM format. Saves space required in cmdline.*/
+	switch (byte[0]) {
+		case 'K':
+			if (addr%align)
+				return -1;
+			addr = addr/align;
+			break;
+		case 'M':
+			addr = addr/(align *align);
+			break;
+	}
+	ptr = str;
+	strcpy(str, cmdstr);
+	ptr += strlen(str);
+	ultoa(addr, ptr);
+	strcat(str, byte);
+	len = strlen(str);
+	cmdlen = strlen(cmdline) + len;
+	if (cmdlen > (COMMAND_LINE_SIZE - 1))
+		die("Command line overflow\n");
+	strcat(cmdline, str);
+#if DEBUG
+	fprintf(stderr, "Command line after adding elfcorehdr: %s\n", cmdline);
+#endif
+	return 0;
+}
+
+/* Loads additional segments in case of a panic kernel is being loaded.
+ * One segment for backup region, another segment for storing elf headers
+ * for crash memory image.
+ */
+int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
+				unsigned long max_addr, unsigned long min_base)
+{
+	void *tmp;
+	unsigned long sz, elfcorehdr;
+	int nr_ranges, align = 1024;
+	long int nr_cpus = 0;
+	struct memory_range *mem_range;
+
+	if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
+		return -1;
+
+	/* Create a backup region segment to store backup data*/
+	sz = (BACKUP_SIZE + align - 1) & ~(align - 1);
+	tmp = xmalloc(sz);
+	memset(tmp, 0, sz);
+	info->backup_start = add_buffer(info, tmp, sz, sz, align,
+					0, max_addr, 1);
+	reserve(info->backup_start, sz);
+	/* Create elf header segment and store crash image data. */
+	nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (nr_cpus < 0) {
+		fprintf(stderr,"kexec_load (elf header segment)"
+			" failed: %s\n", strerror(errno));
+		return -1;
+	}
+	if (arch_options.core_header_type == CORE_TYPE_ELF64) {
+		sz =    sizeof(Elf64_Ehdr) +
+			nr_cpus * sizeof(Elf64_Phdr) +
+			nr_ranges * sizeof(Elf64_Phdr);
+	} else {
+		sz =    sizeof(Elf32_Ehdr) +
+			nr_cpus * sizeof(Elf32_Phdr) +
+			nr_ranges * sizeof(Elf32_Phdr);
+	}
+	sz = (sz + align - 1) & ~(align -1);
+	tmp = xmalloc(sz);
+	memset(tmp, 0, sz);
+	if (arch_options.core_header_type == CORE_TYPE_ELF64) {
+		if (prepare_crash_memory_elf64_headers(info, tmp, sz) < 0)
+			return -1;
+	}
+
+	elfcorehdr = add_buffer(info, tmp, sz, sz, align, min_base,
+				max_addr, 1);
+	reserve(elfcorehdr, sz);
+	/* modify and store the cmdline in a global array. This is later
+	 * read by flatten_device_tree and modified if required
+	 */
+	add_cmdline_param(mod_cmdline, elfcorehdr, " elfcorehdr=", "K");
+	add_cmdline_param(mod_cmdline, saved_max_mem, " savemaxmem=", "M");
+	return 0;
+}
+
 /*
  * Used to save various memory regions needed for the captured kernel.
  */
_



More information about the Linuxppc64-dev mailing list