Blob Blame History Raw
diff -urNp -X dontdiff kexec-tools-1.101/configure kexec-tools-1.101-kdump/configure
--- kexec-tools-1.101/configure	2005-02-16 18:07:44.000000000 +0530
+++ kexec-tools-1.101-kdump/configure	2006-02-22 11:30:09.912285648 +0530
@@ -1384,12 +1384,18 @@ case $host_cpu in
 	powerpc )
 		host_cpu="ppc"
 		;;
+	powerpc64 )
+		host_cpu="ppc64"
+		;;
+	s390x )
+		host_cpu="s390"
+		;;
 	* )
 		host_cpu="$host_cpu"
 		;;
 esac
 case $host_cpu in
-	i386|ppc|x86_64|alpha|ppc64|ia64)
+	i386|ppc|x86_64|alpha|ppc64|ia64|s390)
 		;;
 	* )
 		{ { echo "$as_me:$LINENO: error:  unsupported architecture $host_cpu" >&5
@@ -1406,6 +1412,12 @@ if test "${host_alias}" ; then
 fi
 EXTRA_CFLAGS=""
 
+# Check whether ppc64. Add -m64 for building 64-bit binary
+# Add -mcall-aixdesc to generate dot-symbols as in gcc 3.3.3
+if test "$ARCH" = ppc64; then
+  EXTRA_CFLAGS="$EXTRA_CFLAGS -m64 -mcall-aixdesc"
+fi;
+
 # Check whether --with-objdir or --without-objdir was given.
 if test "${with_objdir+set}" = set; then
   withval="$with_objdir"
@@ -1421,7 +1433,6 @@ if test "${with_gamecube+set}" = set; th
    EXTRA_CFLAGS="$EXTRA_CFLAGS -DCONFIG_GAMECUBE=1"
 fi;
 
-
 # Check whether --with-zlib or --without-zlib was given.
 if test "${with_zlib+set}" = set; then
   withval="$with_zlib"
diff -urNp -X dontdiff kexec-tools-1.101/configure.ac kexec-tools-1.101-kdump/configure.ac
--- kexec-tools-1.101/configure.ac	2005-01-09 07:06:57.000000000 +0530
+++ kexec-tools-1.101-kdump/configure.ac	2006-02-22 11:30:08.809453304 +0530
@@ -25,12 +25,18 @@ case $host_cpu in 
 	powerpc )
 		host_cpu="ppc"
 		;;
+	powerpc64 )
+		host_cpu="ppc64"
+		;;
+	s390x )
+		host_cpu="s390"
+		;;
 	* ) 
 		host_cpu="$host_cpu"
 		;;
 esac
 case $host_cpu in
-	i386|ppc|x86_64|alpha|ppc64|ia64)
+	i386|ppc|x86_64|alpha|ppc64|ia64|s390)
 		;;
 	* )
 		AC_MSG_ERROR([ unsupported architecture $host_cpu])
@@ -45,6 +51,13 @@ if test "${host_alias}" ; then
 	OBJDIR="$OBJDIR-${host_alias}"
 fi 
 EXTRA_CFLAGS=""
+
+# Check whether ppc64. Add -m64 for building 64-bit binary
+# Add -mcall-aixdesc to generate dot-symbols as in gcc 3.3.3
+if test "$ARCH" = ppc64; then
+  EXTRA_CFLAGS="$EXTRA_CFLAGS -m64 -mcall-aixdesc"
+fi;
+
 AC_ARG_WITH([objdir], AC_HELP_STRING([--with-objdir=<dir>],[select directory for object files]),
 	[ OBJDIR="$withval" ], [ OBJDIR="$OBJDIR" ])
 
