2603512c5d
prepare elf core header routine o Fix ppc64 kexec -p failure for gcc 4.10 o Fix few warnings for gcc 4.10 o Add the missing --initrd option for ppc64 o Fix ppc64 persistent root device bug - Remove --elf32-core-headers from default configuration, users may re-add it via KEXEC_ARGS. - Remove obsolete KEXEC_HEADERS
5944 lines
183 KiB
Diff
5944 lines
183 KiB
Diff
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, ¬es_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, ¬es_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", ®s, 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, ¬es_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, ¬es_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", ®s, 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();
|
|
}
|