diff -urNp -X dontdiff kexec-tools-1.101/kdump/kdump.c kexec-tools-1.101-kdump/kdump/kdump.c
--- kexec-tools-1.101/kdump/kdump.c	2005-02-06 07:28:15.000000000 +0530
+++ kexec-tools-1.101-kdump/kdump/kdump.c	2006-02-22 11:30:11.080108112 +0530
@@ -54,7 +54,7 @@ static void *xmalloc(size_t size)
 	result = malloc(size);
 	if (result == NULL) {
 		fprintf(stderr, "malloc of %u bytes failed: %s\n",
-			size, strerror(errno));
+			(unsigned int)size, strerror(errno));
 		exit(7);
 	}
 	return result;
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/crashdump-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/crashdump-x86.c
--- kexec-tools-1.101/kexec/arch/i386/crashdump-x86.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/crashdump-x86.c	2006-02-22 11:30:01.525560624 +0530
@@ -0,0 +1,728 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Vivek Goyal (vgoyal@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2005. 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.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "../../crashdump.h"
+#include "kexec-x86.h"
+#include "crashdump-x86.h"
+#include <x86/x86-linux.h>
+
+extern struct arch_options_t arch_options;
+
+/* Forward Declaration. */
+static int exclude_crash_reserve_region(int *nr_ranges);
+
+/* Stores a sorted list of RAM memory ranges for which to create elf headers.
+ * A separate program header is created for backup region */
+static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+
+/* Memory region reserved for storing panic kernel and other data. */
+static struct memory_range crash_reserved_mem;
+
+/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
+ * create Elf headers. Keeping it separate from get_memory_ranges() as
+ * requirements are different in the case of normal kexec and crashdumps.
+ *
+ * Normal kexec needs to look at all of available physical memory irrespective
+ * of the fact how much of it is being used by currently running kernel.
+ * Crashdumps need to have access to memory regions actually being used by
+ * running  kernel. Expecting a different file/data structure than /proc/iomem
+ * to look into down the line. May be something like /proc/kernelmem or may
+ * be zone data structures exported from kernel.
+ */
+static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+{
+	const char iomem[]= "/proc/iomem";
+	int memory_ranges = 0;
+	char line[MAX_LINE];
+	FILE *fp;
+	unsigned long long start, end;
+
+	fp = fopen(iomem, "r");
+	if (!fp) {
+		fprintf(stderr, "Cannot open %s: %s\n",
+			iomem, strerror(errno));
+		return -1;
+	}
+
+	/* First entry is for first 640K region. Different bios report first
+	 * 640K in different manner hence hardcoding it */
+	crash_memory_range[0].start = 0x00000000;
+	crash_memory_range[0].end = 0x0009ffff;
+	crash_memory_range[0].type = RANGE_RAM;
+	memory_ranges++;
+
+	while(fgets(line, sizeof(line), fp) != 0) {
+		char *str;
+		int type, consumed, count;
+		if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
+			break;
+		count = sscanf(line, "%Lx-%Lx : %n",
+			&start, &end, &consumed);
+		if (count != 2)
+			continue;
+		str = line + consumed;
+#if 0
+		printf("%016Lx-%016Lx : %s",
+			start, end, str);
+#endif
+		/* Only Dumping memory of type System RAM. */
+		if (memcmp(str, "System RAM\n", 11) == 0) {
+			type = RANGE_RAM;
+		} else if (memcmp(str, "Crash kernel\n", 13) == 0) {
+				/* Reserved memory region. New kernel can
+				 * use this region to boot into. */
+				crash_reserved_mem.start = start;
+				crash_reserved_mem.end = end;
+				crash_reserved_mem.type = RANGE_RAM;
+				continue;
+		} else {
+			continue;
+		}
+
+		/* First 640K already registered */
+		if (start >= 0x00000000 && end <= 0x0009ffff)
+			continue;
+
+		crash_memory_range[memory_ranges].start = start;
+		crash_memory_range[memory_ranges].end = end;
+		crash_memory_range[memory_ranges].type = type;
+		memory_ranges++;
+
+		/* Segregate linearly mapped region. */
+		if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) {
+			crash_memory_range[memory_ranges-1].end = MAXMEM -1;
+
+			/* Add segregated region. */
+			crash_memory_range[memory_ranges].start = MAXMEM;
+			crash_memory_range[memory_ranges].end = end;
+			crash_memory_range[memory_ranges].type = type;
+			memory_ranges++;
+		}
+	}
+	fclose(fp);
+	if (exclude_crash_reserve_region(&memory_ranges) < 0)
+		return -1;
+	*range = crash_memory_range;
+	*ranges = memory_ranges;
+#if 0
+	int i;
+	printf("CRASH MEMORY RANGES\n");
+	for(i = 0; i < memory_ranges; i++) {
+		start = crash_memory_range[i].start;
+		end = crash_memory_range[i].end;
+		printf("%016Lx-%016Lx\n", start, end);
+	}
+#endif
+	return 0;
+}
+
+/* Removes crash reserve region from list of memory chunks for whom elf program
+ * headers have to be created. Assuming crash reserve region to be a single
+ * continuous area fully contained inside one of the memory chunks */
+static int exclude_crash_reserve_region(int *nr_ranges)
+{
+	int i, j, tidx = -1;
+	unsigned long long cstart, cend;
+	struct memory_range temp_region;
+
+	/* Crash reserved region. */
+	cstart = crash_reserved_mem.start;
+	cend = crash_reserved_mem.end;
+
+	for (i = 0; i < (*nr_ranges); i++) {
+		unsigned long long mstart, mend;
+		mstart = crash_memory_range[i].start;
+		mend = crash_memory_range[i].end;
+		if (cstart < mend && cend > mstart) {
+			if (cstart != mstart && cend != mend) {
+				/* Split memory region */
+				crash_memory_range[i].end = cstart - 1;
+				temp_region.start = cend + 1;
+				temp_region.end = mend;
+				temp_region.type = RANGE_RAM;
+				tidx = i+1;
+			} else if (cstart != mstart)
+				crash_memory_range[i].end = cstart - 1;
+			else
+				crash_memory_range[i].start = cend + 1;
+		}
+	}
+	/* Insert split memory region, if any. */
+	if (tidx >= 0) {
+		if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) {
+			/* No space to insert another element. */
+			fprintf(stderr, "Error: Number of crash memory ranges"
+					" excedeed the max limit\n");
+			return -1;
+		}
+		for (j = (*nr_ranges - 1); j >= tidx; j--)
+			crash_memory_range[j+1] = crash_memory_range[j];
+		crash_memory_range[tidx].start = temp_region.start;
+		crash_memory_range[tidx].end = temp_region.end;
+		crash_memory_range[tidx].type = temp_region.type;
+		(*nr_ranges)++;
+	}
+	return 0;
+}
+
+/* Adds a segment from list of memory regions which new kernel can use to
+ * boot. Segment start and end should be aligned to 1K boundary. */
+static int add_memmap(struct memory_range *memmap_p, unsigned long long addr,
+								size_t size)
+{
+	int i, j, nr_entries = 0, tidx = 0, align = 1024;
+	unsigned long long mstart, mend;
+
+	/* Do alignment check. */
+	if ((addr%align) || (size%align))
+		return -1;
+
+	/* Make sure at least one entry in list is free. */
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (!mstart  && !mend)
+			break;
+		else
+			nr_entries++;
+	}
+	if (nr_entries == CRASH_MAX_MEMMAP_NR)
+		return -1;
+
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (mstart == 0 && mend == 0)
+			break;
+		if (mstart <= (addr+size-1) && mend >=addr)
+			/* Overlapping region. */
+			return -1;
+		else if (addr > mend)
+			tidx = i+1;
+	}
+		/* Insert the memory region. */
+		for (j = nr_entries-1; j >= tidx; j--)
+			memmap_p[j+1] = memmap_p[j];
+		memmap_p[tidx].start = addr;
+		memmap_p[tidx].end = addr + size - 1;
+#if 0
+	printf("Memmap after adding segment\n");
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (mstart == 0 && mend == 0)
+			break;
+		printf("%016llx - %016llx\n",
+			mstart, mend);
+	}
+#endif
+	return 0;
+}
+
+/* Removes a segment from list of memory regions which new kernel can use to
+ * boot. Segment start and end should be aligned to 1K boundary. */
+static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr,
+								size_t size)
+{
+	int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024;
+	unsigned long long mstart, mend;
+	struct memory_range temp_region;
+
+	/* Do alignment check. */
+	if ((addr%align) || (size%align))
+		return -1;
+
+	/* Make sure at least one entry in list is free. */
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (!mstart  && !mend)
+			break;
+		else
+			nr_entries++;
+	}
+	if (nr_entries == CRASH_MAX_MEMMAP_NR)
+		/* List if full */
+		return -1;
+
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (mstart == 0 && mend == 0)
+			/* Did not find the segment in the list. */
+			return -1;
+		if (mstart <= addr && mend >= (addr + size - 1)) {
+			if (mstart == addr && mend == (addr + size - 1)) {
+				/* Exact match. Delete region */
+				operation = -1;
+				tidx = i;
+				break;
+			}
+			if (mstart != addr && mend != (addr + size - 1)) {
+				/* Split in two */
+				memmap_p[i].end = addr - 1;
+				temp_region.start = addr + size;
+				temp_region.end = mend;
+				operation = 1;
+				tidx = i;
+				break;
+			}
+
+			/* No addition/deletion required. Adjust the existing.*/
+			if (mstart != addr) {
+				memmap_p[i].end = addr - 1;
+				break;
+			} else {
+				memmap_p[i].start = addr + size;
+				break;
+			}
+		}
+	}
+	if ((operation == 1) && tidx >=0) {
+		/* Insert the split memory region. */
+		for (j = nr_entries-1; j > tidx; j--)
+			memmap_p[j+1] = memmap_p[j];
+		memmap_p[tidx+1] = temp_region;
+	}
+	if ((operation == -1) && tidx >=0) {
+		/* Delete the exact match memory region. */
+		for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++)
+			memmap_p[j-1] = memmap_p[j];
+		memmap_p[j-1].start = memmap_p[j-1].end = 0;
+	}
+#if 0
+	printf("Memmap after deleting segment\n");
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (mstart == 0 && mend == 0) {
+			break;
+		}
+		printf("%016llx - %016llx\n",
+			mstart, mend);
+	}
+#endif
+	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;
+	}
+}
+
+/* Adds the appropriate memmap= options to command line, indicating the
+ * memory regions the new kernel can use to boot into. */
+static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p)
+{
+	int i, cmdlen, len, min_sizek = 100;
+	char str_mmap[256], str_tmp[20];
+
+	/* Exact map */
+	strcpy(str_mmap, " memmap=exactmap");
+	len = strlen(str_mmap);
+	cmdlen = strlen(cmdline) + len;
+	if (cmdlen > (COMMAND_LINE_SIZE - 1))
+		die("Command line overflow\n");
+	strcat(cmdline, str_mmap);
+
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		unsigned long startk, endk;
+		startk = (memmap_p[i].start/1024);
+		endk = ((memmap_p[i].end + 1)/1024);
+		if (!startk && !endk)
+			/* All regions traversed. */
+			break;
+
+		/* A region is not worth adding if region size < 100K. It eats
+		 * up precious command line length. */
+		if ((endk - startk) < min_sizek)
+			continue;
+		strcpy (str_mmap, " memmap=");
+		ultoa((endk-startk), str_tmp);
+		strcat (str_mmap, str_tmp);
+		strcat (str_mmap, "K@");
+		ultoa(startk, str_tmp);
+		strcat (str_mmap, str_tmp);
+		strcat (str_mmap, "K");
+		len = strlen(str_mmap);
+		cmdlen = strlen(cmdline) + len;
+		if (cmdlen > (COMMAND_LINE_SIZE - 1))
+			die("Command line overflow\n");
+		strcat(cmdline, str_mmap);
+	}
+
+#if 0
+		printf("Command line after adding memmap\n");
+		printf("%s\n", cmdline);
+#endif
+	return 0;
+}
+
+/* Adds the elfcorehdr= command line parameter to command line. */
+static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr)
+{
+	int cmdlen, len, align = 1024;
+	char str[30], *ptr;
+
+	/* Passing in elfcorehdr=xxxK format. Saves space required in cmdline.
+	 * Ensure 1K alignment*/
+	if (addr%align)
+		return -1;
+	addr = addr/align;
+	ptr = str;
+	strcpy(str, " elfcorehdr=");
+	ptr += strlen(str);
+	ultoa(addr, ptr);
+	strcat(str, "K");
+	len = strlen(str);
+	cmdlen = strlen(cmdline) + len;
+	if (cmdlen > (COMMAND_LINE_SIZE - 1))
+		die("Command line overflow\n");
+	strcat(cmdline, str);
+#if 0
+		printf("Command line after adding elfcorehdr\n");
+		printf("%s\n", cmdline);
+#endif
+	return 0;
+}
+
+
+/*
+ * This routine is specific to i386 architecture to maintain the
+ * backward compatibility, other architectures can use the per
+ * cpu version get_crash_notes_per_cpu() directly.
+ */
+static int get_crash_notes(int cpu, uint64_t *addr)
+{
+	char crash_notes[PATH_MAX];
+	char line[MAX_LINE];
+	FILE *fp;
+	unsigned long vaddr;
+	int count;
+
+	sprintf(crash_notes, "/sys/kernel/crash_notes");
+	fp = fopen(crash_notes, "r");
+	if (fp) {
+		if (fgets(line, sizeof(line), fp) != 0) {
+			count = sscanf(line, "%lx", &vaddr);
+			if (count != 1)
+				die("Cannot parse %s: %s\n", crash_notes,
+						strerror(errno));
+		}
+		*addr = __pa(vaddr + (cpu * MAX_NOTE_BYTES));
+#if 0
+		printf("crash_notes addr = %Lx\n", *addr);
+#endif
+		return 0;
+	} else
+		return get_crash_notes_per_cpu(cpu, addr);
+}
+
+/* Prepares the crash memory elf64 headers and stores in supplied buffer. */
+static int prepare_crash_memory_elf64_headers(struct kexec_info *info,
+						void *buf, unsigned long size)
+{
+	Elf64_Ehdr *elf;
+	Elf64_Phdr *phdr;
+	int i;
+	char *bufp;
+	long int nr_cpus = 0;
+	uint64_t notes_addr;
+
+	bufp = (char*) buf;
+
+	/* Setup ELF Header*/
+	elf = (Elf64_Ehdr *) bufp;
+	bufp += sizeof(Elf64_Ehdr);
+	memcpy(elf->e_ident, ELFMAG, SELFMAG);
+	elf->e_ident[EI_CLASS]  = ELFCLASS64;
+	elf->e_ident[EI_DATA]   = ELFDATA2LSB;
+	elf->e_ident[EI_VERSION]= EV_CURRENT;
+	elf->e_ident[EI_OSABI] = ELFOSABI_NONE;
+	memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+	elf->e_type	= ET_CORE;
+	elf->e_machine	= EM_386;
+	elf->e_version	= EV_CURRENT;
+	elf->e_entry	= 0;
+	elf->e_phoff	= sizeof(Elf64_Ehdr);
+	elf->e_shoff	= 0;
+	elf->e_flags	= 0;
+	elf->e_ehsize   = sizeof(Elf64_Ehdr);
+	elf->e_phentsize= sizeof(Elf64_Phdr);
+	elf->e_phnum    = 0;
+	elf->e_shentsize= 0;
+	elf->e_shnum    = 0;
+	elf->e_shstrndx = 0;
+
+	/* PT_NOTE program headers. One per cpu*/
+	nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (nr_cpus < 0) {
+		return -1;
+	}
+
+	for (i = 0; i < nr_cpus; i++) {
+		if (get_crash_notes(i, &notes_addr) < 0) {
+			/* This cpu is not present. Skip it. */
+			continue;
+		}
+		phdr = (Elf64_Phdr *) bufp;
+		bufp += sizeof(Elf64_Phdr);
+		phdr->p_type	= PT_NOTE;
+		phdr->p_flags	= 0;
+		phdr->p_offset	= phdr->p_paddr = notes_addr;
+		phdr->p_vaddr	= 0;
+		phdr->p_filesz	= phdr->p_memsz	= MAX_NOTE_BYTES;
+		/* Do we need any alignment of segments? */
+		phdr->p_align	= 0;
+
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+
+	/* Setup PT_LOAD type program header for every system RAM chunk.
+	 * A seprate program header for Backup Region*/
+	for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+		unsigned long long mstart, mend;
+		if (crash_memory_range[i].type != RANGE_RAM)
+			continue;
+		mstart = crash_memory_range[i].start;
+		mend = crash_memory_range[i].end;
+		if (!mstart && !mend)
+			continue;
+		phdr = (Elf64_Phdr *) bufp;
+		bufp += sizeof(Elf64_Phdr);
+		phdr->p_type	= PT_LOAD;
+		phdr->p_flags	= PF_R|PF_W|PF_X;
+		if (mstart == BACKUP_START && mend == BACKUP_END)
+			phdr->p_offset	= info->backup_start;
+		else
+			phdr->p_offset	= mstart;
+		/* Handle linearly mapped region.*/
+		if (mend <= (MAXMEM - 1))
+			phdr->p_vaddr = mstart + PAGE_OFFSET;
+		else
+			phdr->p_vaddr = -1ULL;
+		phdr->p_paddr = mstart;
+		phdr->p_filesz	= phdr->p_memsz	= mend - mstart + 1;
+		/* Do we need any alignment of segments? */
+		phdr->p_align	= 0;
+
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+	return 0;
+}
+
+/* Prepares the crash memory elf32 headers and stores in supplied buffer. */
+static int prepare_crash_memory_elf32_headers(struct kexec_info *info,
+						void *buf, unsigned long size)
+{
+	Elf32_Ehdr *elf;
+	Elf32_Phdr *phdr;
+	int i;
+	char *bufp;
+	long int nr_cpus = 0;
+	uint64_t notes_addr;
+
+	bufp = (char*) buf;
+
+	/* Setup ELF Header*/
+	elf = (Elf32_Ehdr *) bufp;
+	bufp += sizeof(Elf32_Ehdr);
+	memcpy(elf->e_ident, ELFMAG, SELFMAG);
+	elf->e_ident[EI_CLASS]  = ELFCLASS32;
+	elf->e_ident[EI_DATA]   = ELFDATA2LSB;
+	elf->e_ident[EI_VERSION]= EV_CURRENT;
+	elf->e_ident[EI_OSABI] = ELFOSABI_NONE;
+	memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+	elf->e_type	= ET_CORE;
+	elf->e_machine	= EM_386;
+	elf->e_version	= EV_CURRENT;
+	elf->e_entry	= 0;
+	elf->e_phoff	= sizeof(Elf32_Ehdr);
+	elf->e_shoff	= 0;
+	elf->e_flags	= 0;
+	elf->e_ehsize   = sizeof(Elf32_Ehdr);
+	elf->e_phentsize= sizeof(Elf32_Phdr);
+	elf->e_phnum    = 0;
+	elf->e_shentsize= 0;
+	elf->e_shnum    = 0;
+	elf->e_shstrndx = 0;
+
+	/* PT_NOTE program headers. One per cpu*/
+	nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (nr_cpus < 0) {
+		return -1;
+	}
+
+	/* Need to find a better way to determine per cpu notes section size. */
+#define MAX_NOTE_BYTES	1024
+	for (i = 0; i < nr_cpus; i++) {
+		if (get_crash_notes(i, &notes_addr) < 0) {
+			/* This cpu is not present. Skip it. */
+			return -1;
+		}
+		phdr = (Elf32_Phdr *) bufp;
+		bufp += sizeof(Elf32_Phdr);
+		phdr->p_type	= PT_NOTE;
+		phdr->p_flags	= 0;
+		phdr->p_offset	= phdr->p_paddr = notes_addr;
+		phdr->p_vaddr	= 0;
+		phdr->p_filesz	= phdr->p_memsz	= MAX_NOTE_BYTES;
+		/* Do we need any alignment of segments? */
+		phdr->p_align	= 0;
+
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+
+	/* Setup PT_LOAD type program header for every system RAM chunk.
+	 * A seprate program header for Backup Region*/
+	for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+		unsigned long long mstart, mend;
+		if (crash_memory_range[i].type != RANGE_RAM)
+			continue;
+		mstart = crash_memory_range[i].start;
+		mend = crash_memory_range[i].end;
+		if (!mstart && !mend)
+			continue;
+		phdr = (Elf32_Phdr *) bufp;
+		bufp += sizeof(Elf32_Phdr);
+		phdr->p_type	= PT_LOAD;
+		phdr->p_flags	= PF_R|PF_W|PF_X;
+		if (mstart == BACKUP_START && mend == BACKUP_END)
+			phdr->p_offset	= info->backup_start;
+		else
+			phdr->p_offset	= mstart;
+		/* Handle linearly mapped region.*/
+		if (mend <= (MAXMEM - 1))
+			phdr->p_vaddr = mstart + PAGE_OFFSET;
+		else
+			phdr->p_vaddr = UINT_MAX;
+		phdr->p_paddr = mstart;
+		phdr->p_filesz	= phdr->p_memsz	= mend - mstart + 1;
+		/* Do we need any alignment of segments? */
+		phdr->p_align	= 0;
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+	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, *memmap_p;
+
+	if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
+		return -1;
+
+	/* Memory regions which panic kernel can safely use to boot into */
+	sz = (sizeof(struct memory_range) * (KEXEC_MAX_SEGMENTS + 1));
+	memmap_p = xmalloc(sz);
+	memset(memmap_p, 0, sz);
+	add_memmap(memmap_p, BACKUP_START, BACKUP_SIZE);
+	sz = crash_reserved_mem.end - crash_reserved_mem.start +1;
+	add_memmap(memmap_p, crash_reserved_mem.start, sz);
+
+	/* 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);
+	if (delete_memmap(memmap_p, info->backup_start, sz) < 0)
+		return -1;
+
+	/* 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;
+	} else {
+		if (prepare_crash_memory_elf32_headers(info, tmp, sz) < 0)
+			return -1;
+	}
+
+	/* Hack: With some ld versions (GNU ld version 2.14.90.0.4 20030523),
+	 * vmlinux program headers show a gap of two pages between bss segment
+	 * and data segment but effectively kernel considers it as bss segment
+	 * and overwrites the any data placed there. Hence bloat the memsz of
+	 * elf core header segment to 16K to avoid being placed in such gaps.
+	 * This is a makeshift solution until it is fixed in kernel.
+	 */
+	elfcorehdr = add_buffer(info, tmp, sz, 16*1024, align, min_base,
+							max_addr, 1);
+	if (delete_memmap(memmap_p, elfcorehdr, sz) < 0)
+		return -1;
+	cmdline_add_memmap(mod_cmdline, memmap_p);
+	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
+	return 0;
+}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/crashdump-x86.h kexec-tools-1.101-kdump/kexec/arch/i386/crashdump-x86.h
--- kexec-tools-1.101/kexec/arch/i386/crashdump-x86.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/crashdump-x86.h	2006-01-19 11:41:30.000000000 +0530
@@ -0,0 +1,21 @@
+#ifndef CRASHDUMP_X86_H
+#define CRASHDUMP_X86_H
+
+int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
+				unsigned long max_addr, unsigned long min_base);
+
+#define PAGE_OFFSET	0xc0000000
+#define __pa(x)		((unsigned long)(x)-PAGE_OFFSET)
+
+#define __VMALLOC_RESERVE       (128 << 20)
+#define MAXMEM                  (-PAGE_OFFSET-__VMALLOC_RESERVE)
+
+#define CRASH_MAX_MEMMAP_NR	(KEXEC_MAX_SEGMENTS + 1)
+#define CRASH_MAX_MEMORY_RANGES	(MAX_MEMORY_RANGES + 2)
+
+/* Backup Region, First 640K of System RAM. */
+#define BACKUP_START	0x00000000
+#define BACKUP_END	0x0009ffff
+#define BACKUP_SIZE	(BACKUP_END - BACKUP_START + 1)
+
+#endif /* CRASHDUMP_X86_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/include/arch/options.h kexec-tools-1.101-kdump/kexec/arch/i386/include/arch/options.h
--- kexec-tools-1.101/kexec/arch/i386/include/arch/options.h	2004-12-22 02:23:37.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/include/arch/options.h	2006-01-19 11:41:36.000000000 +0530
@@ -6,7 +6,9 @@
 #define OPT_SERIAL_BAUD    (OPT_MAX+2)
 #define OPT_CONSOLE_VGA    (OPT_MAX+3)
 #define OPT_CONSOLE_SERIAL (OPT_MAX+4)
-#define OPT_ARCH_MAX       (OPT_MAX+5)
+#define OPT_ELF32_CORE     (OPT_MAX+5)
+#define OPT_ELF64_CORE     (OPT_MAX+6)
+#define OPT_ARCH_MAX       (OPT_MAX+7)
 
 #define KEXEC_ARCH_OPTIONS \
 	KEXEC_OPTIONS \
@@ -15,6 +17,8 @@
 	{ "serial-baud",    1, 0, OPT_SERIAL_BAUD }, \
 	{ "console-vga",    0, 0, OPT_CONSOLE_VGA }, \
 	{ "console-serial", 0, 0, OPT_CONSOLE_SERIAL }, \
+	{ "elf32-core-headers", 0, 0, OPT_ELF32_CORE }, \
+	{ "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \
 
 #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/kexec-bzImage.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-bzImage.c
--- kexec-tools-1.101/kexec/arch/i386/kexec-bzImage.c	2005-01-13 19:02:01.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/kexec-bzImage.c	2006-01-19 11:41:27.000000000 +0530
@@ -214,7 +214,7 @@ int do_bzImage_load(struct kexec_info *i
 
 	/* Fill in the information BIOS calls would normally provide. */
 	if (!real_mode_entry) {
-		setup_linux_system_parameters(real_mode);
+		setup_linux_system_parameters(real_mode, info->kexec_flags);
 	}
 
 	return 0;
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/kexec-elf-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-elf-x86.c
--- kexec-tools-1.101/kexec/arch/i386/kexec-elf-x86.c	2005-01-13 19:29:19.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/kexec-elf-x86.c	2006-01-19 11:41:32.000000000 +0530
@@ -32,10 +32,12 @@
 #include <elf.h>
 #include <x86/x86-linux.h>
 #include "../../kexec.h"
+#include "../../kexec-syscall.h"
 #include "../../kexec-elf.h"
 #include "../../kexec-elf-boot.h"
 #include "x86-linux-setup.h"
 #include "kexec-x86.h"
+#include "crashdump-x86.h"
 #include <arch/options.h>
 
 static const int probe_debug = 0;
@@ -86,7 +88,9 @@ int elf_x86_load(int argc, char **argv, 
 {
 	struct mem_ehdr ehdr;
 	const char *command_line;
+	char *modified_cmdline;
 	int command_line_len;
+	int modified_cmdline_len;
 	const char *ramdisk;
 	unsigned long entry, max_addr;
 	int arg_style;
@@ -119,6 +123,8 @@ int elf_x86_load(int argc, char **argv, 
 	 */
 	arg_style = ARG_STYLE_ELF;
 	command_line = 0;
+	modified_cmdline = 0;
+	modified_cmdline_len = 0;
 	ramdisk = 0;
 	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 		switch(opt) {
@@ -156,6 +162,20 @@ int elf_x86_load(int argc, char **argv, 
 		command_line_len = strlen(command_line) +1;
 	}
 
+	/* 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 (command_line) {
+			strncpy(modified_cmdline, command_line,
+						COMMAND_LINE_SIZE);
+			modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+		}
+		modified_cmdline_len = strlen(modified_cmdline);
+	}
+
 	/* Load the ELF executable */
 	elf_exec_build_load(info, &ehdr, buf, len);
 
@@ -203,10 +223,20 @@ int elf_x86_load(int argc, char **argv, 
 		const unsigned char *ramdisk_buf;
 		off_t ramdisk_length;
 		struct entry32_regs regs;
+		int rc = 0;
 
 		/* Get the linux parameter header */
 		hdr = xmalloc(sizeof(*hdr));
-		param_base = add_buffer(info, hdr, sizeof(*hdr), sizeof(*hdr),
+
+		/* Hack: With some ld versions, vmlinux program headers show
+		 * a gap of two pages between bss segment and data segment
+		 * but effectively kernel considers it as bss segment and
+		 * overwrites the any data placed there. Hence bloat the
+		 * memsz of parameter segment to 16K to avoid being placed
+		 * in such gaps.
+		 * This is a makeshift solution until it is fixed in kernel
+		 */
+		param_base = add_buffer(info, hdr, sizeof(*hdr), 16*1024,
 			16, 0, max_addr, 1);
 
 		/* Initialize the parameter header */
@@ -216,9 +246,19 @@ int elf_x86_load(int argc, char **argv, 
 		/* Add a ramdisk to the current image */
 		ramdisk_buf = NULL;
 		ramdisk_length = 0;
-		if (ramdisk) {
-			unsigned char *ramdisk_buf;
+		if (ramdisk)
 			ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
+
+		/* If panic kernel is being loaded, additional segments need
+		 * to be created. */
+		if (info->kexec_flags & KEXEC_ON_CRASH) {
+			rc = load_crashdump_segments(info, modified_cmdline,
+						max_addr, 0);
+			if (rc < 0)
+				return -1;
+			/* Use new command line. */
+			command_line = modified_cmdline;
+			command_line_len = strlen(modified_cmdline) + 1;
 		}
 
 		/* Tell the kernel what is going on */
@@ -228,7 +268,7 @@ int elf_x86_load(int argc, char **argv, 
 			ramdisk_buf, ramdisk_length);
 
 		/* Fill in the information bios calls would usually provide */
-		setup_linux_system_parameters(&hdr->hdr);
+		setup_linux_system_parameters(&hdr->hdr, info->kexec_flags);
 
 		/* Initialize the registers */
 		elf_rel_get_symbol(&info->rhdr, "entry32_regs", &regs, sizeof(regs));
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/kexec-multiboot-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-multiboot-x86.c
--- kexec-tools-1.101/kexec/arch/i386/kexec-multiboot-x86.c	2005-01-25 01:28:04.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/kexec-multiboot-x86.c	2006-01-19 11:41:27.000000000 +0530
@@ -246,7 +246,8 @@ int multiboot_x86_load(int argc, char **
 	mbi->boot_loader_name = sizeof(*mbi) + command_line_len; 
 
 	/* Memory map */
-	if ((get_memory_ranges(&range, &ranges) < 0) || ranges == 0) {
+	if ((get_memory_ranges(&range, &ranges, info->kexec_flags) < 0)
+			|| ranges == 0) {
 		fprintf(stderr, "Cannot get memory information\n");
 		return -1;
 	}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/kexec-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-x86.c
--- kexec-tools-1.101/kexec/arch/i386/kexec-x86.c	2005-02-06 04:54:35.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/kexec-x86.c	2006-01-19 18:19:07.000000000 +0530
@@ -30,14 +30,14 @@
 #include "../../kexec-elf.h"
 #include "../../kexec-syscall.h"
 #include "kexec-x86.h"
+#include "crashdump-x86.h"
 #include <arch/options.h>
 
-#define MAX_MEMORY_RANGES 64
-#define MAX_LINE 160
 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)
+int get_memory_ranges(struct memory_range **range, int *ranges,
+				unsigned long kexec_flags)
 {
 	const char iomem[]= "/proc/iomem";
 	int memory_ranges = 0;
@@ -79,6 +79,20 @@ int get_memory_ranges(struct memory_rang
 		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;
 		}
@@ -120,21 +134,18 @@ void arch_usage(void)
 		"     --serial-baud=<buad_rate> Specify the serial port baud rate\n"
 		"     --console-vga             Enable the vga console\n"
 		"     --console-serial          Enable the serial console\n"
+		"     --elf32-core-headers      Prepare core headers in ELF32 format\n"
+		"     --elf64-core-headers      Prepare core headers in ELF64 format\n"
 		);
 }
 
-static struct {
-	uint8_t  reset_vga;
-	uint16_t serial_base;
-	uint32_t serial_baud;
-	uint8_t  console_vga;
-	uint8_t  console_serial;
-} arch_options = {
+struct arch_options_t arch_options = {
 	.reset_vga   = 0,
 	.serial_base = 0x3f8,
 	.serial_baud = 0,
 	.console_vga = 0,
 	.console_serial = 0,
+	.core_header_type = CORE_TYPE_ELF64,
 };
 
 int arch_process_options(int argc, char **argv)
@@ -198,6 +209,12 @@ int arch_process_options(int argc, char 
 			}
 			arch_options.serial_baud = value;
 			break;
+		case OPT_ELF32_CORE:
+			arch_options.core_header_type = CORE_TYPE_ELF32;
+			break;
+		case OPT_ELF64_CORE:
+			arch_options.core_header_type = CORE_TYPE_ELF64;
+			break;
 		}
 	}
 	/* Reset getopt for the next pass; called in other source modules */
@@ -206,7 +223,7 @@ int arch_process_options(int argc, char 
 	return 0;
 }
 
-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
+int arch_compat_trampoline(struct kexec_info *info)
 {
 	int result;
 	struct utsname utsname;
@@ -224,11 +241,11 @@ int arch_compat_trampoline(struct kexec_
 		/* For compatibility with older patches 
 		 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_386 here.
 		 */
-		*flags |= KEXEC_ARCH_DEFAULT;
+		info->kexec_flags |= KEXEC_ARCH_DEFAULT;
 	}
 	else if (strcmp(utsname.machine, "x86_64") == 0)
 	{
-		*flags |= KEXEC_ARCH_X86_64;
+		info->kexec_flags |= KEXEC_ARCH_X86_64;
 		if (!info->rhdr.e_shdr) {
 			fprintf(stderr, 
 				"A trampoline is required for cross architecture support\n");
@@ -249,6 +266,8 @@ int arch_compat_trampoline(struct kexec_
 
 void arch_update_purgatory(struct kexec_info *info)
 {
+	uint8_t panic_kernel = 0;
+
 	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",
@@ -259,4 +278,11 @@ void arch_update_purgatory(struct kexec_
 		&arch_options.console_vga, sizeof(arch_options.console_vga));
 	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;
+		elf_rel_set_symbol(&info->rhdr, "backup_start",
+				&info->backup_start, sizeof(info->backup_start));
+	}
+	elf_rel_set_symbol(&info->rhdr, "panic_kernel",
+		&panic_kernel, sizeof(panic_kernel));
 }
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/kexec-x86.h kexec-tools-1.101-kdump/kexec/arch/i386/kexec-x86.h
--- kexec-tools-1.101/kexec/arch/i386/kexec-x86.h	2005-02-06 04:41:32.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/kexec-x86.h	2006-01-19 11:41:29.000000000 +0530
@@ -1,6 +1,10 @@
 #ifndef KEXEC_X86_H
 #define KEXEC_X86_H
 
+#define MAX_MEMORY_RANGES 64
+#define CORE_TYPE_ELF32 1
+#define CORE_TYPE_ELF64 2
+
 extern unsigned char compat_x86_64[];
 extern uint32_t compat_x86_64_size, compat_x86_64_entry32;
 
@@ -35,6 +39,15 @@ struct entry16_regs {
 	uint16_t pad;
 };
 
+struct arch_options_t {
+	uint8_t  reset_vga;
+	uint16_t serial_base;
+	uint32_t serial_baud;
+	uint8_t  console_vga;
+	uint8_t  console_serial;
+	int	 core_header_type;
+};
+
 int multiboot_x86_probe(const char *buf, off_t len);
 int multiboot_x86_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/Makefile kexec-tools-1.101-kdump/kexec/arch/i386/Makefile
--- kexec-tools-1.101/kexec/arch/i386/Makefile	2005-02-06 04:53:58.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/Makefile	2006-01-19 11:41:29.000000000 +0530
@@ -9,3 +9,4 @@ KEXEC_C_SRCS+= kexec/arch/i386/kexec-mul
 KEXEC_C_SRCS+= kexec/arch/i386/kexec-beoboot-x86.c
 KEXEC_C_SRCS+= kexec/arch/i386/kexec-nbi.c
 KEXEC_C_SRCS+= kexec/arch/i386/x86-linux-setup.c
+KEXEC_C_SRCS+= kexec/arch/i386/crashdump-x86.c
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/x86-linux-setup.c kexec-tools-1.101-kdump/kexec/arch/i386/x86-linux-setup.c
--- kexec-tools-1.101/kexec/arch/i386/x86-linux-setup.c	2005-01-13 18:40:01.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/x86-linux-setup.c	2006-02-01 14:41:09.000000000 +0530
@@ -94,7 +94,8 @@ void setup_linux_bootloader_parameters(
 	cmdline_ptr[cmdline_len - 1] = '\0';
 }
 
-void setup_linux_system_parameters(struct x86_linux_param_header *real_mode)
+void setup_linux_system_parameters(struct x86_linux_param_header *real_mode,
+					unsigned long kexec_flags)
 {
 	/* Fill in information the BIOS would usually provide */
 	struct memory_range *range;
@@ -135,7 +136,7 @@ void setup_linux_system_parameters(struc
 	real_mode->aux_device_info = 0;
 
 	/* Fill in the memory info */
-	if ((get_memory_ranges(&range, &ranges) < 0) || ranges == 0) {
+	if ((get_memory_ranges(&range, &ranges, kexec_flags) < 0) || ranges == 0) {
 		die("Cannot get memory information\n");
 	}
 	if (ranges > E820MAX) {
@@ -164,7 +165,7 @@ void setup_linux_system_parameters(struc
 		if (range[i].type != RANGE_RAM)
 			continue;
 		if ((range[i].start <= 0x100000) && range[i].end > 0x100000) {
-			unsigned long long mem_k = (range[i].end >> 10) - 0x100000;
+			unsigned long long mem_k = (range[i].end >> 10) - 0x400;
 			real_mode->ext_mem_k = mem_k;
 			real_mode->alt_mem_k = mem_k;
 			if (mem_k > 0xfc00) {
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/x86-linux-setup.h kexec-tools-1.101-kdump/kexec/arch/i386/x86-linux-setup.h
--- kexec-tools-1.101/kexec/arch/i386/x86-linux-setup.h	2004-12-20 17:50:22.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/x86-linux-setup.h	2006-01-19 11:41:27.000000000 +0530
@@ -7,7 +7,8 @@ void setup_linux_bootloader_parameters(
 	unsigned long real_mode_base, unsigned long cmdline_offset,
 	const char *cmdline, off_t cmdline_len,
 	const unsigned char *initrd_buf, off_t initrd_size);
-void setup_linux_system_parameters(struct x86_linux_param_header *real_mode);
+void setup_linux_system_parameters(struct x86_linux_param_header *real_mode,
+					unsigned long kexec_flags);
 
 
 #define SETUP_BASE    0x90000
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ia64/kexec-ia64.c kexec-tools-1.101-kdump/kexec/arch/ia64/kexec-ia64.c
--- kexec-tools-1.101/kexec/arch/ia64/kexec-ia64.c	2005-01-11 11:58:36.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ia64/kexec-ia64.c	2006-01-19 18:19:07.000000000 +0530
@@ -34,11 +34,11 @@
 #include <arch/options.h>
 
 #define MAX_MEMORY_RANGES 64
-#define MAX_LINE 160
 static struct memory_range memory_range[MAX_MEMORY_RANGES];
 
 /* Return a sorted list of available memory ranges. */
-int get_memory_ranges(struct memory_range **range, int *ranges)
+int get_memory_ranges(struct memory_range **range, int *ranges,
+				unsigned long kexec_flags)
 {
 	int memory_ranges;
 	/*
@@ -103,7 +103,7 @@ int arch_process_options(int argc, char 
 	return 0;
 }
 
-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
+int arch_compat_trampoline(struct kexec_info *info)
 {
 	int result;
 	struct utsname utsname;
@@ -115,7 +115,7 @@ int arch_compat_trampoline(struct kexec_
 	}
 	if (strcmp(utsname.machine, "ia64") == 0)
 	{
-		*flags |= KEXEC_ARCH_X86_64;
+		info->kexec_flags |= KEXEC_ARCH_X86_64;
 	}
 	else {
 		fprintf(stderr, "Unsupported machine type: %s\n",
@@ -125,7 +125,7 @@ int arch_compat_trampoline(struct kexec_
 	return 0;
 }
 
-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
+int arch_compat_trampoline(struct kexec_info *info)
 {
 	int result;
 	struct utsname utsname;
@@ -140,7 +140,7 @@ int arch_compat_trampoline(struct kexec_
 		/* For compatibility with older patches 
 		 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_IA64 here.
 		 */
-		*flags |= KEXEC_ARCH_DEFAULT;
+		info->kexec_flags |= KEXEC_ARCH_DEFAULT;
 	}
 	else {
 		fprintf(stderr, "Unsupported machine type: %s\n",
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc/kexec-ppc.c kexec-tools-1.101-kdump/kexec/arch/ppc/kexec-ppc.c
--- kexec-tools-1.101/kexec/arch/ppc/kexec-ppc.c	2005-01-11 11:58:03.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc/kexec-ppc.c	2006-01-19 18:19:07.000000000 +0530
@@ -19,11 +19,11 @@
 #include <arch/options.h>
 
 #define MAX_MEMORY_RANGES  64
-#define MAX_LINE          160
 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)
+int get_memory_ranges(struct memory_range **range, int *ranges,
+					unsigned long kexec_flags)
 {
 	int memory_ranges = 0;
 #ifdef CONFIG_GAMECUBE
@@ -120,7 +120,7 @@ int arch_process_options(int argc, char 
 	return 0;
 }
 
-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
+int arch_compat_trampoline(struct kexec_info *info)
 {
 	int result;
 	struct utsname utsname;
@@ -135,7 +135,7 @@ int arch_compat_trampoline(struct kexec_
 		/* For compatibility with older patches 
 		 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_PPC here.
 		 */
-		*flags |= KEXEC_ARCH_DEFAULT;
+		info->kexec_flags |= KEXEC_ARCH_DEFAULT;
 	}
 	else {
 		fprintf(stderr, "Unsupported machine type: %s\n",
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/crashdump-ppc64.c kexec-tools-1.101-kdump/kexec/arch/ppc64/crashdump-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/crashdump-ppc64.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/crashdump-ppc64.c	2006-01-19 18:20:07.000000000 +0530
@@ -0,0 +1,511 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: R Sharada (sharada@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2005. 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.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <elf.h>
+#include <dirent.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "../../crashdump.h"
+#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
+ */
+static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+
+/*
+ * Used to save various memory ranges/regions needed for the captured
+ * kernel to boot. (lime memmap= option in other archs)
+ */
+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
+ * create Elf headers. Keeping it separate from get_memory_ranges() as
+ * requirements are different in the case of normal kexec and crashdumps.
+ *
+ * Normal kexec needs to look at all of available physical memory irrespective
+ * of the fact how much of it is being used by currently running kernel.
+ * Crashdumps need to have access to memory regions actually being used by
+ * running  kernel. Expecting a different file/data structure than /proc/iomem
+ * to look into down the line. May be something like /proc/kernelmem or may
+ * be zone data structures exported from kernel.
+ */
+static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+{
+
+	int memory_ranges = 0;
+	char device_tree[256] = "/proc/device-tree/";
+	char fname[256];
+	char buf[MAXBYTES-1];
+	DIR *dir, *dmem;
+	FILE *file;
+	struct dirent *dentry, *mentry;
+	int i, n, match;
+	unsigned long long start, end, cstart, cend;
+
+	/* create a separate program header for the backup region */
+	crash_memory_range[0].start = 0x0000000000000000;
+	crash_memory_range[0].end = 0x0000000000008000;
+	crash_memory_range[0].type = RANGE_RAM;
+	memory_ranges++;
+
+	if ((dir = opendir(device_tree)) == NULL) {
+		perror(device_tree);
+		return -1;
+	}
+	while ((dentry = readdir(dir)) != NULL) {
+		if (strncmp(dentry->d_name, "memory@", 7))
+			continue;
+		strcpy(fname, device_tree);
+		strcat(fname, dentry->d_name);
+		if ((dmem = opendir(fname)) == NULL) {
+			perror(fname);
+			closedir(dir);
+			return -1;
+		}
+		while ((mentry = readdir(dmem)) != NULL) {
+			if (strcmp(mentry->d_name, "reg"))
+				continue;
+			strcat(fname, "/reg");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(dmem);
+				closedir(dir);
+				return -1;
+			}
+			if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+				perror(fname);
+				fclose(file);
+				closedir(dmem);
+				closedir(dir);
+				return -1;
+			}
+			if (memory_ranges >= MAX_MEMORY_RANGES)
+				break;
+			start = ((unsigned long long *)buf)[0];
+			end = start + ((unsigned long long *)buf)[1];
+			if (start == 0 && end >= 0x8000)
+				start = 0x8000;
+			match = 0;
+			sort_regions(&exclude_rgns);
+
+			/* exclude crash reserved regions */
+			for (i = 0; i < exclude_rgns.size; i++) {
+				cstart = exclude_rgns.ranges[i].start;
+				cend = exclude_rgns.ranges[i].end;
+				if (cstart < end && cend > start) {
+					if ((cstart == start) && (cend == end)) {
+						match = 1;
+						continue;
+					}
+					if (start < cstart && end > cend) {
+						match = 1;
+						crash_memory_range[memory_ranges].start = start;
+						crash_memory_range[memory_ranges].end = cstart - 1;
+						crash_memory_range[memory_ranges].type = RANGE_RAM;
+						memory_ranges++;
+						crash_memory_range[memory_ranges].start = cend + 1;
+						crash_memory_range[memory_ranges].end = end;
+						crash_memory_range[memory_ranges].type = RANGE_RAM;
+						memory_ranges++;
+						break;
+					} else if (start < cstart) {
+						match = 1;
+						crash_memory_range[memory_ranges].start = start;
+						crash_memory_range[memory_ranges].end = cstart - 1;
+						crash_memory_range[memory_ranges].type = RANGE_RAM;
+						memory_ranges++;
+						end = cstart - 1;
+						continue;
+					} else if (end > cend){
+						match = 1;
+						crash_memory_range[memory_ranges].start = cend + 1;
+						crash_memory_range[memory_ranges].end = end;
+						crash_memory_range[memory_ranges].type = RANGE_RAM;
+						memory_ranges++;
+						start = cend + 1;
+						continue;
+					}
+				}
+
+			} /* end of for loop */
+			if (!match) {
+				crash_memory_range[memory_ranges].start = start;
+				crash_memory_range[memory_ranges].end  = end;
+				crash_memory_range[memory_ranges].type = RANGE_RAM;
+				memory_ranges++;
+			}
+
+			fclose(file);
+		}
+		closedir(dmem);
+	}
+	closedir(dir);
+
+	/*
+	 * Can not trust the memory regions order that we read from
+	 * device-tree. Hence, get the MAX end value.
+	 */
+	for (i = 0; i < memory_ranges; i++)
+		if (saved_max_mem < crash_memory_range[i].end)
+			saved_max_mem = crash_memory_range[i].end;
+
+	*range = crash_memory_range;
+	*ranges = memory_ranges;
+#if DEBUG
+	int i;
+	printf("CRASH MEMORY RANGES\n");
+	for(i = 0; i < *ranges; i++) {
+		start = crash_memory_range[i].start;
+		end = crash_memory_range[i].end;
+		fprintf(stderr, "%016Lx-%016Lx\n", start, end);
+	}
+#endif
+	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;
+}
+
+/* Prepares the crash memory elf64 headers and stores in supplied buffer. */
+static int prepare_crash_memory_elf64_headers(struct kexec_info *info,
+						void *buf, unsigned long size)
+{
+	Elf64_Ehdr *elf;
+	Elf64_Phdr *phdr;
+	int i;
+	char *bufp;
+	long int nr_cpus = 0;
+	unsigned long notes_addr;
+
+	bufp = (char*) buf;
+
+	/* Setup ELF Header*/
+	elf = (Elf64_Ehdr *) bufp;
+	bufp += sizeof(Elf64_Ehdr);
+	memcpy(elf->e_ident, ELFMAG, SELFMAG);
+	elf->e_ident[EI_CLASS]  = ELFCLASS64;
+	elf->e_ident[EI_DATA]   = ELFDATA2MSB;
+	elf->e_ident[EI_VERSION]= EV_CURRENT;
+	elf->e_ident[EI_OSABI] = ELFOSABI_NONE;
+	memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+	elf->e_type     = ET_CORE;
+	elf->e_machine  = EM_PPC64;
+	elf->e_version  = EV_CURRENT;
+	elf->e_entry    = 0;
+	elf->e_phoff    = sizeof(Elf64_Ehdr);
+	elf->e_shoff    = 0;
+	elf->e_flags    = 0;
+	elf->e_ehsize   = sizeof(Elf64_Ehdr);
+	elf->e_phentsize= sizeof(Elf64_Phdr);
+	elf->e_phnum    = 0;
+	elf->e_shentsize= 0;
+	elf->e_shnum    = 0;
+	elf->e_shstrndx = 0;
+
+	/* PT_NOTE program headers. One per cpu*/
+	nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (nr_cpus < 0)
+		return -1;
+
+	/* Need to find a better way to determine per cpu notes section size. */
+#define MAX_NOTE_BYTES  1024
+	for (i = 0; i < nr_cpus; i++) {
+		if (get_crash_notes_per_cpu(i, &notes_addr) < 0) {
+			/* This cpu is not present. Skip it. */
+			continue;
+		}
+		phdr = (Elf64_Phdr *) bufp;
+		bufp += sizeof(Elf64_Phdr);
+		phdr->p_type    = PT_NOTE;
+		phdr->p_flags   = 0;
+		phdr->p_offset  = phdr->p_paddr =  notes_addr;
+		phdr->p_vaddr   = 0;
+		phdr->p_filesz  = phdr->p_memsz = MAX_NOTE_BYTES;
+		/* Do we need any alignment of segments? */
+		phdr->p_align   = 0;
+
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+
+	/* Setup PT_LOAD type program header for every system RAM chunk.
+	 * A seprate program header for Backup Region
+	 */
+	for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+		unsigned long long mstart, mend;
+		mstart = crash_memory_range[i].start;
+		mend = crash_memory_range[i].end;
+		if (!mstart && !mend)
+			break;
+		phdr = (Elf64_Phdr *) bufp;
+		bufp += sizeof(Elf64_Phdr);
+		phdr->p_type    = PT_LOAD;
+		phdr->p_flags   = PF_R|PF_W|PF_X;
+		if (mstart == BACKUP_START && mend == BACKUP_END)
+			phdr->p_offset  = info->backup_start;
+		else
+			phdr->p_offset  = mstart;
+		/* Handle linearly mapped region.*/
+		if (mend <= (MAXMEM - 1))
+			phdr->p_vaddr = mstart + PAGE_OFFSET;
+		else
+			phdr->p_vaddr = -1ULL;
+		phdr->p_paddr = mstart;
+		phdr->p_filesz  = phdr->p_memsz = mend - mstart;
+		/* Do we need any alignment of segments? */
+		phdr->p_align   = 0;
+
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+	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.
+ */
+
+void add_usable_mem_rgns(unsigned long long base, unsigned long long size)
+{
+	int i;
+	unsigned long long end = base + size;
+	unsigned long long ustart, uend;
+
+	base = _ALIGN_DOWN(base, PAGE_SIZE);
+	end = _ALIGN_UP(end, PAGE_SIZE);
+
+	for (i=0; i < usablemem_rgns.size; i++) {
+		ustart = usablemem_rgns.ranges[i].start;
+		uend = usablemem_rgns.ranges[i].end;
+		if (base < uend && end > ustart) {
+			if ((base >= ustart) && (end <= uend))
+				return;
+			if (base < ustart && end > uend) {
+				usablemem_rgns.ranges[i].start = base;
+				usablemem_rgns.ranges[i].end = end;
+				return;
+			} else if (base < ustart) {
+				usablemem_rgns.ranges[i].start = base;
+				return;
+			} else if (end > uend){
+				usablemem_rgns.ranges[i].end = end;
+				return;
+			}
+		}
+	}
+	usablemem_rgns.ranges[usablemem_rgns.size].start = base;
+	usablemem_rgns.ranges[usablemem_rgns.size++].end = end;
+
+#ifdef DEBUG
+	fprintf(stderr, "usable memory rgns size:%d base:%lx size:%lx\n", usablemem_rgns.size, base, size);
+#endif
+}
+
+/*
+ * Used to exclude various memory regions that do not need elf hdr generation
+ */
+
+void add_exclude_rgns(unsigned long long base, unsigned long long size)
+{
+	int i;
+	unsigned long long end = base + size;
+	unsigned long long xstart, xend;
+
+	for (i=0; i < exclude_rgns.size; i++) {
+		xstart = exclude_rgns.ranges[i].start;
+		xend = exclude_rgns.ranges[i].end;
+		if (base < xend && end > xstart) {
+			if ((base >= xstart) && (end <= xend))
+				return;
+			if (base < xstart && end > xend) {
+				exclude_rgns.ranges[i].start = base;
+				exclude_rgns.ranges[i].end = end;
+				return;
+			} else if (base < xstart) {
+				exclude_rgns.ranges[i].start = base;
+				exclude_rgns.ranges[i].end = xend;
+				return;
+			} else if (end > xend){
+				exclude_rgns.ranges[i].start = xstart;
+				exclude_rgns.ranges[i].end = end;
+				return;
+			}
+		}
+	}
+	exclude_rgns.ranges[exclude_rgns.size].start = base;
+	exclude_rgns.ranges[exclude_rgns.size++].end = end;
+
+#ifdef DEBUG
+	fprintf(stderr, "exclude rgns size:%d base:%lx end:%lx size:%lx\n", exclude_rgns.size, base, end, size);
+#endif
+}
+
+static int sort_regions(mem_rgns_t *rgn)
+{
+	int i, j;
+	unsigned long long tstart, tend;
+	for (i = 0; i < rgn->size; i++) {
+		for (j = 0; j < rgn->size - i - 1; j++) {
+			if (rgn->ranges[j].start > rgn->ranges[j+1].start) {
+				tstart = rgn->ranges[j].start;
+				tend = rgn->ranges[j].end;
+				rgn->ranges[j].start = rgn->ranges[j+1].start;
+				rgn->ranges[j].end = rgn->ranges[j+1].end;
+				rgn->ranges[j+1].start = tstart;
+				rgn->ranges[j+1].end = tend;
+			}
+		}
+	}
+	return 0;
+
+}
+
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/crashdump-ppc64.h kexec-tools-1.101-kdump/kexec/arch/ppc64/crashdump-ppc64.h
--- kexec-tools-1.101/kexec/arch/ppc64/crashdump-ppc64.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/crashdump-ppc64.h	2006-02-22 11:30:11.080108112 +0530
@@ -0,0 +1,35 @@
+#ifndef CRASHDUMP_PPC64_H
+#define CRASHDUMP_PPC64_H
+
+int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
+				unsigned long max_addr, unsigned long min_base);
+void add_usable_mem_rgns(unsigned long long base, unsigned long long size);
+void add_exclude_rgns(unsigned long long base, unsigned long long size);
+
+#define PAGE_OFFSET      0xC000000000000000
+#define KERNELBASE      PAGE_OFFSET
+#define VMALLOCBASE     0xD000000000000000
+
+#define __pa(x)         ((unsigned long)(x)-PAGE_OFFSET)
+
+#define MAXMEM                  (-KERNELBASE-VMALLOCBASE)
+
+#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 6)
+
+#define COMMAND_LINE_SIZE       512 /* from kernel */
+/* Backup Region, First 32K of System RAM. */
+#define BACKUP_START    0x0000
+#define BACKUP_END      0x8000
+#define BACKUP_SIZE     (BACKUP_END - BACKUP_START + 1)
+
+#define KDUMP_BACKUP_LIMIT      0x8000
+#define _ALIGN_UP(addr,size)     (((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr,size)   ((addr)&(~((size)-1)))
+#ifndef PAGE_SIZE
+#define PAGE_SIZE      4096
+#endif
+
+extern unsigned long long crash_base;
+extern unsigned long long crash_size;
+
+#endif /* CRASHDUMP_PPC64_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/fs2dt.c kexec-tools-1.101-kdump/kexec/arch/ppc64/fs2dt.c
--- kexec-tools-1.101/kexec/arch/ppc64/fs2dt.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/fs2dt.c	2006-02-22 11:41:54.993097072 +0530
@@ -0,0 +1,462 @@
+/*
+ * fs2dt: creates a flattened device-tree
+ *
+ * Copyright (C) 2004,2005  Milton D Miller II, IBM Corporation
+ * Copyright (C) 2005  R Sharada (sharada@in.ibm.com), IBM Corporation
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "../../kexec.h"
+#include "kexec-ppc64.h"
+#include "crashdump-ppc64.h"
+
+#define MAXPATH 1024		/* max path name length */
+#define NAMESPACE 16384		/* max bytes for property names */
+#define TREEWORDS 65536		/* max 32 bit words for property values */
+#define MEMRESERVE 256		/* max number of reserved memory blocks */
+
+enum {
+	ERR_NONE,
+	ERR_USAGE,
+	ERR_OPENDIR,
+	ERR_READDIR,
+	ERR_STAT,
+	ERR_OPEN,
+	ERR_READ,
+	ERR_RESERVE,
+};
+
+void err(const char *str, int rc)
+{
+	if (errno)
+		perror(str);
+	else
+		fprintf(stderr, "%s: unrecoverable error\n", str);
+	exit(rc);
+}
+
+typedef unsigned dvt;
+struct stat statbuf[1];
+char pathname[MAXPATH], *pathstart;
+char propnames[NAMESPACE];
+dvt dtstruct[TREEWORDS], *dt;
+unsigned long long mem_rsrv[2*MEMRESERVE];
+
+static int initrd_found = 0;
+static int crash_param = 0;
+char local_cmdline[COMMAND_LINE_SIZE] = { "" };
+dvt *dt_len; /* changed len of modified cmdline in flat device-tree */
+extern mem_rgns_t usablemem_rgns;
+struct bootblock bb[1];
+
+void reserve(unsigned long long where, unsigned long long length)
+{
+	unsigned long long *mr;
+
+	mr = mem_rsrv;
+
+	while(mr[1])
+		mr += 2;
+
+	mr[0] = where;
+	mr[1] = length;
+}
+
+/* look for properties we need to reserve memory space for */
+void checkprop(char *name, dvt *data)
+{
+	static unsigned long long base, size, end;
+
+	if ((data == NULL) && (base || size || end))
+			err((void *)data, ERR_RESERVE);
+	else if (!strcmp(name, "linux,rtas-base"))
+		base = *data;
+	else if (!strcmp(name, "linux,tce-base"))
+		base = *(unsigned long long *) data;
+	else if (!strcmp(name, "rtas-size") ||
+			!strcmp(name, "linux,tce-size"))
+		size = *data;
+
+	if (size && end)
+		err(name, ERR_RESERVE);
+	if (base && size) {
+		reserve(base, size);
+		base = size = 0;
+	}
+	if (base && end) {
+		reserve(base, end-base);
+		base = end = 0;
+	}
+}
+
+/*
+ * return the property index for a property name, creating a new one
+ * if needed.
+ */
+dvt propnum(const char *name)
+{
+	dvt offset = 0;
+
+	while(propnames[offset])
+		if (strcmp(name, propnames+offset))
+			offset += strlen(propnames+offset)+1;
+		else
+			return offset;
+
+	strcpy(propnames+offset, name);
+
+	return offset;
+}
+
+void add_usable_mem_property(int fd, int len)
+{
+	char fname[MAXPATH], *bname;
+	char buf[MAXBYTES +1];
+	unsigned long ranges[2*MAX_MEMORY_RANGES];
+	unsigned long long base, end, loc_base, loc_end;
+	int range, rlen = 0;
+
+	strcpy(fname, pathname);
+	bname = strrchr(fname,'/');
+	bname[0] = '\0';
+	bname = strrchr(fname,'/');
+	if (strncmp(bname, "/memory@", 8))
+		return;
+
+	lseek(fd, 0, SEEK_SET);
+	if (read(fd, buf, len) != len)
+		err(pathname, ERR_READ);
+
+	base = ((unsigned long long *)buf)[0];
+	end = base + ((unsigned long long *)buf)[1];
+
+	for (range = 0; range < usablemem_rgns.size; range++) {
+		loc_base = usablemem_rgns.ranges[range].start;
+		loc_end = usablemem_rgns.ranges[range].end;
+		if (loc_base >= base && loc_end <= end) {
+			ranges[rlen++] = loc_base;
+			ranges[rlen++] = loc_end - loc_base;
+		} else if (base < loc_end && end > loc_base) {
+			if (loc_base < base)
+				loc_base = base;
+			if (loc_end > end)
+				loc_end = end;
+			ranges[rlen++] = loc_base;
+			ranges[rlen++] = loc_end - loc_base;
+		}
+	}
+
+	if (!rlen) {
+		/*
+		 * User did not pass any ranges for thsi region. Hence, write
+		 * (0,0) duple in linux,usable-memory property such that
+		 * this region will be ignored.
+		 */
+		ranges[rlen++] = 0;
+		ranges[rlen++] = 0;
+	}
+
+	rlen = rlen * sizeof(unsigned long);
+	/*
+	 * No add linux,usable-memory property.
+	 */
+	*dt++ = 3;
+	*dt++ = rlen;
+	*dt++ = propnum("linux,usable-memory");
+	if ((rlen >= 8) && ((unsigned long)dt & 0x4))
+		dt++;
+	memcpy(dt,&ranges,rlen);
+	dt += (rlen + 3)/4;
+}
+
+/* put all properties (files) in the property structure */
+void putprops(char *fn, struct dirent **nlist, int numlist)
+{
+	struct dirent *dp;
+	int i = 0;
+
+	for (i = 0; i < numlist; i++) {
+		dp = nlist[i];
+		strcpy(fn, dp->d_name);
+
+		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+                        continue;
+
+		if (lstat(pathname, statbuf))
+			err(pathname, ERR_STAT);
+
+		if (!crash_param && !strcmp(fn,"linux,crashkernel-base"))
+			continue;
+
+		if (!crash_param && !strcmp(fn,"linux,crashkernel-size"))
+			continue;
+
+		/*
+		 * This property will be created for each node during kexec
+		 * boot. So, ignore it.
+		 */
+		if (!strcmp(dp->d_name, "linux,pci-domain") ||
+			!strcmp(dp->d_name, "linux,htab-base") ||
+			!strcmp(dp->d_name, "linux,htab-size") ||
+			!strcmp(dp->d_name, "linux,kernel-end"))
+				continue;
+
+		/* This property will be created/modified later in putnode()
+		 * So ignore it.
+		 */
+		if (!strcmp(dp->d_name, "linux,initrd-start") ||
+			!strcmp(dp->d_name, "linux,initrd-end"))
+				continue;
+
+		if (S_ISREG(statbuf[0].st_mode)) {
+			int fd, len = statbuf[0].st_size;
+
+			*dt++ = 3;
+			dt_len = dt;
+			*dt++ = len;
+			*dt++ = propnum(fn);
+
+			if ((len >= 8) && ((unsigned long)dt & 0x4))
+				dt++;
+
+			fd = open(pathname, O_RDONLY);
+			if (fd == -1)
+				err(pathname, ERR_OPEN);
+
+			if (read(fd, dt, len) != len)
+				err(pathname, ERR_READ);
+
+			checkprop(fn, dt);
+
+			/* Get the cmdline from the device-tree and modify it */
+			if (!strcmp(dp->d_name, "bootargs")) {
+				int cmd_len;
+				char temp_cmdline[COMMAND_LINE_SIZE] = { "" };
+				char *param = NULL;
+				cmd_len = strlen(local_cmdline);
+				if (cmd_len != 0) {
+					param = strstr(local_cmdline,
+							"crashkernel=");
+					if (param)
+						crash_param = 1;
+					param = strstr(local_cmdline, "root=");
+				}
+				if (!param) {
+					char *old_param;
+					memcpy(temp_cmdline, dt, len);
+					param = strstr(temp_cmdline, "root=");
+					old_param = strtok(param, " ");
+					if (cmd_len != 0)
+						strcat(local_cmdline, " ");
+					strcat(local_cmdline, old_param);
+				}
+				strcat(local_cmdline, " ");
+				cmd_len = strlen(local_cmdline);
+				cmd_len = cmd_len + 1;
+				memcpy(dt,local_cmdline,cmd_len);
+				len = cmd_len;
+				*dt_len = cmd_len;
+				fprintf(stderr, "Modified cmdline:%s\n", local_cmdline);
+			}
+
+			dt += (len + 3)/4;
+			if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size)
+				add_usable_mem_property(fd, len);
+			close(fd);
+		}
+	}
+	fn[0] = '\0';
+	if(errno == ENOSYS)
+		errno = 0;
+	if (errno)
+		err(pathname, ERR_READDIR);
+	checkprop(pathname, NULL);
+}
+
+/*
+ * Compare function used to sort the device-tree directories
+ * This function will be passed to scandir.
+ */
+int comparefunc(const void *dentry1, const void *dentry2)
+{
+	char *str1 = (*(struct dirent **)dentry1)->d_name;
+	char *str2 = (*(struct dirent **)dentry2)->d_name;
+
+	/*
+	 * strcmp scans from left to right and fails to idetify for some
+	 * strings such as memory@10000000 and memory@f000000.
+	 * Therefore, we get the wrong sorted order like memory@10000000 and
+	 * memory@f000000.
+	 */
+	if (strchr(str1, '@') && strchr(str2, '@') &&
+		(strlen(str1) > strlen(str2)))
+		return 1;
+
+	return strcmp(str1, str2);
+}
+
+/*
+ * put a node (directory) in the property structure.  first properties
+ * then children.
+ */
+void putnode(void)
+{
+	char *dn;
+	struct dirent *dp;
+	char *basename;
+	struct dirent **namelist;
+	int numlist, i;
+
+	*dt++ = 1;
+	strcpy((void *)dt, *pathstart ? pathstart : "/");
+	while(*dt)
+		dt++;
+	if (dt[-1] & 0xff)
+		dt++;
+
+	numlist = scandir(pathname, &namelist, 0, comparefunc);
+	if (numlist == 0)
+		err(pathname, ERR_OPENDIR);
+
+	basename = strrchr(pathname,'/');
+
+	strcat(pathname, "/");
+	dn = pathname + strlen(pathname);
+
+	putprops(dn, namelist, numlist);
+
+	/* Add initrd entries to the second kernel if first kernel does not
+	 * have and second kernel needs.
+	 */
+	if (initrd_base && !initrd_found && !strcmp(basename,"/chosen/")) {
+		int len = 8;
+		unsigned long long initrd_end;
+		*dt++ = 3;
+		*dt++ = len;
+		*dt++ = propnum("linux,initrd-start");
+
+		if ((len >= 8) && ((unsigned long)dt & 0x4))
+			dt++;
+
+		memcpy(dt,&initrd_base,len);
+		dt += (len + 3)/4;
+
+		len = 8;
+		*dt++ = 3;
+		*dt++ = len;
+		*dt++ = propnum("linux,initrd-end");
+
+		initrd_end = initrd_base + initrd_size;
+		if ((len >= 8) && ((unsigned long)dt & 0x4))
+			dt++;
+
+		memcpy(dt,&initrd_end,len);
+		dt += (len + 3)/4;
+
+		reserve(initrd_base, initrd_size);
+	}
+
+	for (i=0; i < numlist; i++) {
+		dp = namelist[i];
+		strcpy(dn, dp->d_name);
+		free(namelist[i]);
+
+		if (!strcmp(dn, ".") || !strcmp(dn, ".."))
+			continue;
+
+		if (lstat(pathname, statbuf))
+			err(pathname, ERR_STAT);
+
+		if (S_ISDIR(statbuf[0].st_mode))
+			putnode();
+	}
+	if (errno)
+		err(pathname, ERR_READDIR);
+
+	*dt++ = 2;
+	dn[-1] = '\0';
+	free(namelist);
+}
+
+int create_flatten_tree(struct kexec_info *info, unsigned char **bufp,
+			unsigned long *sizep, char *cmdline)
+{
+	unsigned long len;
+	unsigned long tlen;
+	unsigned char *buf;
+	unsigned long me;
+
+	me = 0;
+
+	strcpy(pathname, "/proc/device-tree/");
+
+	pathstart = pathname + strlen(pathname);
+	dt = dtstruct;
+
+	if (cmdline)
+		strcpy(local_cmdline, cmdline);
+
+	putnode();
+	*dt++ = 9;
+
+	len = sizeof(bb[0]);
+	len += 7; len &= ~7;
+
+	bb->off_mem_rsvmap = len;
+
+	for (len = 1; mem_rsrv[len]; len += 2)
+		;
+	len+= 3;
+	len *= sizeof(mem_rsrv[0]);
+
+	bb->off_dt_struct = bb->off_mem_rsvmap + len;
+
+	len = dt - dtstruct;
+	len *= sizeof(dvt);
+	bb->off_dt_strings = bb->off_dt_struct + len;
+
+	len = propnum("");
+	len +=  3; len &= ~3;
+	bb->totalsize = bb->off_dt_strings + len;
+
+	bb->magic = 0xd00dfeed;
+	bb->version = 2;
+	bb->last_comp_version = 2;
+
+	reserve(me, bb->totalsize); /* patched later in kexec_load */
+
+	buf = (unsigned char *) malloc(bb->totalsize);
+	*bufp = buf;
+	memcpy(buf, bb, bb->off_mem_rsvmap);
+	tlen = bb->off_mem_rsvmap;
+	memcpy(buf+tlen, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap);
+	tlen = tlen + (bb->off_dt_struct - bb->off_mem_rsvmap);
+	memcpy(buf+tlen, dtstruct,  bb->off_dt_strings - bb->off_dt_struct);
+	tlen = tlen +  (bb->off_dt_strings - bb->off_dt_struct);
+	memcpy(buf+tlen, propnames,  bb->totalsize - bb->off_dt_strings);
+	tlen = tlen + bb->totalsize - bb->off_dt_strings;
+	*sizep = tlen;
+	return 0;
+}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/include/arch/options.h kexec-tools-1.101-kdump/kexec/arch/ppc64/include/arch/options.h
--- kexec-tools-1.101/kexec/arch/ppc64/include/arch/options.h	2004-12-22 01:56:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/include/arch/options.h	2006-01-19 18:20:07.000000000 +0530
@@ -2,9 +2,11 @@
 #define KEXEC_ARCH_PPC64_OPTIONS_H
 
 #define OPT_ARCH_MAX   (OPT_MAX+0)
+#define OPT_ELF64_CORE  (OPT_MAX+1)
 
 #define KEXEC_ARCH_OPTIONS \
 	KEXEC_OPTIONS \
+	{ "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \
 
 #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-ppc64.c kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-elf-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-ppc64.c	2004-12-17 15:02:04.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-elf-ppc64.c	2006-02-22 11:38:31.003108264 +0530
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 2004  Adam Litke (agl@us.ibm.com)
  * Copyright (C) 2004  IBM Corp.
+ * Copyright (C) 2005  R Sharada (sharada@in.ibm.com)
+ * Copyright (C) 2006  Mohan Kumar M (mohan@in.ibm.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
@@ -32,46 +34,19 @@
 #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
 
-#define UPSZ(X) ((sizeof(X) + 3) & ~3)
-static struct boot_notes {
-	Elf_Bhdr hdr;
-	Elf_Nhdr bl_hdr;
-	unsigned char bl_desc[UPSZ(BOOTLOADER)];
-	Elf_Nhdr blv_hdr;
-	unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
-	Elf_Nhdr cmd_hdr;
-	unsigned char command_line[0];
-} elf_boot_notes = {
-	.hdr = {
-		.b_signature = 0x0E1FB007,
-		.b_size = sizeof(elf_boot_notes),
-		.b_checksum = 0,
-		.b_records = 3,
-	},
-	.bl_hdr = {
-		.n_namesz = 0,
-		.n_descsz = sizeof(BOOTLOADER),
-		.n_type = EBN_BOOTLOADER_NAME,
-	},
-	.bl_desc = BOOTLOADER,
-	.blv_hdr = {
-		.n_namesz = 0,
-		.n_descsz = sizeof(BOOTLOADER_VERSION),
-		.n_type = EBN_BOOTLOADER_VERSION,
-	},
-	.blv_desc = BOOTLOADER_VERSION,
-	.cmd_hdr = {
-		.n_namesz = 0,
-		.n_descsz = 0,
-		.n_type = EBN_COMMAND_LINE,
-	},
-};
+unsigned long initrd_base, initrd_size;
+
+int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *,
+			char *);
+int my_r2(struct mem_ehdr *ehdr);
 
 int elf_ppc64_probe(const char *buf, off_t len)
 {
@@ -94,12 +69,94 @@ int elf_ppc64_probe(const char *buf, off
 	return result;
 }
 
-int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len, 
-	struct kexec_info *info)
+int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
+			struct kexec_info *info)
 {
 	struct mem_ehdr ehdr;
+	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;
+	unsigned long my_kernel, my_dt_offset;
+	unsigned int my_panic_kernel;
+	unsigned long my_stack, my_backup_start;
+	unsigned long toc_addr;
+
+#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 },
+		{ "initrd",             1, NULL, OPT_RAMDISK },
+		{ "devicetreeblob",     1, NULL, OPT_DEVICETREEBLOB },
+		{ 0,                    0, NULL, 0 },
+	};
+
+	static const char short_options[] = KEXEC_OPT_STR "";
 
 	/* Parse command line arguments */
+	initrd_base = 0;
+	initrd_size = 0;
+	cmdline = 0;
+	ramdisk = 0;
+	devicetreeblob = 0;
+	max_addr = 0xFFFFFFFFFFFFFFFFUL;
+	hole_addr = 0;
+
+	while ((opt = getopt_long(argc, argv, short_options,
+					options, 0)) != -1) {
+		switch (opt) {
+		default:
+			/* Ignore core options */
+			if (opt < OPT_ARCH_MAX)
+				break;
+		case '?':
+			usage();
+			return -1;
+		case OPT_APPEND:
+			cmdline = optarg;
+			break;
+		case OPT_RAMDISK:
+			ramdisk = optarg;
+			break;
+		case OPT_DEVICETREEBLOB:
+			devicetreeblob = optarg;
+			break;
+		}
+	}
+
+	cmdline_len = 0;
+	if (cmdline)
+		cmdline_len = strlen(cmdline) + 1;
+	else
+		fprintf(stdout, "Warning: append= option is not passed. Using the first kernel root partition\n");
+
+	setup_memory_ranges(info->kexec_flags);
+
+	/* 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);
@@ -108,13 +165,173 @@ int elf_ppc64_load(int argc, char **argv
 		return result;
 	}
 
-	/* Load the Elf data */
+	/* 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
+	 */
+
+	phdr = &ehdr.e_phdr[0];
+	size = phdr->p_filesz;
+	if (size > phdr->p_memsz)
+		size = phdr->p_memsz;
+
+	hole_addr = (unsigned long)locate_hole(info, size, 0, 0,
+			max_addr, 1);
+	ehdr.e_phdr[0].p_paddr = hole_addr;
 	result = elf_exec_load(&ehdr, info);
 	if (result < 0) {
 		free_elf_info(&ehdr);
 		return result;
 	}
-	return 1;
+
+	/* 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 */
+	seg_buf = NULL;
+	seg_size = 0;
+
+	seg_buf = (unsigned char *) malloc(purgatory_size);
+	if (seg_buf == NULL) {
+		free_elf_info(&ehdr);
+		return -1;
+	}
+	memcpy(seg_buf, purgatory, purgatory_size);
+	seg_size = purgatory_size;
+	elf_rel_build_load(info, &info->rhdr, (const char *)purgatory,
+				purgatory_size, 0, max_addr, 1);
+
+	/* Add a ram-disk to the current image
+	 * Note: Add the ramdisk after elf_rel_build_load
+	 */
+	if (ramdisk) {
+		if (devicetreeblob) {
+			fprintf(stderr,
+			"Can't use ramdisk with device tree blob input\n");
+			return -1;
+		}
+		seg_buf = (unsigned char *)slurp_file(ramdisk, &seg_size);
+		add_buffer(info, seg_buf, seg_size, seg_size, 0, 0, max_addr, 1);
+		hole_addr = (unsigned long long)
+			info->segment[info->nr_segments-1].mem;
+		initrd_base = hole_addr;
+		initrd_size = (unsigned long long)
+			info->segment[info->nr_segments-1].memsz;
+	} /* ramdisk */
+
+	if (devicetreeblob) {
+		unsigned char *blob_buf = NULL;
+		off_t blob_size = 0;
+
+		/* Grab device tree from buffer */
+		blob_buf =
+			(unsigned char *)slurp_file(devicetreeblob, &blob_size);
+		add_buffer(info, blob_buf, blob_size, blob_size, 0, 0,
+				max_addr, -1);
+
+	} else {
+		/* create from fs2dt */
+		seg_buf = NULL;
+		seg_size = 0;
+		create_flatten_tree(info, (unsigned char **)&seg_buf,
+				(unsigned long *)&seg_size,cmdline);
+		add_buffer(info, seg_buf, seg_size, seg_size,
+				0, 0, max_addr, -1);
+	}
+
+	/* patch reserve map address for flattened device-tree
+	 * find last entry (both 0) in the reserve mem list.  Assume DT
+	 * entry is before this one
+	 */
+	bb_ptr = (struct bootblock *)(
+		(unsigned char *)info->segment[(info->nr_segments)-1].buf);
+	rsvmap_ptr = (unsigned long long *)(
+		(unsigned char *)info->segment[(info->nr_segments)-1].buf +
+		bb_ptr->off_mem_rsvmap);
+	while (*rsvmap_ptr || *(rsvmap_ptr+1))
+		rsvmap_ptr += 2;
+	rsvmap_ptr -= 2;
+	*rsvmap_ptr = (unsigned long long)(
+		info->segment[(info->nr_segments)-1].mem);
+	rsvmap_ptr++;
+	*rsvmap_ptr = (unsigned long long)bb_ptr->totalsize;
+
+	nr_segments = info->nr_segments;
+
+	/* Set kernel */
+	my_kernel = (unsigned long )info->segment[0].mem;
+	elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel));
+
+	/* Set dt_offset */
+	my_dt_offset = (unsigned long )info->segment[nr_segments-1].mem;
+	elf_rel_set_symbol(&info->rhdr, "dt_offset", &my_dt_offset,
+				sizeof(my_dt_offset));
+
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		my_panic_kernel = 1;
+		/* Set panic flag */
+		elf_rel_set_symbol(&info->rhdr, "panic_kernel",
+				&my_panic_kernel, sizeof(my_panic_kernel));
+
+		/* Set backup address */
+		my_backup_start = info->backup_start;
+		elf_rel_set_symbol(&info->rhdr, "backup_start",
+				&my_backup_start, sizeof(my_backup_start));
+	}
+
+	/* Set stack address */
+	my_stack = locate_hole(info, 16*1024, 0, 0, max_addr, 1);
+	my_stack += 16*1024;
+	elf_rel_set_symbol(&info->rhdr, "stack", &my_stack, sizeof(my_stack));
+
+	/* Set toc */
+	toc_addr = (unsigned long) my_r2(&info->rhdr);
+	elf_rel_set_symbol(&info->rhdr, "my_toc", &toc_addr, sizeof(toc_addr));
+
+#ifdef DEBUG
+	my_kernel = 0;
+	my_dt_offset = 0;
+	my_panic_kernel = 0;
+	my_backup_start = 0;
+	my_stack = 0;
+	toc_addr = 0;
+
+	elf_rel_get_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel));
+	elf_rel_get_symbol(&info->rhdr, "dt_offset", &my_dt_offset,
+				sizeof(my_dt_offset));
+	elf_rel_get_symbol(&info->rhdr, "panic_kernel", &my_panic_kernel,
+				sizeof(my_panic_kernel));
+	elf_rel_get_symbol(&info->rhdr, "backup_start", &my_backup_start,
+				sizeof(my_backup_start));
+	elf_rel_get_symbol(&info->rhdr, "stack", &my_stack, sizeof(my_stack));
+	elf_rel_get_symbol(&info->rhdr, "my_toc", &toc_addr,
+				sizeof(toc_addr));
+
+	fprintf(stderr, "info->entry is %p\n", info->entry);
+	fprintf(stderr, "kernel is %Lx\n", my_kernel);
+	fprintf(stderr, "dt_offset is %Lx\n", my_dt_offset);
+	fprintf(stderr, "panic_kernel is %x\n", my_panic_kernel);
+	fprintf(stderr, "backup_start is %Lx\n", my_backup_start);
+	fprintf(stderr, "stack is %Lx\n", my_stack);
+	fprintf(stderr, "toc_addr is %Lx\n", toc_addr);
+	fprintf(stderr, "purgatory size is %d\n", purgatory_size);
+#endif
+
+	for (i = 0; i < nr_segments; i++)
+		fprintf(stderr, "segment[%d].mem:%p memsz:%ld\n", i,
+			info->segment[i].mem, info->segment[i].memsz);
+
+	return 0;
 }
 
 void elf_ppc64_usage(void)
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-rel-ppc64.c kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-elf-rel-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-rel-ppc64.c	2004-12-20 07:36:04.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-elf-rel-ppc64.c	2006-02-22 11:30:11.082107808 +0530
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <elf.h>
+#include <string.h>
 #include "../../kexec.h"
 #include "../../kexec-elf.h"
 
@@ -21,20 +22,20 @@ static struct mem_shdr *toc_section(cons
 {
 	struct mem_shdr *shdr, *shdr_end;
 	unsigned char *strtab;
-	strtab = ehdr->e_shdr[ehdr->e_shstrndx].sh_data;
-	shdr_end = &ehdr->e_shdr[ehdr->shnum];
-	for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
-		if (strcmp(shdr->sh_name, ".toc") == 0) {
+	strtab = (unsigned char *)ehdr->e_shdr[ehdr->e_shstrndx].sh_data;
+	shdr_end = &ehdr->e_shdr[ehdr->e_shnum];
+	for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++)
+		if ( shdr->sh_size &&
+			strcmp((char *)&strtab[shdr->sh_name],
+						".toc") == 0)
 			return shdr;
-		}
-	}
 	return NULL;
 }
 
 /* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
    gives the value maximum span in an instruction which uses a signed
    offset) */
-static unsigned long my_r2(const struct mem_ehdr *ehdr)
+unsigned long my_r2(const struct mem_ehdr *ehdr)
 {
 	struct mem_shdr *shdr;
 	shdr = toc_section(ehdr);
@@ -53,7 +54,7 @@ void machine_apply_elf_rel(struct mem_eh
 		/* Simply set it */
 		*(uint32_t *)location = value;
 		break;
-		
+
 	case R_PPC64_ADDR64:
 		/* Simply set it */
 		*(uint64_t *)location = value;
@@ -78,15 +79,34 @@ void machine_apply_elf_rel(struct mem_eh
 		/* Convert value to relative */
 		value -= address;
 		if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){
-			die("REL24 %li out of range!\n", 
+			die("REL24 %li out of range!\n",
 				(long int)value);
 		}
 
 		/* Only replace bits 2 through 26 */
-		*(uint32_t *)location 
-			= (*(uint32_t *)location & ~0x03fffffc)
-			| (value & 0x03fffffc);
+		*(uint32_t *)location = (*(uint32_t *)location & ~0x03fffffc)
+					| (value & 0x03fffffc);
+		break;
+
+	case R_PPC64_ADDR16_LO:
+		*(uint16_t *)location = value & 0xffff;
+		break;
+
+	case R_PPC64_ADDR16_HI:
+		*(uint16_t *)location = (value>>16) & 0xffff;
 		break;
+
+	case R_PPC64_ADDR16_HA:
+		*(uint16_t *)location = ((value>>16)  & 0xffff);
+		break;
+
+	case R_PPC64_ADDR16_HIGHEST:
+		*(uint16_t *)location = ((value>>48)  & 0xffff);
+		break;
+	case R_PPC64_ADDR16_HIGHER:
+		*(uint16_t *)location = ((value>>32)  & 0xffff);
+		break;
+
 	default:
 		die("Unknown rela relocation: %lu\n", r_type);
 		break;
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/kexec-ppc64.c kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-ppc64.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-ppc64.c	2006-01-19 18:20:07.000000000 +0530
@@ -0,0 +1,640 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
+ * Copyright (C) 2005  R Sharada (sharada@in.ibm.com), IBM Corporation
+ *
+ * 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 <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <getopt.h>
+#include <sys/utsname.h>
+#include "../../kexec.h"
+#include "../../kexec-syscall.h"
+#include "kexec-ppc64.h"
+#include "crashdump-ppc64.h"
+#include <arch/options.h>
+
+/* Platforms supported by kexec on PPC64 */
+#define PLATFORM_PSERIES	0x0100
+#define PLATFORM_PSERIES_LPAR	0x0101
+
+static struct exclude_range exclude_range[MAX_MEMORY_RANGES];
+static unsigned long long rmo_top;
+static unsigned int platform;
+static struct memory_range memory_range[MAX_MEMORY_RANGES];
+static struct memory_range base_memory_range[MAX_MEMORY_RANGES];
+unsigned long long memory_max = 0;
+static int nr_memory_ranges, nr_exclude_ranges;
+unsigned long long crash_base, crash_size;
+
+static int sort_base_ranges();
+
+/* Get base memory ranges */
+static int get_base_ranges()
+{
+	int local_memory_ranges = 0;
+	char device_tree[256] = "/proc/device-tree/";
+	char fname[256];
+	char buf[MAXBYTES-1];
+	DIR *dir, *dmem;
+	FILE *file;
+	struct dirent *dentry, *mentry;
+	int n;
+
+	if ((dir = opendir(device_tree)) == NULL) {
+		perror(device_tree);
+		return -1;
+	}
+	while ((dentry = readdir(dir)) != NULL) {
+		if (strncmp(dentry->d_name, "memory@", 7))
+			continue;
+		strcpy(fname, device_tree);
+		strcat(fname, dentry->d_name);
+		if ((dmem = opendir(fname)) == NULL) {
+			perror(fname);
+			closedir(dir);
+			return -1;
+		}
+		while ((mentry = readdir(dmem)) != NULL) {
+			if (strcmp(mentry->d_name, "reg"))
+				continue;
+			strcat(fname, "/reg");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(dmem);
+				closedir(dir);
+				return -1;
+			}
+			if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+				perror(fname);
+				fclose(file);
+				closedir(dmem);
+				closedir(dir);
+				return -1;
+			}
+			if (local_memory_ranges >= MAX_MEMORY_RANGES)
+				break;
+			base_memory_range[local_memory_ranges].start =
+				((unsigned long long *)buf)[0];
+			base_memory_range[local_memory_ranges].end  =
+				base_memory_range[local_memory_ranges].start +
+				((unsigned long long *)buf)[1];
+			base_memory_range[local_memory_ranges].type = RANGE_RAM;
+			local_memory_ranges++;
+#ifdef DEBUG
+			fprintf(stderr, "%016Lx-%016Lx : %x\n", memory_range[local_memory_ranges-1].start, memory_range[local_memory_ranges-1].end, memory_range[local_memory_ranges].type);
+#endif
+			fclose(file);
+		}
+		closedir(dmem);
+	}
+	closedir(dir);
+	nr_memory_ranges = local_memory_ranges;
+	sort_base_ranges();
+	memory_max = base_memory_range[nr_memory_ranges - 1].end;
+#ifdef DEBUG
+	fprintf(stderr, "get base memory ranges:%d\n", nr_memory_ranges);
+#endif
+	return 0;
+}
+
+/* Sort the base ranges in memory - this is useful for ensuring that our
+ * ranges are in ascending order, even if device-tree read of memory nodes
+ * is done differently. Also, could be used for other range coalescing later
+ */
+static int sort_base_ranges()
+{
+	int i, j;
+	unsigned long long tstart, tend;
+
+	for (i = 0; i < nr_memory_ranges - 1; i++) {
+		for (j = 0; j < nr_memory_ranges - i - 1; j++) {
+			if (base_memory_range[j].start > base_memory_range[j+1].start) {
+				tstart = base_memory_range[j].start;
+				tend = base_memory_range[j].end;
+				base_memory_range[j].start = base_memory_range[j+1].start;
+				base_memory_range[j].end = base_memory_range[j+1].end;
+				base_memory_range[j+1].start = tstart;
+				base_memory_range[j+1].end = tend;
+			}
+		}
+	}
+	return 0;
+}
+
+/* Sort the exclude ranges in memory */
+static int sort_ranges()
+{
+	int i, j;
+	unsigned long long tstart, tend;
+	for (i = 0; i < nr_exclude_ranges - 1; i++) {
+		for (j = 0; j < nr_exclude_ranges - i - 1; j++) {
+			if (exclude_range[j].start > exclude_range[j+1].start) {
+				tstart = exclude_range[j].start;
+				tend = exclude_range[j].end;
+				exclude_range[j].start = exclude_range[j+1].start;
+				exclude_range[j].end = exclude_range[j+1].end;
+				exclude_range[j+1].start = tstart;
+				exclude_range[j+1].end = tend;
+			}
+		}
+	}
+	return 0;
+}
+
+/* Get devtree details and create exclude_range array
+ * Also create usablemem_ranges for KEXEC_ON_CRASH
+ */
+static int get_devtree_details(unsigned long kexec_flags)
+{
+	unsigned long long rmo_base;
+	unsigned long long tce_base;
+	unsigned int tce_size;
+	unsigned int rtas_base, rtas_size;
+	unsigned long long htab_base, htab_size;
+	unsigned long long kernel_end;
+	char buf[MAXBYTES-1];
+	char device_tree[256] = "/proc/device-tree/";
+	char fname[256];
+	DIR *dir, *cdir;
+	FILE *file;
+	struct dirent *dentry;
+	int n, i = 0;
+
+	if ((dir = opendir(device_tree)) == NULL) {
+		perror(device_tree);
+		return -1;
+	}
+
+	while ((dentry = readdir(dir)) != NULL) {
+		if (strncmp(dentry->d_name, "chosen", 6) &&
+			strncmp(dentry->d_name, "memory@0", 8) &&
+			strncmp(dentry->d_name, "pci@", 4) &&
+			strncmp(dentry->d_name, "rtas", 4))
+			continue;
+		strcpy(fname, device_tree);
+		strcat(fname, dentry->d_name);
+		if ((cdir = opendir(fname)) == NULL) {
+			perror(fname);
+			closedir(dir);
+			return -1;
+		}
+
+		if (strncmp(dentry->d_name, "chosen", 6) == 0) {
+			/* get platform details from /chosen node */
+			strcat(fname, "/linux,platform");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if (fread(&platform, sizeof(int), 1, file) != 1) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			fclose(file);
+
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,kernel-end");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if (fread(&kernel_end, sizeof(unsigned long), 1, file) != 1) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			fclose(file);
+
+			/* Add kernel memory to exclude_range */
+			exclude_range[i].start = 0x0UL;
+			exclude_range[i].end = kernel_end;
+			i++;
+
+			if (kexec_flags & KEXEC_ON_CRASH) {
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,crashkernel-base");
+				if ((file = fopen(fname, "r")) == NULL) {
+					perror(fname);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+				if (fread(&crash_base, sizeof(unsigned long), 1,
+						file) != 1) {
+					perror(fname);
+					fclose(file);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+				fclose(file);
+
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,crashkernel-size");
+				if ((file = fopen(fname, "r")) == NULL) {
+					perror(fname);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+				if (fread(&crash_size, sizeof(unsigned long), 1,
+						file) != 1) {
+					perror(fname);
+					fclose(file);
+					closedir(cdir);
+					closedir(dir);
+					return -1;
+				}
+
+				if (crash_base > mem_min)
+					mem_min = crash_base;
+				if (crash_base + crash_size < mem_max)
+					mem_max = crash_base + crash_size;
+
+				add_usable_mem_rgns(0, crash_base + crash_size);
+				reserve(KDUMP_BACKUP_LIMIT, crash_base-KDUMP_BACKUP_LIMIT);
+			}
+
+			/* if LPAR, no need to read any more from /chosen */
+			if (platform != PLATFORM_PSERIES) {
+				closedir(cdir);
+				continue;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,htab-base");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if (fread(&htab_base, sizeof(unsigned long), 1, file) != 1) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,htab-size");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if (fread(&htab_size, sizeof(unsigned long), 1, file) != 1) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			/* Add htab address to exclude_range - NON-LPAR only */
+			exclude_range[i].start = htab_base;
+			exclude_range[i].end = htab_base + htab_size;
+			i++;
+		} /* chosen */
+
+		if (strncmp(dentry->d_name, "rtas", 4) == 0) {
+			strcat(fname, "/linux,rtas-base");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if (fread(&rtas_base, sizeof(unsigned int), 1, file) != 1) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/rtas-size");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if (fread(&rtas_size, sizeof(unsigned int), 1, file) != 1) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			closedir(cdir);
+			/* Add rtas to exclude_range */
+			exclude_range[i].start = rtas_base;
+			exclude_range[i].end = rtas_base + rtas_size;
+			i++;
+			if (kexec_flags & KEXEC_ON_CRASH)
+				add_usable_mem_rgns(rtas_base, rtas_size);
+		} /* rtas */
+
+		if (strncmp(dentry->d_name, "memory@0", 8) == 0) {
+			strcat(fname, "/reg");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if ((n = fread(buf, 1, MAXBYTES, file)) < 0) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			rmo_base = ((unsigned long long *)buf)[0];
+			rmo_top = rmo_base + ((unsigned long long *)buf)[1];
+			if (platform == PLATFORM_PSERIES) {
+				if (rmo_top > 0x30000000UL)
+					rmo_top = 0x30000000UL;
+			}
+			fclose(file);
+			closedir(cdir);
+		} /* memory */
+
+		if (strncmp(dentry->d_name, "pci@", 4) == 0) {
+			if (platform != PLATFORM_PSERIES) {
+				closedir(cdir);
+				continue;
+			}
+			strcat(fname, "/linux,tce-base");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if (fread(&tce_base, sizeof(unsigned long), 1, file) != 1) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,tce-size");
+			if ((file = fopen(fname, "r")) == NULL) {
+				perror(fname);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			if (fread(&tce_size, sizeof(unsigned int), 1, file) != 1) {
+				perror(fname);
+				fclose(file);
+				closedir(cdir);
+				closedir(dir);
+				return -1;
+			}
+			/* Add tce to exclude_range - NON-LPAR only */
+			exclude_range[i].start = tce_base;
+			exclude_range[i].end = tce_base + tce_size;
+			i++;
+			if (kexec_flags & KEXEC_ON_CRASH)
+				add_usable_mem_rgns(tce_base, tce_size);
+			closedir(cdir);
+		} /* pci */
+	}
+	closedir(dir);
+
+	nr_exclude_ranges = i;
+
+	sort_ranges();
+
+	/* add crash_region and remove rtas range from exclude regions if it
+	 * lies within crash region
+	 */
+	if (kexec_flags & KEXEC_ON_CRASH) {
+		unsigned long new_crash_size;
+		if (crash_base < rtas_base &&
+			((crash_base + crash_size) > (rtas_base + rtas_size))){
+			new_crash_size = rtas_base - crash_base;
+			add_exclude_rgns(crash_base, new_crash_size);
+			new_crash_size = (crash_base + crash_size) - (rtas_base + rtas_size);
+			add_exclude_rgns(rtas_base + rtas_size, new_crash_size);
+		} else if (crash_base < rtas_base &&
+			((rtas_base + rtas_size) > (crash_base + crash_size))){
+			new_crash_size = rtas_base - crash_base;
+			add_exclude_rgns(crash_base, new_crash_size);
+		} else if (crash_base > rtas_base &&
+			((rtas_base + rtas_size) < (crash_base + crash_size))){
+			new_crash_size = (crash_base + crash_size) - (rtas_base + rtas_size);
+			add_exclude_rgns(rtas_base + rtas_size, new_crash_size);
+		} else
+			add_exclude_rgns(crash_base, crash_size);
+	}
+
+#ifdef DEBUG
+	int k;
+	for (k = 0; k < i; k++)
+		fprintf(stderr, "exclude_range sorted exclude_range[%d] start:%lx, end:%lx\n", k, exclude_range[k].start, exclude_range[k].end);
+#endif
+	return 0;
+}
+
+/* Setup a sorted list of memory ranges. */
+int setup_memory_ranges(unsigned long kexec_flags)
+{
+	int i, j = 0;
+
+	/* Get the base list of memory ranges from /proc/device-tree/memory
+	 * nodes. Build list of ranges to be excluded from valid memory
+	 */
+
+	get_base_ranges();
+	get_devtree_details(kexec_flags);
+
+	for (i = 0; i < nr_exclude_ranges; i++) {
+		/* If first exclude range does not start with 0, include the
+		 * first hole of valid memory from 0 - exclude_range[0].start
+		 */
+		if (i == 0) {
+			if (exclude_range[i].start != 0) {
+				memory_range[j].start = 0;
+				memory_range[j].end = exclude_range[i].start - 1;
+				memory_range[j].type = RANGE_RAM;
+				j++;
+			}
+		} /* i == 0 */
+		/* If the last exclude range does not end at memory_max, include
+		 * the last hole of valid memory from exclude_range[last].end -
+		 * memory_max
+		 */
+		if (i == nr_exclude_ranges - 1) {
+			if (exclude_range[i].end < memory_max) {
+				memory_range[j].start = exclude_range[i].end + 1;
+				memory_range[j].end = memory_max;
+				memory_range[j].type = RANGE_RAM;
+				j++;
+				/* Limit the end to rmo_top */
+				if (memory_range[j-1].start >= rmo_top) {
+					j--;
+					break;
+				}
+				if ((memory_range[j-1].start < rmo_top) &&
+				(memory_range[j-1].end >= rmo_top)) {
+					memory_range[j-1].end = rmo_top;
+					break;
+				}
+				continue;
+			}
+		} /* i == nr_exclude_ranges - 1 */
+		/* contiguous exclude ranges - skip */
+		if (exclude_range[i+1].start == exclude_range[i].end + 1)
+			continue;
+		memory_range[j].start = exclude_range[i].end + 1;
+		memory_range[j].end = exclude_range[i+1].start - 1;
+		memory_range[j].type = RANGE_RAM;
+		j++;
+		/* Limit range to rmo_top */
+		if (memory_range[j-1].start >= rmo_top) {
+			j--;
+			break;
+		}
+		if ((memory_range[j-1].start < rmo_top) &&
+			(memory_range[j-1].end >= rmo_top)) {
+			memory_range[j-1].end = rmo_top;
+			break;
+		}
+	}
+	nr_memory_ranges = j;
+
+#ifdef DEBUG
+	int k;
+	for (k = 0; k < j; k++)
+		fprintf(stderr, "setup_memory_ranges memory_range[%d] start:%lx, end:%lx\n", k, memory_range[k].start, memory_range[k].end);
+#endif
+	return 0;
+}
+
+/* Return a list of valid memory ranges */
+int get_memory_ranges(struct memory_range **range, int *ranges,
+			unsigned long kexec_flags)
+{
+	setup_memory_ranges(kexec_flags);
+	*range = memory_range;
+	*ranges = nr_memory_ranges;
+	fprintf(stderr, "get memory ranges:%d\n", nr_memory_ranges);
+	return 0;
+}
+
+struct file_type file_type[] = {
+	{ "elf-ppc64", elf_ppc64_probe, elf_ppc64_load, elf_ppc64_usage },
+};
+int file_types = sizeof(file_type) / sizeof(file_type[0]);
+
+void arch_usage(void)
+{
+	fprintf(stderr, "     --devicetreeblob=<filename> Specify device tree blob file.\n");
+	fprintf(stderr, "     --elf64-core-headers Prepare core headers in ELF64 format\n");
+}
+
+struct arch_options_t arch_options = {
+	.core_header_type = CORE_TYPE_ELF64,
+};
+
+int arch_process_options(int argc, char **argv)
+{
+	static const struct option options[] = {
+		KEXEC_ARCH_OPTIONS
+		{ 0, 0, NULL, 0 },
+	};
+	static const char short_options[] = KEXEC_ARCH_OPT_STR;
+	int opt;
+
+	opterr = 0; /* Don't complain about unrecognized options here */
+	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
+		switch(opt) {
+		default:
+			break;
+		case OPT_ELF64_CORE:
+			arch_options.core_header_type = CORE_TYPE_ELF64;
+			break;
+		}
+	}
+	/* Reset getopt for the next pass; called in other source modules */
+	opterr = 1;
+	optind = 1;
+	return 0;
+}
+
+int arch_compat_trampoline(struct kexec_info *info)
+{
+	int result;
+	struct utsname utsname;
+	result = uname(&utsname);
+	if (result < 0) {
+		fprintf(stderr, "uname failed: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	if (strcmp(utsname.machine, "ppc64") == 0)
+	{
+		/* We are running a 32-bit kexec-tools on 64-bit ppc64.
+		 * So pass KEXEC_ARCH_PPC64 here
+		 */
+		info->kexec_flags |= KEXEC_ARCH_PPC64;
+	}
+	else {
+		fprintf(stderr, "Unsupported machine type: %s\n",
+			utsname.machine);
+		return -1;
+	}
+	return 0;
+}
+
+void arch_update_purgatory(struct kexec_info *info)
+{
+}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/kexec-ppc64.h kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-ppc64.h
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-ppc64.h	2004-12-17 12:14:42.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-ppc64.h	2006-01-19 18:20:07.000000000 +0530
@@ -1,9 +1,44 @@
 #ifndef KEXEC_PPC64_H
 #define KEXEC_PPC64_H
 
+#define MAX_MEMORY_RANGES 256 /* TO FIX - needs to be dynamically set */
+#define MAXBYTES 128
+#define MAX_LINE 160
+#define CORE_TYPE_ELF32 1
+#define CORE_TYPE_ELF64 2
+
+int setup_memory_ranges(unsigned long kexec_flags);
+
 int elf_ppc64_probe(const char *buf, off_t len);
 int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
 void elf_ppc64_usage(void);
+void reserve(unsigned long long where, unsigned long long length);
+
+extern unsigned long initrd_base, initrd_size;
+/* boot block version 2 as defined by the linux kernel */
+struct bootblock {
+	unsigned magic,
+		totalsize,
+		off_dt_struct,
+		off_dt_strings,
+		off_mem_rsvmap,
+		version,
+		last_comp_version,
+		boot_physid;
+};
+
+struct arch_options_t {
+	int core_header_type;
+};
+
+struct exclude_range {
+        unsigned long long start, end;
+};
+
+typedef struct mem_rgns {
+        unsigned int size;
+        struct exclude_range ranges[MAX_MEMORY_RANGES];
+} mem_rgns_t;
 
-#endif /* KEXEC_PPC_H */
+#endif /* KEXEC_PPC64_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/kexec-zImage-ppc64.c kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-zImage-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-zImage-ppc64.c	2004-12-16 17:47:51.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/kexec-zImage-ppc64.c	2006-02-22 11:30:11.082107808 +0530
@@ -153,7 +153,8 @@ int zImage_ppc64_load(FILE *file, int ar
 			return -1;
 		}
 		mem_offset = p->p_vaddr - load_loc;
-		if (fread(segment->buf+mem_offset, p->p_filesz, 1, file) != 1) {
+		if (fread((void *)segment->buf+mem_offset, p->p_filesz, 1,
+				file) != 1) {
 			perror("read error: ");
 			return -1;
 		}
@@ -161,7 +162,7 @@ int zImage_ppc64_load(FILE *file, int ar
 	segment->mem = (void *) load_loc;
 	segment->memsz = memsize;
 	segment->bufsz = filesize;
-	*ret_entry = elf.e_entry;
+	*ret_entry = (void *)((uint64_t)elf.e_entry);
 	*ret_nr_segments = i - 1;
 	free(ph);
 	return 0;
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/ppc64/Makefile kexec-tools-1.101-kdump/kexec/arch/ppc64/Makefile
--- kexec-tools-1.101/kexec/arch/ppc64/Makefile	2004-12-17 12:05:30.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/ppc64/Makefile	2006-01-19 18:20:06.000000000 +0530
@@ -2,6 +2,10 @@
 # kexec ppc64 (linux booting linux)
 #
 KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-elf-rel-ppc64.c
-KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-zImage-ppc64.c 
+KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-zImage-ppc64.c
+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 -urNp -X dontdiff kexec-tools-1.101/kexec/arch/s390/include/arch/options.h kexec-tools-1.101-kdump/kexec/arch/s390/include/arch/options.h
--- kexec-tools-1.101/kexec/arch/s390/include/arch/options.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/s390/include/arch/options.h	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,11 @@
+#ifndef KEXEC_ARCH_S390_OPTIONS_H
+#define KEXEC_ARCH_S390_OPTIONS_H
+
+#define OPT_ARCH_MAX   (OPT_MAX+0)
+
+#define KEXEC_ARCH_OPTIONS \
+	KEXEC_OPTIONS \
+
+#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
+
+#endif /* KEXEC_ARCH_S390_OPTIONS_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/s390/kexec-elf-rel-s390.c kexec-tools-1.101-kdump/kexec/arch/s390/kexec-elf-rel-s390.c
--- kexec-tools-1.101/kexec/arch/s390/kexec-elf-rel-s390.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/s390/kexec-elf-rel-s390.c	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,23 @@
+/*
+ * kexec/arch/s390/kexec-elf-rel-s390.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+#include <stdio.h>
+#include <elf.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+
+int machine_verify_elf_rel(struct mem_ehdr *ehdr)
+{
+	return 0;
+}
+
+void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
+	void *location, unsigned long address, unsigned long value)
+{
+}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/s390/kexec-image.c kexec-tools-1.101-kdump/kexec/arch/s390/kexec-image.c
--- kexec-tools-1.101/kexec/arch/s390/kexec-image.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/s390/kexec-image.c	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,137 @@
+/*
+ * kexec/arch/s390/kexec-image.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *            Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "../../kexec.h"
+#include "kexec-s390.h"
+
+#define OPT_APPEND     OPT_MAX+0
+#define OPT_RAMDISK    OPT_MAX+1
+
+int
+image_s390_load(int argc, char **argv, const char *kernel_buf,
+		off_t kernel_size, struct kexec_info *info)
+{
+	void *krnl_buffer;
+	char *rd_buffer;
+	const char *command_line;
+	const char *ramdisk;
+	int command_line_len;
+	off_t ramdisk_len;
+	unsigned int ramdisk_origin;
+	int opt;
+
+	static const struct option options[] =
+		{
+			KEXEC_OPTIONS
+			{"command-line",     1, 0, OPT_APPEND},
+			{"initrd",           1, 0, OPT_RAMDISK},
+			{0,                  0, 0, 0},
+		};
+	static const char short_options[] = KEXEC_OPT_STR "";
+
+	ramdisk = NULL;
+	command_line = NULL;
+	ramdisk_len = 0;
+	ramdisk_origin = 0;
+
+	while ((opt = getopt_long(argc,argv,short_options,options,0)) != -1) {
+		switch(opt) {
+		case '?':
+			usage();
+			return -1;
+			break;
+		case OPT_APPEND:
+			command_line = optarg;
+			break;
+		case OPT_RAMDISK:
+			ramdisk = optarg;
+			break;
+		}
+	}
+
+	/* Process a given command_line: */
+	if (command_line) {
+		command_line_len = strlen(command_line) + 1; /* Remember the '\0' */
+		if (command_line_len > COMMAND_LINESIZE) {
+		        fprintf(stderr, "Command line too long.\n");
+			return -1;
+		}
+	}
+
+	/* Add kernel segment */
+	add_segment(info, kernel_buf + IMAGE_READ_OFFSET,
+		    kernel_size - IMAGE_READ_OFFSET, IMAGE_READ_OFFSET,
+		    kernel_size - IMAGE_READ_OFFSET);
+
+	/* We do want to change the kernel image */
+	krnl_buffer = (void *) kernel_buf + IMAGE_READ_OFFSET;
+
+	/* Load ramdisk if present */
+	if (ramdisk) {
+		rd_buffer = slurp_file(ramdisk, &ramdisk_len);
+		if (rd_buffer == NULL) {
+			fprintf(stderr, "Could not read ramdisk.\n");
+			return -1;
+		}
+		ramdisk_origin = RAMDISK_ORIGIN_ADDR;
+		add_segment(info, rd_buffer, ramdisk_len, RAMDISK_ORIGIN_ADDR, ramdisk_len);
+	}
+
+	/* Register the ramdisk in the kernel. */
+	{
+		unsigned long long *tmp;
+
+		tmp = krnl_buffer + INITRD_START_OFFS;
+		*tmp = (unsigned long long) ramdisk_origin;
+
+		tmp = krnl_buffer + INITRD_SIZE_OFFS;
+		*tmp = (unsigned long long) ramdisk_len;
+	}
+
+	/*
+	 * We will write a probably given command line.
+	 * First, erase the old area, then setup the new parameters:
+	 */
+	if (command_line) {
+		memset(krnl_buffer + COMMAND_LINE_OFFS, 0, COMMAND_LINESIZE);
+		memcpy(krnl_buffer + COMMAND_LINE_OFFS, command_line, strlen(command_line));
+	}
+
+	info->entry = (void *) IMAGE_READ_OFFSET;
+
+	return 0;
+}
+
+int
+image_s390_probe(const char *kernel_buf, off_t kernel_size)
+{
+	/*
+	 * Can't reliably tell if an image is valid,
+	 * therefore everything is valid.
+	 */
+	return 0;
+}
+
+void
+image_s390_usage(void)
+{
+	printf("--command-line=STRING Pass a custom command line STRING to the kernel.\n"
+	       "--initrd=FILENAME     Use the file FILENAME as a ramdisk.\n"
+		);
+}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/s390/kexec-s390.c kexec-tools-1.101-kdump/kexec/arch/s390/kexec-s390.c
--- kexec-tools-1.101/kexec/arch/s390/kexec-s390.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/s390/kexec-s390.c	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,104 @@
+/*
+ * kexec/arch/s390/kexec-s390.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/utsname.h>
+#include "../../kexec.h"
+#include "../../kexec-syscall.h"
+#include "kexec-s390.h"
+#include <arch/options.h>
+
+#define MAX_MEMORY_RANGES 64
+static struct memory_range memory_range[MAX_MEMORY_RANGES];
+
+/*
+ * get_memory_ranges:
+ *  Return a list of memory ranges by parsing /proc/iomem
+ *
+ * INPUT:
+ *  - Pointer to an array of memory_range structures.
+ *  - Pointer to an integer with holds the number of memory ranges.
+ *
+ * RETURN:
+ *  - 0 on normal execution.
+ *  - (-1) if something went wrong.
+ */
+
+int get_memory_ranges(struct memory_range **range, int *ranges)
+{
+	char sys_ram[] = "System RAM\n";
+	char iomem[] = "/proc/iomem";
+	FILE *fp;
+	char line[80];
+	int current_range = 0;
+
+	fp = fopen(iomem,"r");
+	if(fp == 0) {
+		fprintf(stderr,"Unable to open %s: %s\n",iomem,strerror(errno));
+		return -1;
+	}
+
+	/* Setup the compare string properly. */
+	while(fgets(line,sizeof(line),fp) != 0) {
+		unsigned long long start, end;
+		int cons;
+		char *str;
+
+		if (current_range == MAX_MEMORY_RANGES)
+			break;
+
+		sscanf(line,"%Lx-%Lx : %n", &start, &end, &cons);
+		str = line+cons;
+		if(memcmp(str,sys_ram,strlen(sys_ram)) == 0) {
+			memory_range[current_range].start = start;
+			memory_range[current_range].end = end;
+			memory_range[current_range].type = RANGE_RAM;
+			current_range++;
+		}
+		else {
+			continue;
+		}
+	}
+	fclose(fp);
+	*range = memory_range;
+	*ranges = current_range;
+
+	return 0;
+}
+
+/* Supported file types and callbacks */
+struct file_type file_type[] = {
+	{ "image", image_s390_probe, image_s390_load, image_s390_usage},
+};
+int file_types = sizeof(file_type) / sizeof(file_type[0]);
+
+
+void arch_usage(void)
+{
+}
+
+int arch_process_options(int argc, char **argv)
+{
+	return 0;
+}
+
+int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
+{
+	return 0;
+}
+
+void arch_update_purgatory(struct kexec_info *info)
+{
+}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/s390/kexec-s390.h kexec-tools-1.101-kdump/kexec/arch/s390/kexec-s390.h
--- kexec-tools-1.101/kexec/arch/s390/kexec-s390.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/s390/kexec-s390.h	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,25 @@
+/*
+ * kexec/arch/s390/kexec-s390.h
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+#ifndef KEXEC_S390_H
+#define KEXEC_S390_H
+
+#define IMAGE_READ_OFFSET     0x10000
+
+#define RAMDISK_ORIGIN_ADDR   0x800000
+#define INITRD_START_OFFS     0x408
+#define INITRD_SIZE_OFFS      0x410
+#define COMMAND_LINE_OFFS     0x480
+#define COMMAND_LINESIZE      896
+
+extern int image_s390_load(int, char **, const char *, off_t, struct kexec_info *);
+extern int image_s390_probe(const char *, off_t);
+extern void image_s390_usage(void);
+
+#endif /* KEXEC_IA64_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/s390/Makefile kexec-tools-1.101-kdump/kexec/arch/s390/Makefile
--- kexec-tools-1.101/kexec/arch/s390/Makefile	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/s390/Makefile	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,6 @@
+#
+# kexec s390 (linux booting linux)
+#
+KEXEC_C_SRCS+= kexec/arch/s390/kexec-s390.c
+KEXEC_C_SRCS+= kexec/arch/s390/kexec-image.c
+KEXEC_C_SRCS+= kexec/arch/s390/kexec-elf-rel-s390.c
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/x86_64/crashdump-x86_64.c kexec-tools-1.101-kdump/kexec/arch/x86_64/crashdump-x86_64.c
--- kexec-tools-1.101/kexec/arch/x86_64/crashdump-x86_64.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/x86_64/crashdump-x86_64.c	2006-02-19 11:13:06.000000000 +0530
@@ -0,0 +1,655 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Murali M Chakravarthy (muralim@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ * Heavily borrowed from kexec/arch/i386/crashdump-x86.c
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "../../crashdump.h"
+#include "kexec-x86_64.h"
+#include "crashdump-x86_64.h"
+#include <x86/x86-linux.h>
+
+extern struct arch_options_t arch_options;
+
+/* Forward Declaration. */
+static int exclude_crash_reserve_region(int *nr_ranges);
+
+/* Stores a sorted list of RAM memory ranges for which to create elf headers.
+ * A separate program header is created for backup region */
+static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+
+/* Memory region reserved for storing panic kernel and other data. */
+static struct memory_range crash_reserved_mem;
+
+/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
+ * create Elf headers. Keeping it separate from get_memory_ranges() as
+ * requirements are different in the case of normal kexec and crashdumps.
+ *
+ * Normal kexec needs to look at all of available physical memory irrespective
+ * of the fact how much of it is being used by currently running kernel.
+ * Crashdumps need to have access to memory regions actually being used by
+ * running  kernel. Expecting a different file/data structure than /proc/iomem
+ * to look into down the line. May be something like /proc/kernelmem or may
+ * be zone data structures exported from kernel.
+ */
+static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+{
+	const char iomem[]= "/proc/iomem";
+	int memory_ranges = 0;
+	char line[MAX_LINE];
+	FILE *fp;
+	unsigned long long start, end;
+
+	fp = fopen(iomem, "r");
+	if (!fp) {
+		fprintf(stderr, "Cannot open %s: %s\n",
+			iomem, strerror(errno));
+		return -1;
+	}
+
+	/* First entry is for first 640K region. Different bios report first
+	 * 640K in different manner hence hardcoding it */
+	crash_memory_range[0].start = 0x00000000;
+	crash_memory_range[0].end = 0x0009ffff;
+	crash_memory_range[0].type = RANGE_RAM;
+	memory_ranges++;
+
+	while(fgets(line, sizeof(line), fp) != 0) {
+		char *str;
+		int type, consumed, count;
+		if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
+			break;
+		count = sscanf(line, "%Lx-%Lx : %n",
+			&start, &end, &consumed);
+		if (count != 2)
+			continue;
+		str = line + consumed;
+#if 0
+		printf("%016Lx-%016Lx : %s",
+			start, end, str);
+#endif
+		/* Only Dumping memory of type System RAM. */
+		if (memcmp(str, "System RAM\n", 11) == 0) {
+			type = RANGE_RAM;
+		} else if (memcmp(str, "Crash kernel\n", 13) == 0) {
+				/* Reserved memory region. New kernel can
+				 * use this region to boot into. */
+				crash_reserved_mem.start = start;
+				crash_reserved_mem.end = end;
+				crash_reserved_mem.type = RANGE_RAM;
+				continue;
+		} else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
+			/*
+			 * ACPI Tables area need to be passed to new
+			 * kernel with appropriate memmap= option. This
+			 * is needed so that x86_64 kernel creates linear
+			 * mapping for this region which is required for
+			 * initializing acpi tables in second kernel.
+			 */
+			type = RANGE_ACPI;
+		} else {
+			continue;
+		}
+
+		/* First 640K already registered */
+		if (start >= 0x00000000 && end <= 0x0009ffff)
+			continue;
+
+		crash_memory_range[memory_ranges].start = start;
+		crash_memory_range[memory_ranges].end = end;
+		crash_memory_range[memory_ranges].type = type;
+		memory_ranges++;
+
+		/* Segregate linearly mapped region. */
+		if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) {
+			crash_memory_range[memory_ranges-1].end = MAXMEM -1;
+
+			/* Add segregated region. */
+			crash_memory_range[memory_ranges].start = MAXMEM;
+			crash_memory_range[memory_ranges].end = end;
+			crash_memory_range[memory_ranges].type = type;
+			memory_ranges++;
+		}
+	}
+	fclose(fp);
+	if (exclude_crash_reserve_region(&memory_ranges) < 0)
+		return -1;
+	*range = crash_memory_range;
+	*ranges = memory_ranges;
+#if 0
+	int i;
+	printf("CRASH MEMORY RANGES\n");
+	for(i = 0; i < memory_ranges; i++) {
+		start = crash_memory_range[i].start;
+		end = crash_memory_range[i].end;
+		printf("%016Lx-%016Lx\n", start, end);
+	}
+#endif
+	return 0;
+}
+
+/* Removes crash reserve region from list of memory chunks for whom elf program
+ * headers have to be created. Assuming crash reserve region to be a single
+ * continuous area fully contained inside one of the memory chunks */
+static int exclude_crash_reserve_region(int *nr_ranges)
+{
+	int i, j, tidx = -1;
+	unsigned long long cstart, cend;
+	struct memory_range temp_region;
+
+	/* Crash reserved region. */
+	cstart = crash_reserved_mem.start;
+	cend = crash_reserved_mem.end;
+
+	for (i = 0; i < (*nr_ranges); i++) {
+		unsigned long long mstart, mend;
+		mstart = crash_memory_range[i].start;
+		mend = crash_memory_range[i].end;
+		if (cstart < mend && cend > mstart) {
+			if (cstart != mstart && cend != mend) {
+				/* Split memory region */
+				crash_memory_range[i].end = cstart - 1;
+				temp_region.start = cend + 1;
+				temp_region.end = mend;
+				temp_region.type = RANGE_RAM;
+				tidx = i+1;
+			} else if (cstart != mstart)
+				crash_memory_range[i].end = cstart - 1;
+			else
+				crash_memory_range[i].start = cend + 1;
+		}
+	}
+	/* Insert split memory region, if any. */
+	if (tidx >= 0) {
+		if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) {
+			/* No space to insert another element. */
+			fprintf(stderr, "Error: Number of crash memory ranges"
+					" excedeed the max limit\n");
+			return -1;
+		}
+		for (j = (*nr_ranges - 1); j >= tidx; j--)
+			crash_memory_range[j+1] = crash_memory_range[j];
+		crash_memory_range[tidx].start = temp_region.start;
+		crash_memory_range[tidx].end = temp_region.end;
+		crash_memory_range[tidx].type = temp_region.type;
+		(*nr_ranges)++;
+	}
+	return 0;
+}
+
+/* Adds a segment from list of memory regions which new kernel can use to
+ * boot. Segment start and end should be aligned to 1K boundary. */
+static int add_memmap(struct memory_range *memmap_p, unsigned long long addr,
+								size_t size)
+{
+	int i, j, nr_entries = 0, tidx = 0, align = 1024;
+	unsigned long long mstart, mend;
+
+	/* Do alignment check. */
+	if ((addr%align) || (size%align))
+		return -1;
+
+	/* Make sure at least one entry in list is free. */
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (!mstart  && !mend)
+			break;
+		else
+			nr_entries++;
+	}
+	if (nr_entries == CRASH_MAX_MEMMAP_NR)
+		return -1;
+
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (mstart == 0 && mend == 0)
+			break;
+		if (mstart <= (addr+size-1) && mend >=addr)
+			/* Overlapping region. */
+			return -1;
+		else if (addr > mend)
+			tidx = i+1;
+	}
+		/* Insert the memory region. */
+		for (j = nr_entries-1; j >= tidx; j--)
+			memmap_p[j+1] = memmap_p[j];
+		memmap_p[tidx].start = addr;
+		memmap_p[tidx].end = addr + size - 1;
+#if 0
+	printf("Memmap after adding segment\n");
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (mstart == 0 && mend == 0)
+			break;
+		printf("%016llx - %016llx\n",
+			mstart, mend);
+	}
+#endif
+	return 0;
+}
+
+/* Removes a segment from list of memory regions which new kernel can use to
+ * boot. Segment start and end should be aligned to 1K boundary. */
+static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr,
+								size_t size)
+{
+	int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024;
+	unsigned long long mstart, mend;
+	struct memory_range temp_region;
+
+	/* Do alignment check. */
+	if ((addr%align) || (size%align))
+		return -1;
+
+	/* Make sure at least one entry in list is free. */
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (!mstart  && !mend)
+			break;
+		else
+			nr_entries++;
+	}
+	if (nr_entries == CRASH_MAX_MEMMAP_NR)
+		/* List if full */
+		return -1;
+
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (mstart == 0 && mend == 0)
+			/* Did not find the segment in the list. */
+			return -1;
+		if (mstart <= addr && mend >= (addr + size - 1)) {
+			if (mstart == addr && mend == (addr + size - 1)) {
+				/* Exact match. Delete region */
+				operation = -1;
+				tidx = i;
+				break;
+			}
+			if (mstart != addr && mend != (addr + size - 1)) {
+				/* Split in two */
+				memmap_p[i].end = addr - 1;
+				temp_region.start = addr + size;
+				temp_region.end = mend;
+				operation = 1;
+				tidx = i;
+				break;
+			}
+
+			/* No addition/deletion required. Adjust the existing.*/
+			if (mstart != addr) {
+				memmap_p[i].end = addr - 1;
+				break;
+			} else {
+				memmap_p[i].start = addr + size;
+				break;
+			}
+		}
+	}
+	if ((operation == 1) && tidx >=0) {
+		/* Insert the split memory region. */
+		for (j = nr_entries-1; j > tidx; j--)
+			memmap_p[j+1] = memmap_p[j];
+		memmap_p[tidx+1] = temp_region;
+	}
+	if ((operation == -1) && tidx >=0) {
+		/* Delete the exact match memory region. */
+		for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++)
+			memmap_p[j-1] = memmap_p[j];
+		memmap_p[j-1].start = memmap_p[j-1].end = 0;
+	}
+#if 0
+	printf("Memmap after deleting segment\n");
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		mstart = memmap_p[i].start;
+		mend = memmap_p[i].end;
+		if (mstart == 0 && mend == 0) {
+			break;
+		}
+		printf("%016llx - %016llx\n",
+			mstart, mend);
+	}
+#endif
+	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;
+	}
+}
+
+/* Adds the appropriate memmap= options to command line, indicating the
+ * memory regions the new kernel can use to boot into. */
+static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p)
+{
+	int i, cmdlen, len, min_sizek = 100;
+	char str_mmap[256], str_tmp[20];
+
+	/* Exact map */
+	strcpy(str_mmap, " memmap=exactmap");
+	len = strlen(str_mmap);
+	cmdlen = strlen(cmdline) + len;
+	if (cmdlen > (COMMAND_LINE_SIZE - 1))
+		die("Command line overflow\n");
+	strcat(cmdline, str_mmap);
+
+	for (i = 0; i < CRASH_MAX_MEMMAP_NR;  i++) {
+		unsigned long startk, endk;
+		startk = (memmap_p[i].start/1024);
+		endk = ((memmap_p[i].end + 1)/1024);
+		if (!startk && !endk)
+			/* All regions traversed. */
+			break;
+
+		/* A region is not worth adding if region size < 100K. It eats
+		 * up precious command line length. */
+		if ((endk - startk) < min_sizek)
+			continue;
+		strcpy (str_mmap, " memmap=");
+		ultoa((endk-startk), str_tmp);
+		strcat (str_mmap, str_tmp);
+		strcat (str_mmap, "K@");
+		ultoa(startk, str_tmp);
+		strcat (str_mmap, str_tmp);
+		strcat (str_mmap, "K");
+		len = strlen(str_mmap);
+		cmdlen = strlen(cmdline) + len;
+		if (cmdlen > (COMMAND_LINE_SIZE - 1))
+			die("Command line overflow\n");
+		strcat(cmdline, str_mmap);
+	}
+#if 0
+		printf("Command line after adding memmap\n");
+		printf("%s\n", cmdline);
+#endif
+	return 0;
+}
+
+/* Adds the elfcorehdr= command line parameter to command line. */
+static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr)
+{
+	int cmdlen, len, align = 1024;
+	char str[30], *ptr;
+
+	/* Passing in elfcorehdr=xxxK format. Saves space required in cmdline.
+	 * Ensure 1K alignment*/
+	if (addr%align)
+		return -1;
+	addr = addr/align;
+	ptr = str;
+	strcpy(str, " elfcorehdr=");
+	ptr += strlen(str);
+	ultoa(addr, ptr);
+	strcat(str, "K");
+	len = strlen(str);
+	cmdlen = strlen(cmdline) + len;
+	if (cmdlen > (COMMAND_LINE_SIZE - 1))
+		die("Command line overflow\n");
+	strcat(cmdline, str);
+#if 0
+		printf("Command line after adding elfcorehdr\n");
+		printf("%s\n", cmdline);
+#endif
+	return 0;
+}
+
+/* Appends memmap=X#Y commandline for ACPI to command line*/
+static int cmdline_add_memmap_acpi(char *cmdline, unsigned long start,
+					unsigned long end)
+{
+	int cmdlen, len, align = 1024;
+	unsigned long startk, endk;
+	char str_mmap[256], str_tmp[20];
+
+	if (!(end - start))
+		return 0;
+
+	startk = start/1024;
+	endk = (end + align - 1)/1024;
+	strcpy (str_mmap, " memmap=");
+	ultoa((endk - startk), str_tmp);
+	strcat (str_mmap, str_tmp);
+	strcat (str_mmap, "K#");
+	ultoa(startk, str_tmp);
+	strcat (str_mmap, str_tmp);
+	strcat (str_mmap, "K");
+	len = strlen(str_mmap);
+	cmdlen = strlen(cmdline) + len;
+	if (cmdlen > (COMMAND_LINE_SIZE - 1))
+		die("Command line overflow\n");
+	strcat(cmdline, str_mmap);
+
+#if 0
+		printf("Command line after adding acpi memmap\n");
+		printf("%s\n", cmdline);
+#endif
+	return 0;
+}
+
+/* Prepares the crash memory elf64 headers and stores in supplied buffer. */
+static int prepare_crash_memory_elf64_headers(struct kexec_info *info,
+						void *buf, unsigned long size)
+{
+	Elf64_Ehdr *elf;
+	Elf64_Phdr *phdr;
+	int i;
+	char *bufp;
+	long int nr_cpus = 0;
+	uint64_t notes_addr;
+
+	bufp = (char*) buf;
+
+	/* Setup ELF Header*/
+	elf = (Elf64_Ehdr *) bufp;
+	bufp += sizeof(Elf64_Ehdr);
+	memcpy(elf->e_ident, ELFMAG, SELFMAG);
+	elf->e_ident[EI_CLASS]  = ELFCLASS64;
+	elf->e_ident[EI_DATA]   = ELFDATA2LSB;
+	elf->e_ident[EI_VERSION]= EV_CURRENT;
+	elf->e_ident[EI_OSABI] = ELFOSABI_NONE;
+	memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+	elf->e_type	= ET_CORE;
+	elf->e_machine	= EM_X86_64;
+	elf->e_version	= EV_CURRENT;
+	elf->e_entry	= 0;
+	elf->e_phoff	= sizeof(Elf64_Ehdr);
+	elf->e_shoff	= 0;
+	elf->e_flags	= 0;
+	elf->e_ehsize   = sizeof(Elf64_Ehdr);
+	elf->e_phentsize= sizeof(Elf64_Phdr);
+	elf->e_phnum    = 0;
+	elf->e_shentsize= 0;
+	elf->e_shnum    = 0;
+	elf->e_shstrndx = 0;
+
+	/* PT_NOTE program headers. One per cpu*/
+	nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (nr_cpus < 0) {
+		return -1;
+	}
+
+	/* Need to find a better way to determine per cpu notes section size. */
+#define MAX_NOTE_BYTES	1024
+	for (i = 0; i < nr_cpus; i++) {
+		if (get_crash_notes_per_cpu(i, &notes_addr) < 0) {
+			/* This cpu is not present. Skip it. */
+			continue;
+		}
+
+		phdr = (Elf64_Phdr *) bufp;
+		bufp += sizeof(Elf64_Phdr);
+		phdr->p_type	= PT_NOTE;
+		phdr->p_flags	= 0;
+		phdr->p_offset  = phdr->p_paddr = notes_addr;
+		phdr->p_vaddr   = 0;
+		phdr->p_filesz	= phdr->p_memsz	= MAX_NOTE_BYTES;
+		/* Do we need any alignment of segments? */
+		phdr->p_align	= 0;
+
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+
+	/* Setup PT_LOAD type program header for every system RAM chunk.
+	 * A seprate program header for Backup Region*/
+	for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+		unsigned long long mstart, mend;
+		if (crash_memory_range[i].type != RANGE_RAM)
+			continue;
+		mstart = crash_memory_range[i].start;
+		mend = crash_memory_range[i].end;
+		if (!mstart && !mend)
+			continue;
+		phdr = (Elf64_Phdr *) bufp;
+		bufp += sizeof(Elf64_Phdr);
+		phdr->p_type	= PT_LOAD;
+		phdr->p_flags	= PF_R|PF_W|PF_X;
+		if (mstart == BACKUP_START && mend == BACKUP_END)
+			phdr->p_offset	= info->backup_start;
+		else
+			phdr->p_offset	= mstart;
+
+		/* Handle linearly mapped region.*/
+
+		/* Filling the vaddr conditionally as we have two linearly
+		 * mapped regions here. One is __START_KERNEL_map 0 to 40 MB
+		 * other one is PAGE_OFFSET */
+
+		if ((mend <= (MAXMEM - 1)) && mstart < KERNEL_TEXT_SIZE)
+			phdr->p_vaddr = mstart + __START_KERNEL_map;
+		else {
+			if (mend <= (MAXMEM - 1))
+				phdr->p_vaddr = mstart + PAGE_OFFSET;
+			else
+				phdr->p_vaddr = -1ULL;
+		}
+		phdr->p_paddr = mstart;
+		phdr->p_filesz	= phdr->p_memsz	= mend - mstart + 1;
+		/* Do we need any alignment of segments? */
+		phdr->p_align	= 0;
+
+		/* Increment number of program headers. */
+		(elf->e_phnum)++;
+	}
+	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, i;
+	long int nr_cpus = 0;
+	struct memory_range *mem_range, *memmap_p;
+
+	if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
+		return -1;
+
+	/* Memory regions which panic kernel can safely use to boot into */
+	sz = (sizeof(struct memory_range) * (KEXEC_MAX_SEGMENTS + 1));
+	memmap_p = xmalloc(sz);
+	memset(memmap_p, 0, sz);
+	add_memmap(memmap_p, BACKUP_START, BACKUP_SIZE);
+	sz = crash_reserved_mem.end - crash_reserved_mem.start +1;
+	add_memmap(memmap_p, crash_reserved_mem.start, sz);
+
+	/* 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);
+	if (delete_memmap(memmap_p, info->backup_start, sz) < 0)
+		return -1;
+
+	/* 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;
+	}
+	sz = 	sizeof(Elf64_Ehdr) + nr_cpus * sizeof(Elf64_Phdr) +
+			nr_ranges * sizeof(Elf64_Phdr);
+	sz = (sz + align - 1) & ~(align -1);
+	tmp = xmalloc(sz);
+	memset(tmp, 0, sz);
+
+	/* Prepare ELF64 core heaers. */
+	if (prepare_crash_memory_elf64_headers(info, tmp, sz) < 0)
+		return -1;
+
+	/* Hack: With some ld versions (GNU ld version 2.14.90.0.4 20030523),
+	 * vmlinux program headers show a gap of two pages between bss segment
+	 * and data segment but effectively kernel considers it as bss segment
+	 * and overwrites the any data placed there. Hence bloat the memsz of
+	 * elf core header segment to 16K to avoid being placed in such gaps.
+	 * This is a makeshift solution until it is fixed in kernel.
+	 */
+	elfcorehdr = add_buffer(info, tmp, sz, 16*1024, align, min_base,
+							max_addr, 1);
+	if (delete_memmap(memmap_p, elfcorehdr, sz) < 0)
+		return -1;
+	cmdline_add_memmap(mod_cmdline, memmap_p);
+	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
+
+	/* Inform second kernel about the presence of ACPI tables. */
+	for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+		unsigned long start, end;
+		if (mem_range[i].type != RANGE_ACPI)
+			continue;
+		start = mem_range[i].start;
+		end = mem_range[i].end;
+		cmdline_add_memmap_acpi(mod_cmdline, start, end);
+	}
+	return 0;
+}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/x86_64/crashdump-x86_64.h kexec-tools-1.101-kdump/kexec/arch/x86_64/crashdump-x86_64.h
--- kexec-tools-1.101/kexec/arch/x86_64/crashdump-x86_64.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/x86_64/crashdump-x86_64.h	2006-01-19 11:41:40.000000000 +0530
@@ -0,0 +1,24 @@
+#ifndef CRASHDUMP_X86_64_H
+#define CRASHDUMP_X86_64_H
+
+int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
+				unsigned long max_addr, unsigned long min_base);
+
+#define __START_KERNEL_map      0xffffffff80000000UL
+#define PAGE_OFFSET		0xffff810000000000UL
+#define __pa(x)                 (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET)
+
+#define MAXMEM           0x3fffffffffffUL
+
+/* Kernel text size */
+#define KERNEL_TEXT_SIZE  (40UL*1024*1024)
+
+#define CRASH_MAX_MEMMAP_NR	(KEXEC_MAX_SEGMENTS + 1)
+#define CRASH_MAX_MEMORY_RANGES	(MAX_MEMORY_RANGES + 2)
+
+/* Backup Region, First 640K of System RAM. */
+#define BACKUP_START	0x00000000
+#define BACKUP_END	0x0009ffff
+#define BACKUP_SIZE	(BACKUP_END - BACKUP_START + 1)
+
+#endif /* CRASHDUMP_X86_64_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/x86_64/kexec-elf-x86_64.c kexec-tools-1.101-kdump/kexec/arch/x86_64/kexec-elf-x86_64.c
--- kexec-tools-1.101/kexec/arch/x86_64/kexec-elf-x86_64.c	2005-01-13 18:40:54.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/x86_64/kexec-elf-x86_64.c	2006-01-19 11:41:42.000000000 +0530
@@ -32,10 +32,12 @@
 #include <elf.h>
 #include <x86/x86-linux.h>
 #include "../../kexec.h"
+#include "../../kexec-syscall.h"
 #include "../../kexec-elf.h"
 #include "../../kexec-elf-boot.h"
 #include "../i386/x86-linux-setup.h"
 #include "kexec-x86_64.h"
+#include "crashdump-x86_64.h"
 #include <arch/options.h>
 
 static const int probe_debug = 0;
@@ -85,7 +87,9 @@ int elf_x86_64_load(int argc, char **arg
 {
 	struct mem_ehdr ehdr;
 	const char *command_line;
+	char *modified_cmdline;
 	int command_line_len;
+	int modified_cmdline_len;
 	const char *ramdisk;
 	unsigned long entry, max_addr;
 	int arg_style;
@@ -118,6 +122,8 @@ int elf_x86_64_load(int argc, char **arg
 	 */
 	arg_style = ARG_STYLE_ELF;
 	command_line = 0;
+	modified_cmdline = 0;
+	modified_cmdline_len = 0;
 	ramdisk = 0;
 	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 		switch(opt) {
@@ -156,6 +162,20 @@ int elf_x86_64_load(int argc, char **arg
 		command_line_len = strlen(command_line) +1;
 	}
 
+	/* 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 (command_line) {
+			strncpy(modified_cmdline, command_line,
+						COMMAND_LINE_SIZE);
+			modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+		}
+		modified_cmdline_len = strlen(modified_cmdline);
+	}
+
 	/* Load the ELF executable */
 	elf_exec_build_load(info, &ehdr, buf, len);
 
@@ -197,6 +217,7 @@ int elf_x86_64_load(int argc, char **arg
 		const unsigned char *ramdisk_buf;
 		off_t ramdisk_length;
 		struct entry64_regs regs;
+		int rc=0;
 
 		/* Get the linux parameter header */
 		hdr = xmalloc(sizeof(*hdr));
@@ -210,9 +231,19 @@ int elf_x86_64_load(int argc, char **arg
 		/* Add a ramdisk to the current image */
 		ramdisk_buf = 0;
 		ramdisk_length = 0;
-		if (ramdisk) {
-			unsigned char *ramdisk_buf;
+		if (ramdisk)
 			ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
+
+		/* If panic kernel is being loaded, additional segments need
+		 * to be created. */
+		if (info->kexec_flags & KEXEC_ON_CRASH) {
+			rc = load_crashdump_segments(info, modified_cmdline,
+							max_addr, 0);
+			if (rc < 0)
+				return -1;
+			/* Use new command line. */
+			command_line = modified_cmdline;
+			command_line_len = strlen(modified_cmdline) + 1;
 		}
 
 		/* Tell the kernel what is going on */
@@ -222,7 +253,7 @@ int elf_x86_64_load(int argc, char **arg
 			ramdisk_buf, ramdisk_length);
 
 		/* Fill in the information bios calls would usually provide */
-		setup_linux_system_parameters(&hdr->hdr);
+		setup_linux_system_parameters(&hdr->hdr, info->kexec_flags);
 
 		/* Initialize the registers */
 		elf_rel_get_symbol(&info->rhdr, "entry64_regs", &regs, sizeof(regs));
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/x86_64/kexec-x86_64.c kexec-tools-1.101-kdump/kexec/arch/x86_64/kexec-x86_64.c
--- kexec-tools-1.101/kexec/arch/x86_64/kexec-x86_64.c	2005-02-06 04:55:01.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/x86_64/kexec-x86_64.c	2006-02-19 11:11:37.000000000 +0530
@@ -30,14 +30,15 @@
 #include "../../kexec-elf.h"
 #include "../../kexec-syscall.h"
 #include "kexec-x86_64.h"
+#include "crashdump-x86_64.h"
 #include <arch/options.h>
 
 #define MAX_MEMORY_RANGES 64
-#define MAX_LINE 160
 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)
+int get_memory_ranges(struct memory_range **range, int *ranges,
+					unsigned long kexec_flags)
 {
 	const char iomem[]= "/proc/iomem";
 	int memory_ranges = 0;
@@ -79,6 +80,20 @@ int get_memory_ranges(struct memory_rang
 		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;
 		}
@@ -124,18 +139,20 @@ void arch_usage(void)
 		);
 }
 
-static struct {
+struct {
 	uint8_t  reset_vga;
 	uint16_t serial_base;
 	uint32_t serial_baud;
 	uint8_t  console_vga;
 	uint8_t  console_serial;
+	int core_header_type;
 } arch_options = {
 	.reset_vga   = 0,
 	.serial_base = 0x3f8,
 	.serial_baud = 0,
 	.console_vga = 0,
 	.console_serial = 0,
+	.core_header_type = CORE_TYPE_ELF64,
 };
 
 int arch_process_options(int argc, char **argv)
@@ -207,7 +224,7 @@ int arch_process_options(int argc, char 
 	return 0;
 }
 
-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
+int arch_compat_trampoline(struct kexec_info *info)
 {
 	int result;
 	struct utsname utsname;
@@ -222,7 +239,7 @@ int arch_compat_trampoline(struct kexec_
 		/* For compatibility with older patches 
 		 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_X86_64 here.
 		 */
-		*flags |= KEXEC_ARCH_DEFAULT;
+		info->kexec_flags |= KEXEC_ARCH_DEFAULT;
 	}
 	else {
 		fprintf(stderr, "Unsupported machine type: %s\n",
@@ -234,6 +251,8 @@ int arch_compat_trampoline(struct kexec_
 
 void arch_update_purgatory(struct kexec_info *info)
 {
+	uint8_t panic_kernel = 0;
+
 	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", 
@@ -244,4 +263,12 @@ void arch_update_purgatory(struct kexec_
 		&arch_options.console_vga, sizeof(arch_options.console_vga));
 	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;
+		elf_rel_set_symbol(&info->rhdr, "backup_start",
+					&info->backup_start, sizeof(info->backup_start));
+	}
+	elf_rel_set_symbol(&info->rhdr, "panic_kernel",
+				&panic_kernel, sizeof(panic_kernel));
 }
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/x86_64/Makefile kexec-tools-1.101-kdump/kexec/arch/x86_64/Makefile
--- kexec-tools-1.101/kexec/arch/x86_64/Makefile	2005-02-06 04:55:19.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/x86_64/Makefile	2006-01-19 11:41:40.000000000 +0530
@@ -7,6 +7,7 @@ KEXEC_C_SRCS+= kexec/arch/i386/kexec-mul
 KEXEC_C_SRCS+= kexec/arch/i386/kexec-beoboot-x86.c
 KEXEC_C_SRCS+= kexec/arch/i386/kexec-nbi.c
 KEXEC_C_SRCS+= kexec/arch/i386/x86-linux-setup.c
+KEXEC_C_SRCS+= kexec/arch/x86_64/crashdump-x86_64.c
 KEXEC_C_SRCS+= kexec/arch/x86_64/kexec-x86_64.c 
 KEXEC_C_SRCS+= kexec/arch/x86_64/kexec-elf-x86_64.c 
 KEXEC_C_SRCS+= kexec/arch/x86_64/kexec-elf-rel-x86_64.c
diff -urNp -X dontdiff kexec-tools-1.101/kexec/crashdump.c kexec-tools-1.101-kdump/kexec/crashdump.c
--- kexec-tools-1.101/kexec/crashdump.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/crashdump.c	2006-01-19 18:19:07.000000000 +0530
@@ -0,0 +1,65 @@
+/*
+ * crashdump.c: Architecture independent code for crashdump support.
+ *
+ * Created by: Vivek Goyal (vgoyal@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2005. 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "kexec.h"
+#include "crashdump.h"
+
+/* Returns the physical address of start of crash notes buffer for a cpu. */
+int get_crash_notes_per_cpu(int cpu, uint64_t *addr)
+{
+	char crash_notes[PATH_MAX];
+	char line[MAX_LINE];
+	FILE *fp;
+	struct stat cpu_stat;
+	int count;
+	unsigned long long temp;
+
+	sprintf(crash_notes, "/sys/devices/system/cpu/cpu%d/crash_notes", cpu);
+	fp = fopen(crash_notes, "r");
+	if (!fp) {
+		/* Either sysfs is not mounted or CPU is not present*/
+		if (stat("/sys/devices", &cpu_stat))
+			die("Sysfs is not mounted. Try mounting sysfs\n");
+
+		/* CPU is not physically present.*/
+		*addr = 0;
+		return errno;
+	}
+	if (fgets(line, sizeof(line), fp) != 0) {
+		count = sscanf(line, "%Lx", &temp);
+		if (count != 1)
+			die("Cannot parse %s: %s\n", crash_notes,
+						strerror(errno));
+		*addr = (uint64_t) temp;
+	}
+#if 0
+	printf("crash_notes addr = %Lx\n", *addr);
+#endif
+	return 0;
+}
diff -urNp -X dontdiff kexec-tools-1.101/kexec/crashdump.h kexec-tools-1.101-kdump/kexec/crashdump.h
--- kexec-tools-1.101/kexec/crashdump.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/crashdump.h	2006-01-19 18:19:07.000000000 +0530
@@ -0,0 +1,9 @@
+#ifndef CRASHDUMP_H
+#define CRASHDUMP_H
+
+extern int get_crash_notes_per_cpu(int cpu, uint64_t *addr);
+
+/* Need to find a better way to determine per cpu notes section size. */
+#define MAX_NOTE_BYTES		1024
+
+#endif /* CRASHDUMP_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/kexec.c kexec-tools-1.101-kdump/kexec/kexec.c
--- kexec-tools-1.101/kexec/kexec.c	2005-01-13 18:54:29.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/kexec.c	2006-02-01 14:41:52.000000000 +0530
@@ -38,8 +38,8 @@
 #include "kexec-elf.h"
 #include "kexec-sha256.h"
 
-static unsigned long long mem_min = 0;
-static unsigned long long mem_max = ULONG_MAX;
+unsigned long long mem_min = 0;
+unsigned long long mem_max = ULONG_MAX;
 
 void die(char *fmt, ...)
 {
@@ -187,7 +187,7 @@ unsigned long locate_hole(struct kexec_i
 	}
 
 	/* Compute the free memory ranges */
-	max_mem_ranges = memory_ranges + (info->nr_segments -1);
+	max_mem_ranges = memory_ranges + info->nr_segments;
 	mem_range = malloc(max_mem_ranges *sizeof(struct memory_range));
 	mem_ranges = 0;
 		
@@ -323,12 +323,17 @@ unsigned long add_buffer(struct kexec_in
 {
 	unsigned long base;
 	int result;
+	int pagesize;
 
 	result = sort_segments(info);
 	if (result < 0) {
 		die("sort_segments failed\n");
 	}
 
+	/* Round memsz up to a multiple of pagesize */
+	pagesize = getpagesize();
+	memsz = (memsz + (pagesize - 1)) & ~(pagesize - 1);
+
 	base = locate_hole(info, memsz, buf_align, buf_min, buf_max, buf_end);
 	if (base == ULONG_MAX) {
 		die("locate_hole failed\n");
@@ -507,6 +512,8 @@ static int my_load(const char *type, int
 	info.segment = NULL;
 	info.nr_segments = 0;
 	info.entry = NULL;
+	info.backup_start = 0;
+	info.kexec_flags = kexec_flags;
 
 	result = 0;
 	if (argc - fileind <= 0) {
@@ -522,7 +529,8 @@ static int my_load(const char *type, int
 		kernel_buf, kernel_size);
 #endif
 
-	if (get_memory_ranges(&memory_range, &memory_ranges) < 0) {
+	if (get_memory_ranges(&memory_range, &memory_ranges,
+		info.kexec_flags) < 0) {
 		fprintf(stderr, "Could not get memory layout\n");
 		return -1;
 	}
@@ -564,7 +572,7 @@ static int my_load(const char *type, int
 		return -1;
 	}
 	/* If we are not in native mode setup an appropriate trampoline */
-	if (arch_compat_trampoline(&info, &kexec_flags) < 0) {
+	if (arch_compat_trampoline(&info) < 0) {
 		return -1;
 	}
 	/* Verify all of the segments load to a valid location in memory */
@@ -585,17 +593,17 @@ static int my_load(const char *type, int
 	update_purgatory(&info);
 #if 0
 	fprintf(stderr, "kexec_load: entry = %p flags = %lx\n", 
-		info.entry, kexec_flags);
+		info.entry, info.kexec_flags);
 	print_segments(stderr, &info);
 #endif
 	result = kexec_load(
-		info.entry, info.nr_segments, info.segment, kexec_flags);
+		info.entry, info.nr_segments, info.segment, info.kexec_flags);
 	if (result != 0) {
 		/* The load failed, print some debugging information */
 		fprintf(stderr, "kexec_load failed: %s\n", 
 			strerror(errno));
 		fprintf(stderr, "entry       = %p flags = %lx\n", 
-			info.entry, kexec_flags);
+			info.entry, info.kexec_flags);
 		print_segments(stderr, &info);
 	}
 	return result;
diff -urNp -X dontdiff kexec-tools-1.101/kexec/kexec-elf.c kexec-tools-1.101-kdump/kexec/kexec-elf.c
--- kexec-tools-1.101/kexec/kexec-elf.c	2004-12-20 14:58:30.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/kexec-elf.c	2006-02-22 11:30:11.084107504 +0530
@@ -113,21 +113,21 @@ static int build_mem_elf32_ehdr(const ch
 		}
 		return -1;
 	}
-	if (elf32_to_cpu(ehdr, lehdr.e_entry) > ULONG_MAX) {
+	if (elf32_to_cpu(ehdr, lehdr.e_entry) > UINT32_MAX) {
 		/* entry is to large */
 		if (probe_debug) {
 			fprintf(stderr, "ELF e_entry to large\n");
 		}
 		return -1;
 	}
-	if (elf32_to_cpu(ehdr, lehdr.e_phoff) > ULONG_MAX) {
+	if (elf32_to_cpu(ehdr, lehdr.e_phoff) > UINT32_MAX) {
 		/* phoff is to large */
 		if (probe_debug) {
 			fprintf(stderr, "ELF e_phoff to large\n");
 		}
 		return -1;
 	}
-	if (elf32_to_cpu(ehdr, lehdr.e_shoff) > ULONG_MAX) {
+	if (elf32_to_cpu(ehdr, lehdr.e_shoff) > UINT32_MAX) {
 		/* shoff is to large */
 		if (probe_debug) {
 			fprintf(stderr, "ELF e_shoff to large\n");
@@ -146,7 +146,7 @@ static int build_mem_elf32_ehdr(const ch
 	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr.e_shstrndx);
 
 	if ((ehdr->e_phnum > 0) &&
-		(elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf32_Phdr))) 
+		(elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf32_Phdr)))
 	{
 		/* Invalid program header size */
 		if (probe_debug) {
@@ -185,21 +185,21 @@ static int build_mem_elf64_ehdr(const ch
 		}
 		return -1;
 	}
-	if (elf32_to_cpu(ehdr, lehdr.e_entry) > ULONG_MAX) {
+	if (elf32_to_cpu(ehdr, lehdr.e_entry) > UINT32_MAX) {
 		/* entry is to large */
 		if (probe_debug) {
 			fprintf(stderr, "ELF e_entry to large\n");
 		}
 		return -1;
 	}
-	if (elf32_to_cpu(ehdr, lehdr.e_phoff) > ULONG_MAX) {
+	if (elf32_to_cpu(ehdr, lehdr.e_phoff) > UINT32_MAX) {
 		/* phoff is to large */
 		if (probe_debug) {
 			fprintf(stderr, "ELF e_phoff to large\n");
 		}
 		return -1;
 	}
-	if (elf32_to_cpu(ehdr, lehdr.e_shoff) > ULONG_MAX) {
+	if (elf32_to_cpu(ehdr, lehdr.e_shoff) > UINT32_MAX) {
 		/* shoff is to large */
 		if (probe_debug) {
 			fprintf(stderr, "ELF e_shoff to large\n");
@@ -218,7 +218,7 @@ static int build_mem_elf64_ehdr(const ch
 	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr.e_shstrndx);
 
 	if ((ehdr->e_phnum > 0) &&
-		(elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf64_Phdr))) 
+		(elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf64_Phdr)))
 	{
 		/* Invalid program header size */
 		if (probe_debug) {
@@ -302,7 +302,7 @@ static int build_mem_ehdr(const char *bu
 	return 0;
 }
 
-static int build_mem_elf32_phdr(const char *buf, off_t len, 
+static int build_mem_elf32_phdr(const char *buf, off_t len,
 	struct mem_ehdr *ehdr, int idx)
 {
 	struct mem_phdr *phdr;
@@ -312,12 +312,12 @@ static int build_mem_elf32_phdr(const ch
 	phdr = &ehdr->e_phdr[idx];
 	memcpy(&lphdr, pbuf, sizeof(lphdr));
 
-	if (	(elf32_to_cpu(ehdr, lphdr.p_filesz) > ULONG_MAX) || 
-		(elf32_to_cpu(ehdr, lphdr.p_memsz)  > ULONG_MAX) ||
-		(elf32_to_cpu(ehdr, lphdr.p_offset) > ULONG_MAX) ||
-		(elf32_to_cpu(ehdr, lphdr.p_paddr)  > ULONG_MAX) ||
-		(elf32_to_cpu(ehdr, lphdr.p_vaddr)  > ULONG_MAX) ||
-		(elf32_to_cpu(ehdr, lphdr.p_align)  > ULONG_MAX))
+	if (	(elf32_to_cpu(ehdr, lphdr.p_filesz) > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_memsz)  > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_offset) > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_paddr)  > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_vaddr)  > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_align)  > UINT32_MAX))
 	{
 		fprintf(stderr, "Program segment size out of range\n");
 		return -1;
@@ -345,12 +345,12 @@ static int build_mem_elf64_phdr(const ch
 	phdr = &ehdr->e_phdr[idx];
 	memcpy(&lphdr, pbuf, sizeof(lphdr));
 
-	if (	(elf64_to_cpu(ehdr, lphdr.p_filesz) > ULONG_MAX) || 
-		(elf64_to_cpu(ehdr, lphdr.p_memsz)  > ULONG_MAX) ||
-		(elf64_to_cpu(ehdr, lphdr.p_offset) > ULONG_MAX) ||
-		(elf64_to_cpu(ehdr, lphdr.p_paddr)  > ULONG_MAX) ||
-		(elf64_to_cpu(ehdr, lphdr.p_vaddr)  > ULONG_MAX) ||
-		(elf64_to_cpu(ehdr, lphdr.p_align)  > ULONG_MAX))
+	if (	(elf64_to_cpu(ehdr, lphdr.p_filesz) > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lphdr.p_memsz)  > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lphdr.p_offset) > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lphdr.p_paddr)  > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lphdr.p_vaddr)  > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lphdr.p_align)  > UINT64_MAX))
 	{
 		fprintf(stderr, "Program segment size out of range\n");
 		return -1;
@@ -388,7 +388,7 @@ static int build_mem_phdrs(const char *b
 		fprintf(stderr, "Invalid ei_class?\n");
 		return -1;
 	}
-	phdr_size *= ehdr->e_phnum; 
+	phdr_size *= ehdr->e_phnum;
 	if (ehdr->e_phoff + phdr_size > len) {
 		/* The program header did not fit in the file buffer */
 		if (probe_debug) {
@@ -396,7 +396,7 @@ static int build_mem_phdrs(const char *b
 		}
 		return -1;
 	}
-	
+
 	/* Allocate the e_phdr array */
 	mem_phdr_size = sizeof(ehdr->e_phdr[0]) * ehdr->e_phnum;
 	ehdr->e_phdr = xmalloc(mem_phdr_size);
@@ -440,7 +440,7 @@ static int build_mem_phdrs(const char *b
 	return 0;
 }
 
-static int build_mem_elf32_shdr(const char *buf, off_t len, 
+static int build_mem_elf32_shdr(const char *buf, off_t len,
 	struct mem_ehdr *ehdr, int idx)
 {
 	struct mem_shdr *shdr;
@@ -451,12 +451,12 @@ static int build_mem_elf32_shdr(const ch
 	shdr = &ehdr->e_shdr[idx];
 	memcpy(&lshdr, sbuf, sizeof(lshdr));
 
-	if (	(elf32_to_cpu(ehdr, lshdr.sh_flags)     > ULONG_MAX) || 
-		(elf32_to_cpu(ehdr, lshdr.sh_addr)      > ULONG_MAX) ||
-		(elf32_to_cpu(ehdr, lshdr.sh_offset)    > ULONG_MAX) ||
-		(elf32_to_cpu(ehdr, lshdr.sh_size)      > ULONG_MAX) ||
-		(elf32_to_cpu(ehdr, lshdr.sh_addralign) > ULONG_MAX) ||
-		(elf32_to_cpu(ehdr, lshdr.sh_entsize)   > ULONG_MAX))
+	if (	(elf32_to_cpu(ehdr, lshdr.sh_flags)     > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_addr)      > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_offset)    > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_size)      > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_addralign) > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_entsize)   > UINT32_MAX))
 	{
 		fprintf(stderr, "Program section size out of range\n");
 		return -1;
@@ -510,7 +510,7 @@ static int build_mem_elf32_shdr(const ch
 	return 0;
 }
 
-static int build_mem_elf64_shdr(const char *buf, off_t len, 
+static int build_mem_elf64_shdr(const char *buf, off_t len,
 	struct mem_ehdr *ehdr, int idx)
 {
 	struct mem_shdr *shdr;
@@ -521,12 +521,12 @@ static int build_mem_elf64_shdr(const ch
 	shdr = &ehdr->e_shdr[idx];
 	memcpy(&lshdr, sbuf, sizeof(lshdr));
 
-	if (	(elf64_to_cpu(ehdr, lshdr.sh_flags)     > ULONG_MAX) || 
-		(elf64_to_cpu(ehdr, lshdr.sh_addr)      > ULONG_MAX) ||
-		(elf64_to_cpu(ehdr, lshdr.sh_offset)    > ULONG_MAX) ||
-		(elf64_to_cpu(ehdr, lshdr.sh_size)      > ULONG_MAX) ||
-		(elf64_to_cpu(ehdr, lshdr.sh_addralign) > ULONG_MAX) ||
-		(elf64_to_cpu(ehdr, lshdr.sh_entsize)   > ULONG_MAX))
+	if (	(elf64_to_cpu(ehdr, lshdr.sh_flags)     > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lshdr.sh_addr)      > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lshdr.sh_offset)    > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lshdr.sh_size)      > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lshdr.sh_addralign) > UINT64_MAX) ||
+		(elf64_to_cpu(ehdr, lshdr.sh_entsize)   > UINT64_MAX))
 	{
 		fprintf(stderr, "Program section size out of range\n");
 		return -1;
@@ -608,7 +608,7 @@ static int build_mem_shdrs(const char *b
 		}
 		return -1;
 	}
-	
+
 	/* Allocate the e_shdr array */
 	mem_shdr_size = sizeof(ehdr->e_shdr[0]) * ehdr->e_shnum;
 	ehdr->e_shdr = xmalloc(mem_shdr_size);
@@ -635,7 +635,7 @@ static int build_mem_shdrs(const char *b
 		{
 			/* The section does not fit in the buffer */
 			if (probe_debug) {
-				fprintf(stderr, "ELF section %d not in file\n", 
+				fprintf(stderr, "ELF section %d not in file\n",
 					i);
 			}
 			return -1;
@@ -648,19 +648,19 @@ static int build_mem_shdrs(const char *b
 			return -1;
 		}
 		/* Remember where the section lives in the buffer */
-		shdr->sh_data = buf + shdr->sh_offset;
+		shdr->sh_data = (unsigned char *)(buf + shdr->sh_offset);
 	}
 	return 0;
 }
 
-static void read_nhdr(const struct mem_ehdr *ehdr, 
+static void read_nhdr(const struct mem_ehdr *ehdr,
 	ElfNN_Nhdr *hdr, const unsigned char *note)
 {
 	memcpy(hdr, note, sizeof(*hdr));
 	hdr->n_namesz = elf32_to_cpu(ehdr, hdr->n_namesz);
 	hdr->n_descsz = elf32_to_cpu(ehdr, hdr->n_descsz);
 	hdr->n_type   = elf32_to_cpu(ehdr, hdr->n_type);
-		
+
 }
 static int build_mem_notes(const char *buf, off_t len, struct mem_ehdr *ehdr)
 {
@@ -672,7 +672,7 @@ static int build_mem_notes(const char *b
 	for(i = 0; !note_start && (i < ehdr->e_phnum); i++) {
 		struct mem_phdr *phdr = &ehdr->e_phdr[i];
 		if (phdr->p_type == PT_NOTE) {
-			note_start = phdr->p_data;
+			note_start = (unsigned char *)phdr->p_data;
 			note_end = note_start + phdr->p_filesz;
 		}
 	}
@@ -686,7 +686,7 @@ static int build_mem_notes(const char *b
 	if (!note_start) {
 		return 0;
 	}
-	
+
 	/* Walk through and count the notes */
 	ehdr->e_notenum = 0;
 	for(note = note_start; note < note_end; note+= note_size) {
@@ -708,15 +708,15 @@ static int build_mem_notes(const char *b
 		note_size += (hdr.n_namesz + 3) & ~3;
 		desc       = note + note_size;
 		note_size += (hdr.n_descsz + 3) & ~3;
-		
+
 		if ((hdr.n_namesz != 0) && (name[hdr.n_namesz -1] != '\0')) {
 			die("Note name is not null termiated");
 		}
 		ehdr->e_note[i].n_type = hdr.n_type;
-		ehdr->e_note[i].n_name = name;
+		ehdr->e_note[i].n_name = (char *)name;
 		ehdr->e_note[i].n_desc = desc;
 		ehdr->e_note[i].n_descsz = hdr.n_descsz;
-		
+
 	}
 	return 0;
 }
diff -urNp -X dontdiff kexec-tools-1.101/kexec/kexec-elf-rel.c kexec-tools-1.101-kdump/kexec/kexec-elf-rel.c
--- kexec-tools-1.101/kexec/kexec-elf-rel.c	2005-01-13 18:34:21.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/kexec-elf-rel.c	2006-02-22 11:30:11.085107352 +0530
@@ -155,7 +155,7 @@ int build_elf_rel_info(const char *buf, 
 		if (probe_debug) {
 			fprintf(stderr, "No ELF section headers\n");
 		}
-		return -1; 
+		return -1;
 	}
 	if (!machine_verify_elf_rel(ehdr)) {
 		/* It does not meant the native architecture constraints */
@@ -251,7 +251,7 @@ int elf_rel_load(struct mem_ehdr *ehdr, 
 
 	/* Allocate where we will put the relocated object */
 	buf = xmalloc(bufsz);
-	buf_addr = add_buffer(info, buf, bufsz, bufsz + bss_pad + bsssz, 
+	buf_addr = add_buffer(info, buf, bufsz, bufsz + bss_pad + bsssz,
 		buf_align, min, max, end);
 	ehdr->rel_addr = buf_addr;
 	ehdr->rel_size = bufsz + bss_pad + bsssz;
@@ -269,7 +269,7 @@ int elf_rel_load(struct mem_ehdr *ehdr, 
 			unsigned long off;
 			/* Adjust the address */
 			data_addr = (data_addr + (align - 1)) & ~(align -1);
-			
+
 			/* Update the section */
 			off = data_addr - buf_addr;
 			memcpy(buf + off, shdr->sh_data, shdr->sh_size);
@@ -306,7 +306,7 @@ int elf_rel_load(struct mem_ehdr *ehdr, 
 			continue;
 		}
 		if ((shdr->sh_info > ehdr->e_shnum) ||
-			(shdr->sh_link > ehdr->e_shnum)) 
+			(shdr->sh_link > ehdr->e_shnum))
 		{
 			die("Invalid section number\n");
 		}
@@ -350,12 +350,12 @@ int elf_rel_load(struct mem_ehdr *ehdr, 
 
 			/* The final address of that location */
 			address = section->sh_addr + rel.r_offset;
-			
+
 			/* The relevant symbol */
 			sym = elf_sym(ehdr, symtab->sh_data + (rel.r_sym * elf_sym_size(ehdr)));
-#if 0
+#ifdef DEBUG
 			fprintf(stderr, "sym: %10s info: %02x other: %02x shndx: %lx value: %lx size: %lx\n",
-				strtab + sym.st_name, 
+				strtab + sym.st_name,
 				sym.st_info,
 				sym.st_other,
 				sym.st_shndx,
@@ -364,8 +364,19 @@ int elf_rel_load(struct mem_ehdr *ehdr, 
 
 #endif
 			if (sym.st_shndx == STN_UNDEF) {
-				die("Undefined symbol: %s\n", 
+			/*
+			 * NOTE: ppc64 elf .ro shows up a  UNDEF section.
+			 * From Elf 1.2 Spec:
+			 * Relocation Entries: If the index is STN_UNDEF,
+			 * the undefined symbol index, the relocation uses 0
+			 * as the "symbol value".
+			 * So, is this really an error condition to flag die?
+			 */
+			/*
+				die("Undefined symbol: %s\n",
 					strtab + sym.st_name);
+			*/
+				continue;
 			}
 			sec_base = 0;
 			if (sym.st_shndx == SHN_COMMON) {
@@ -383,14 +394,14 @@ int elf_rel_load(struct mem_ehdr *ehdr, 
 			else {
 				sec_base = ehdr->e_shdr[sym.st_shndx].sh_addr;
 			}
-#if 0
+#ifdef DEBUG
 			fprintf(stderr, "sym: %s value: %lx addr: %lx\n",
 				strtab + sym.st_name, value, address);
 #endif
 			value = sym.st_value;
 			value += sec_base;
 			value += rel.r_addend;
-			machine_apply_elf_rel(ehdr, rel.r_type, 
+			machine_apply_elf_rel(ehdr, rel.r_type,
 				(void *)location, address, value);
 		}
 	}
@@ -399,14 +410,14 @@ int elf_rel_load(struct mem_ehdr *ehdr, 
 	return result;
 }
 
-void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr, 
+void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr,
 	const char *buf, off_t len, unsigned long min, unsigned long max,
 	int end)
 {
 	int result;
 
 	/* Parse the Elf file */
-	result = build_elf_rel_info(purgatory, purgatory_size, ehdr);
+	result = build_elf_rel_info((char *)purgatory, purgatory_size, ehdr);
 	if (result < 0) {
 		die("ELF rel parse failed\n");
 	}
@@ -439,7 +450,7 @@ int elf_rel_find_symbol(struct mem_ehdr 
 			/* Invalid strtab section number? */
 			continue;
 		}
-		strtab = ehdr->e_shdr[shdr->sh_link].sh_data;
+		strtab = (char *)ehdr->e_shdr[shdr->sh_link].sh_data;
 		/* Walk through the symbol table and find the symbol */
 		sym_size = elf_sym_size(ehdr);
 		sym_end = shdr->sh_data + shdr->sh_size;
@@ -452,8 +463,8 @@ int elf_rel_find_symbol(struct mem_ehdr 
 			if (strcmp(strtab + sym.st_name, name) != 0) {
 				continue;
 			}
-			if ((sym.st_shndx == STN_UNDEF) || 
-				(sym.st_shndx > ehdr->e_shnum)) 
+			if ((sym.st_shndx == STN_UNDEF) ||
+				(sym.st_shndx > ehdr->e_shnum))
 			{
 				die("Symbol: %s has Bad section index %d\n",
 					name, sym.st_shndx);
@@ -491,7 +502,7 @@ void elf_rel_set_symbol(struct mem_ehdr 
 
 	result = elf_rel_find_symbol(ehdr, name, &sym);
 	if (result < 0) {
-		die("Symbol: %s not found cannot set\n", 
+		die("Symbol: %s not found cannot set\n",
 			name);
 	}
 	if (sym.st_size != size) {
diff -urNp -X dontdiff kexec-tools-1.101/kexec/kexec.h kexec-tools-1.101-kdump/kexec/kexec.h
--- kexec-tools-1.101/kexec/kexec.h	2005-01-13 18:33:00.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/kexec.h	2006-01-19 18:19:07.000000000 +0530
@@ -91,6 +91,8 @@ do { \
 } while(0)
 #endif
 
+extern unsigned long long mem_min, mem_max;
+
 struct kexec_segment {
 	const void *buf;
 	size_t bufsz;
@@ -112,10 +114,13 @@ struct kexec_info {
 	int nr_segments;
 	void *entry;
 	struct mem_ehdr rhdr;
+	unsigned long backup_start;
+	unsigned long kexec_flags;
 };
 
 void usage(void);
-int get_memory_ranges(struct memory_range **range, int *ranges);
+int get_memory_ranges(struct memory_range **range, int *ranges,
+						unsigned long kexec_flags);
 int valid_memory_range(unsigned long sstart, unsigned long send);
 int valid_memory_segment(struct kexec_segment *segment);
 void print_segments(FILE *file, struct kexec_info *info);
@@ -188,7 +193,8 @@ extern size_t purgatory_size;
 
 void arch_usage(void);
 int arch_process_options(int argc, char **argv);
-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags);
+int arch_compat_trampoline(struct kexec_info *info);
 void arch_update_purgatory(struct kexec_info *info);
 
+#define MAX_LINE	160
 #endif /* KEXEC_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/kexec-syscall.h kexec-tools-1.101-kdump/kexec/kexec-syscall.h
--- kexec-tools-1.101/kexec/kexec-syscall.h	2005-01-06 12:29:50.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/kexec-syscall.h	2006-01-19 11:41:43.000000000 +0530
@@ -37,6 +37,12 @@
 #ifdef __x86_64__
 #define __NR_kexec_load		246
 #endif
+#ifdef __s390x__
+#define __NR_kexec_load		277
+#endif
+#ifdef __s390__
+#define __NR_kexec_load		277
+#endif
 #ifndef __NR_kexec_load
 #error Unknown processor architecture.  Needs a kexec_load syscall number.
 #endif
@@ -67,7 +73,8 @@ static inline long kexec_reboot(void)
 #define KEXEC_ARCH_PPC     (20 << 16)
 #define KEXEC_ARCH_PPC64   (21 << 16)
 #define KEXEC_ARCH_IA_64   (50 << 16)
+#define KEXEC_ARCH_S390    (22 << 16)
 
-#define KEXEC_MAX_SEGMENTS 8
+#define KEXEC_MAX_SEGMENTS 16
 
 #endif /* KEXEC_SYSCALL_H */
diff -urNp -X dontdiff kexec-tools-1.101/kexec/Makefile kexec-tools-1.101-kdump/kexec/Makefile
--- kexec-tools-1.101/kexec/Makefile	2004-12-22 01:06:39.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/Makefile	2006-01-19 18:19:07.000000000 +0530
@@ -15,6 +15,7 @@ KEXEC_C_SRCS+= kexec/kexec-elf.c 
 KEXEC_C_SRCS+= kexec/kexec-elf-exec.c 
 KEXEC_C_SRCS+= kexec/kexec-elf-rel.c 
 KEXEC_C_SRCS+= kexec/kexec-elf-boot.c 
+KEXEC_C_SRCS+= kexec/crashdump.c
 KEXEC_C_SRCS+= $(PURGATORY_HEX_C)
 KEXEC_S_SRCS:= 
 include kexec/arch/$(ARCH)/Makefile
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/i386/crashdump_backup.c kexec-tools-1.101-kdump/purgatory/arch/i386/crashdump_backup.c
--- kexec-tools-1.101/purgatory/arch/i386/crashdump_backup.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/i386/crashdump_backup.c	2006-01-19 11:41:41.000000000 +0530
@@ -0,0 +1,46 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by:  Vivek goyal (vgoyal@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2005. 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.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#define BACKUP_REGION_SOURCE 0x00000000
+#define BACKUP_REGION_SIZE 0xa0000
+
+/* Backup region start gets set after /proc/iomem has been parsed. */
+/* We reuse the same code for x86_64 also so changing backup_start to
+   unsigned long */
+unsigned long  backup_start = 0;
+
+/* Backup first 640K of memory to backup region as reserved by kexec.
+ * Assuming first 640K has to be present on i386 machines and no address
+ * validity checks have to be performed. */
+
+void crashdump_backup_memory(void)
+{
+	void *dest, *src;
+
+	src = (void *) BACKUP_REGION_SOURCE;
+
+	if (backup_start) {
+		dest = (void *)(backup_start);
+		memcpy(dest, src, BACKUP_REGION_SIZE);
+	}
+}
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/i386/Makefile kexec-tools-1.101-kdump/purgatory/arch/i386/Makefile
--- kexec-tools-1.101/purgatory/arch/i386/Makefile	2005-01-11 06:37:58.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/i386/Makefile	2006-01-19 11:41:27.000000000 +0530
@@ -12,3 +12,4 @@ PURGATORY_C_SRCS+= purgatory/arch/i386/p
 PURGATORY_C_SRCS+= purgatory/arch/i386/console-x86.c
 PURGATORY_C_SRCS+= purgatory/arch/i386/vga.c
 PURGATORY_C_SRCS+= purgatory/arch/i386/pic.c
+PURGATORY_C_SRCS+= purgatory/arch/i386/crashdump_backup.c
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/i386/purgatory-x86.c kexec-tools-1.101-kdump/purgatory/arch/i386/purgatory-x86.c
--- kexec-tools-1.101/purgatory/arch/i386/purgatory-x86.c	2004-12-21 21:59:48.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/i386/purgatory-x86.c	2006-01-19 11:41:27.000000000 +0530
@@ -30,6 +30,7 @@ void x86_setup_cpu(void)
 uint8_t reset_vga = 0;
 uint8_t legacy_timer = 0;
 uint8_t legacy_pic   = 0;
+uint8_t panic_kernel = 0;
 
 void setup_arch(void)
 {
@@ -38,3 +39,9 @@ void setup_arch(void)
 	if (legacy_pic)   x86_setup_legacy_pic();
 	/* if (legacy_timer) x86_setup_legacy_timer(); */
 }
+
+/* This function can be used to execute after the SHA256 verification. */
+void post_verification_setup_arch(void)
+{
+	if (panic_kernel)   crashdump_backup_memory();
+}
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/i386/purgatory-x86.h kexec-tools-1.101-kdump/purgatory/arch/i386/purgatory-x86.h
--- kexec-tools-1.101/purgatory/arch/i386/purgatory-x86.h	2004-12-20 17:52:26.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/i386/purgatory-x86.h	2006-01-19 11:41:27.000000000 +0530
@@ -4,5 +4,6 @@
 void x86_reset_vga(void);
 void x86_setup_legacy_pic(void);
 void x86_setup_legacy_timer(void);
+void crashdump_backup_memory(void);
 
 #endif /* PURGATORY_X86_H */
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/ia64/purgatory-ia64.c kexec-tools-1.101-kdump/purgatory/arch/ia64/purgatory-ia64.c
--- kexec-tools-1.101/purgatory/arch/ia64/purgatory-ia64.c	2004-12-21 04:15:21.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/ia64/purgatory-ia64.c	2006-01-19 11:41:27.000000000 +0530
@@ -5,3 +5,9 @@ void setup_arch(void)
 {
 	/* Nothing for now */
 }
+
+/* This function can be used to execute after the SHA256 verification. */
+void post_verification_setup_arch(void)
+{
+	/* Nothing for now */
+}
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/ppc/purgatory-ppc.c kexec-tools-1.101-kdump/purgatory/arch/ppc/purgatory-ppc.c
--- kexec-tools-1.101/purgatory/arch/ppc/purgatory-ppc.c	2004-12-21 04:17:43.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/ppc/purgatory-ppc.c	2006-01-19 11:41:27.000000000 +0530
@@ -5,3 +5,9 @@ void setup_arch(void)
 {
 	/* Nothing for now */
 }
+
+/* This function can be used to execute after the SHA256 verification. */
+void post_verification_setup_arch(void)
+{
+	/* Nothing for now */
+}
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/ppc64/console-ppc64.c kexec-tools-1.101-kdump/purgatory/arch/ppc64/console-ppc64.c
--- kexec-tools-1.101/purgatory/arch/ppc64/console-ppc64.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/ppc64/console-ppc64.c	2006-01-19 18:20:08.000000000 +0530
@@ -0,0 +1,27 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. 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.
+ */
+
+#include <purgatory.h>
+
+void putchar(int c)
+{
+	return;
+}
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/ppc64/crashdump_backup.c kexec-tools-1.101-kdump/purgatory/arch/ppc64/crashdump_backup.c
--- kexec-tools-1.101/purgatory/arch/ppc64/crashdump_backup.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/ppc64/crashdump_backup.c	2006-01-19 18:20:08.000000000 +0530
@@ -0,0 +1,41 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. 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.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#define BACKUP_REGION_SOURCE 0x0
+#define BACKUP_REGION_SIZE 32*1024
+
+extern unsigned long backup_start;
+
+/* Backup first 32KB of memory to backup region reserved by kexec */
+void crashdump_backup_memory(void)
+{
+	void *dest, *src;
+
+	src = (void *)BACKUP_REGION_SOURCE;
+
+	if (backup_start) {
+		dest = (void *)(backup_start);
+		memcpy(dest, src, BACKUP_REGION_SIZE);
+	}
+}
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/ppc64/Makefile kexec-tools-1.101-kdump/purgatory/arch/ppc64/Makefile
--- kexec-tools-1.101/purgatory/arch/ppc64/Makefile	2004-12-17 11:00:20.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/ppc64/Makefile	2006-01-19 18:20:08.000000000 +0530
@@ -2,6 +2,7 @@
 # Purgatory ppc
 #
 
-PURGATORY_C_SRCS+=
-PURGATORY_S_SRCS+=
-
+PURGATORY_S_SRCS+= purgatory/arch/ppc64/v2wrap.S
+PURGATORY_C_SRCS += purgatory/arch/ppc64/purgatory-ppc64.c
+PURGATORY_C_SRCS += purgatory/arch/ppc64/console-ppc64.c
+PURGATORY_C_SRCS += purgatory/arch/ppc64/crashdump_backup.c
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/ppc64/purgatory-ppc64.c kexec-tools-1.101-kdump/purgatory/arch/ppc64/purgatory-ppc64.c
--- kexec-tools-1.101/purgatory/arch/ppc64/purgatory-ppc64.c	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/ppc64/purgatory-ppc64.c	2006-01-19 18:20:08.000000000 +0530
@@ -0,0 +1,41 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. 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.
+ */
+
+#include <purgatory.h>
+#include "purgatory-ppc64.h"
+
+unsigned int panic_kernel = 0;
+unsigned long backup_start = 0;
+unsigned long stack = 0;
+unsigned long dt_offset = 0;
+unsigned long my_toc = 0;
+unsigned long kernel = 0;
+
+void setup_arch(void)
+{
+	return;
+}
+
+void post_verification_setup_arch(void)
+{
+	if (panic_kernel)
+		crashdump_backup_memory();
+}
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/ppc64/purgatory-ppc64.h kexec-tools-1.101-kdump/purgatory/arch/ppc64/purgatory-ppc64.h
--- kexec-tools-1.101/purgatory/arch/ppc64/purgatory-ppc64.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/ppc64/purgatory-ppc64.h	2006-01-19 18:20:08.000000000 +0530
@@ -0,0 +1,6 @@
+#ifndef PURGATORY_PPC64_H
+#define PURGATORY_PPC64_H
+
+void crashdump_backup_memory(void);
+
+#endif /* PURGATORY_PPC64_H */
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/ppc64/v2wrap.S kexec-tools-1.101-kdump/purgatory/arch/ppc64/v2wrap.S
--- kexec-tools-1.101/purgatory/arch/ppc64/v2wrap.S	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/ppc64/v2wrap.S	2006-01-19 18:20:08.000000000 +0530
@@ -0,0 +1,128 @@
+#
+#  kexec: Linux boots Linux
+#
+#  Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
+#  Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation
+#
+#  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.
+#
+
+# v2wrap.S
+# a wrapper to call purgatory code to backup first
+# 32kB of first kernel into the backup region
+# reserved by kexec-tools.
+# Invokes ppc64 kernel with the expected arguments
+# of kernel(device-tree, phys-offset, 0)
+
+#
+# calling convention:
+#   r3 = physical number of this cpu (all cpus)
+#   r4 = address of this chunk (master only)
+# master enters at purgatory_start (aka first byte of this chunk)
+# slaves (additional cpus), if any, enter a copy of the
+# first 0x100 bytes of this code relocated to 0x0
+#
+# in other words,
+#   a copy of the first 0x100 bytes of this code is copied to 0
+#   and the slaves are sent to address 0x60
+#   with r3 = their physical cpu number.
+
+#define LOADADDR(rn,name) \
+	lis     rn,name##@highest;      \
+	ori     rn,rn,name##@higher;    \
+	rldicr  rn,rn,32,31;            \
+	oris    rn,rn,name##@h;         \
+	ori     rn,rn,name##@l
+
+# look a bit like a Linux kernel here ...
+	.machine ppc64
+	.globl purgatory_start
+purgatory_start:	b	master
+	tweq	0,0
+master:
+	or	1,1,1		# low priority to let other thread catchup
+	isync
+	mr      17,3            # save cpu id to r17
+	mr      15,4            # save physical address in reg15
+
+	LOADADDR(6,my_toc)
+	ld      2,0(6)          #setup toc
+
+	LOADADDR(6,stack)
+	ld      1,0(6)          #setup stack
+
+	subi    1,1,112
+	bl      .purgatory
+	nop
+
+	b       81f
+	.org purgatory_start + 0x60     # ABI: slaves start at 60 with r3=phys
+slave:
+	# load slave spin code address and branch into that
+	LOADADDR(6,slave_spin)
+	ld      4,0(6)
+	mtctr 4
+	bctr
+
+spin: .long 1
+slave_spin_code:
+	lis     5,spin@ha
+	lwz     5,spin@l(5)
+	cmpwi   0,5,0
+	bne     slave_spin_code
+	ba 0x60
+
+81:				# master continues here
+	or	3,3,3		# ok back to high, lets boot
+	lis	6,0x1
+	mtctr	6		# delay a bit for slaves to catch up
+83:	bdnz	83b		# before we overwrite 0-100 again
+
+	LOADADDR(16, dt_offset)
+	ld      3,0(16)         # load device-tree address
+	mr      16,3            # save dt address in reg16
+	lwz     6,20(3)         # fetch version number
+	cmpwi   0,6,2           # v2 ?
+	blt     80f
+	stw     17,28(3)        # save my cpu number as boot_cpu_phys
+80:
+	LOADADDR(6,kernel)
+	ld      4,0(6)          # load the kernel address
+
+	addi	5,4,-8		# prepare copy with update form instructions
+	li	6,0x100/8
+	mtctr	6
+	li	6,-8
+85:	ldu	7,8(5)
+	stdu	7,8(6)
+	bdnz	85b
+
+	li	5,0		# r5 will be 0 for kernel
+	dcbst	0,5		# store dcache, flush icache
+	dcbst	0,6		# 0 and 0xf8 covers us with 128 byte lines
+	mtctr	4		# prepare branch too
+	sync
+	icbi	0,5
+	icbi	0,6
+	sync
+	isync
+	lis     6,spin@ha
+	li      0,0
+	stw     0,spin@l(6)
+	mr      3,16            # restore dt address
+
+	bctr			# start kernel
+
+slave_spin: .llong  slave_spin_code
+
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/s390/include/limits.h kexec-tools-1.101-kdump/purgatory/arch/s390/include/limits.h
--- kexec-tools-1.101/purgatory/arch/s390/include/limits.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/s390/include/limits.h	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,54 @@
+#ifndef _LIMITS_H_
+#define _LIMITS_H_
+
+/* Number of bits in a `char'.	*/
+#  define CHAR_BIT	8
+
+/* Minimum and maximum values a `signed char' can hold.  */
+#  define SCHAR_MIN	(-128)
+#  define SCHAR_MAX	127
+
+/* Maximum value an `unsigned char' can hold.  (Minimum is 0.)  */
+#  define UCHAR_MAX	255
+
+#  define CHAR_MIN	SCHAR_MIN
+#  define CHAR_MAX	SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold.  */
+#  define SHRT_MIN	(-32768)
+#  define SHRT_MAX	32767
+
+/* Maximum value an `unsigned short int' can hold.  (Minimum is 0.)  */
+#  define USHRT_MAX	65535
+
+/* Minimum and maximum values a `signed int' can hold.  */
+#  define INT_MIN	(-INT_MAX - 1)
+#  define INT_MAX	2147483647
+
+/* Maximum value an `unsigned int' can hold.  (Minimum is 0.)  */
+#  define UINT_MAX	4294967295U
+
+/* Minimum and maximum values a `signed long int' can hold.  */
+#ifdef __s390x__
+#   define LONG_MAX	9223372036854775807L
+#else
+#   define LONG_MAX	2147483647L
+#endif
+
+#  define LONG_MIN	(-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long int' can hold.  (Minimum is 0.)  */
+#ifdef __s390x__
+#   define ULONG_MAX	18446744073709551615UL
+#else
+#   define ULONG_MAX	4294967295UL
+#endif
+
+/* Minimum and maximum values a `signed long long int' can hold.  */
+#   define LLONG_MAX	9223372036854775807LL
+#   define LLONG_MIN	(-LLONG_MAX - 1LL)
+
+/* Maximum value an `unsigned long long int' can hold.  (Minimum is 0.)  */
+#   define ULLONG_MAX	18446744073709551615ULL
+
+#endif	/* !_LIMITS_H_ */
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/s390/include/stdint.h kexec-tools-1.101-kdump/purgatory/arch/s390/include/stdint.h
--- kexec-tools-1.101/purgatory/arch/s390/include/stdint.h	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/s390/include/stdint.h	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,24 @@
+#ifndef _STDINT_H
+#define _STDINT_H
+
+typedef unsigned long		size_t;
+
+typedef unsigned char		uint8_t;
+typedef unsigned short		uint16_t;
+typedef unsigned int		uint32_t;
+#ifdef __s390x__
+typedef unsigned long		uint64_t;
+#else
+typedef unsigned long long	uint64_t;
+#endif
+
+typedef signed char 		int8_t;
+typedef short 			int16_t;
+typedef int 			int32_t;
+#ifdef __s390x__
+typedef long			int64_t;
+#else
+typedef long long		int64_t;
+#endif
+
+#endif
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/s390/Makefile kexec-tools-1.101-kdump/purgatory/arch/s390/Makefile
--- kexec-tools-1.101/purgatory/arch/s390/Makefile	1970-01-01 05:30:00.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/s390/Makefile	2006-01-19 11:41:37.000000000 +0530
@@ -0,0 +1,7 @@
+#
+# Purgatory s390
+#
+
+PURGATORY_C_SRCS+=
+PURGATORY_S_SRCS+=
+
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/x86_64/Makefile kexec-tools-1.101-kdump/purgatory/arch/x86_64/Makefile
--- kexec-tools-1.101/purgatory/arch/x86_64/Makefile	2004-12-21 12:43:53.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/x86_64/Makefile	2006-01-19 11:41:41.000000000 +0530
@@ -9,6 +9,7 @@ PURGATORY_S_SRCS+= purgatory/arch/x86_64
 PURGATORY_S_SRCS+= purgatory/arch/x86_64/setup-x86_64.S
 PURGATORY_S_SRCS+= purgatory/arch/x86_64/stack.S
 PURGATORY_C_SRCS+= purgatory/arch/x86_64/purgatory-x86_64.c
+PURGATORY_C_SRCS+= purgatory/arch/i386/crashdump_backup.c
 PURGATORY_C_SRCS+= purgatory/arch/i386/console-x86.c
 PURGATORY_C_SRCS+= purgatory/arch/i386/vga.c
 PURGATORY_C_SRCS+= purgatory/arch/i386/pic.c
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/arch/x86_64/purgatory-x86_64.c kexec-tools-1.101-kdump/purgatory/arch/x86_64/purgatory-x86_64.c
--- kexec-tools-1.101/purgatory/arch/x86_64/purgatory-x86_64.c	2004-12-21 22:07:41.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/arch/x86_64/purgatory-x86_64.c	2006-01-19 11:41:41.000000000 +0530
@@ -4,9 +4,16 @@
 
 uint8_t reset_vga = 0;
 uint8_t legacy_pic = 0;
+uint8_t panic_kernel = 0;
 
 void setup_arch(void)
 {
 	if (reset_vga)    x86_reset_vga();
 	if (legacy_pic)   x86_setup_legacy_pic();
 }
+
+/* This function can be used to execute after the SHA256 verification. */
+void post_verification_setup_arch(void)
+{
+	 if (panic_kernel)   crashdump_backup_memory();
+}
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/include/purgatory.h kexec-tools-1.101-kdump/purgatory/include/purgatory.h
--- kexec-tools-1.101/purgatory/include/purgatory.h	2004-12-18 18:42:15.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/include/purgatory.h	2006-01-19 11:41:27.000000000 +0530
@@ -4,5 +4,6 @@
 void putchar(int ch);
 void printf(const char *fmt, ...);
 void setup_arch(void);
+void post_verification_setup_arch(void);
 
 #endif /* PURGATORY_H */
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/Makefile kexec-tools-1.101-kdump/purgatory/Makefile
--- kexec-tools-1.101/purgatory/Makefile	2005-01-09 04:06:32.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/Makefile	2006-01-19 18:20:08.000000000 +0530
@@ -6,6 +6,11 @@
 # There is probably a cleaner way to do this but for now this
 # should keep us from accidentially include unsafe library functions
 # or headers.
+
+ifeq ($(ARCH),ppc64)
+LDFLAGS = -melf64ppc
+endif
+
 PCFLAGS:=-Wall -Os  \
 	-I$(shell $(CC) -print-file-name=include) \
 	-Ipurgatory/include -Ipurgatory/arch/$(ARCH)/include \
@@ -16,11 +21,11 @@ PCFLAGS += $(call cc-option, -fnobuiltin
 PCFLAGS += $(call cc-option, -fnostdinc)
 PCFLAGS += $(call cc-option, -fno-zero-initialized-in-bss)
 
-PURGATORY_C_SRCS:= 
+PURGATORY_C_SRCS:=
 PURGATORY_C_SRCS += purgatory/purgatory.c
 PURGATORY_C_SRCS += purgatory/printf.c
 PURGATORY_C_SRCS += purgatory/string.c
-PURGATORY_S_OBJS:= 
+PURGATORY_S_OBJS:=
 
 include purgatory/arch/$(ARCH)/Makefile
 
diff -urNp -X dontdiff kexec-tools-1.101/purgatory/purgatory.c kexec-tools-1.101-kdump/purgatory/purgatory.c
--- kexec-tools-1.101/purgatory/purgatory.c	2004-12-22 00:21:03.000000000 +0530
+++ kexec-tools-1.101-kdump/purgatory/purgatory.c	2006-01-19 11:41:27.000000000 +0530
@@ -44,4 +44,5 @@ void purgatory(void)
 	printf("I'm in purgatory\n");
 	setup_arch();
 	verify_sha256_digest();
+	post_verification_setup_arch();
 }