kexec-tools/kexec-tools-1.101-kdump.patch

4514 lines
137 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 2005-12-14 16:00:40.000000000 +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
@@ -1421,6 +1427,10 @@ if test "${with_gamecube+set}" = set; th
EXTRA_CFLAGS="$EXTRA_CFLAGS -DCONFIG_GAMECUBE=1"
fi;
+# Check whether ppc64. Add -m64 for building 64-bit binary
+if test "$ARCH" = ppc64; then
+ EXTRA_CFLAGS="$EXTRA_CFLAGS -m64"
+fi;
# Check whether --with-zlib or --without-zlib was given.
if test "${with_zlib+set}" = set; then
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 2005-12-15 16:51:43.720392560 +0530
@@ -0,0 +1,724 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Vivek Goyal (vgoyal@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "../../crashdump.h"
+#include "kexec-x86.h"
+#include "crashdump-x86.h"
+#include <x86/x86-linux.h>
+
+extern struct arch_options_t arch_options;
+
+/* Forward Declaration. */
+static int exclude_crash_reserve_region(int *nr_ranges);
+
+/* Stores a sorted list of RAM memory ranges for which to create elf headers.
+ * A separate program header is created for backup region */
+static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+
+/* Memory region reserved for storing panic kernel and other data. */
+static struct memory_range crash_reserved_mem;
+
+/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
+ * create Elf headers. Keeping it separate from get_memory_ranges() as
+ * requirements are different in the case of normal kexec and crashdumps.
+ *
+ * Normal kexec needs to look at all of available physical memory irrespective
+ * of the fact how much of it is being used by currently running kernel.
+ * Crashdumps need to have access to memory regions actually being used by
+ * running kernel. Expecting a different file/data structure than /proc/iomem
+ * to look into down the line. May be something like /proc/kernelmem or may
+ * be zone data structures exported from kernel.
+ */
+static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+{
+ const char iomem[]= "/proc/iomem";
+ int memory_ranges = 0;
+ char line[MAX_LINE];
+ FILE *fp;
+ unsigned long long start, end;
+
+ fp = fopen(iomem, "r");
+ if (!fp) {
+ fprintf(stderr, "Cannot open %s: %s\n",
+ iomem, strerror(errno));
+ return -1;
+ }
+
+ /* First entry is for first 640K region. Different bios report first
+ * 640K in different manner hence hardcoding it */
+ crash_memory_range[0].start = 0x00000000;
+ crash_memory_range[0].end = 0x0009ffff;
+ crash_memory_range[0].type = RANGE_RAM;
+ memory_ranges++;
+
+ while(fgets(line, sizeof(line), fp) != 0) {
+ char *str;
+ int type, consumed, count;
+ if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
+ break;
+ count = sscanf(line, "%Lx-%Lx : %n",
+ &start, &end, &consumed);
+ if (count != 2)
+ continue;
+ str = line + consumed;
+#if 0
+ printf("%016Lx-%016Lx : %s",
+ start, end, str);
+#endif
+ /* Only Dumping memory of type System RAM. */
+ if (memcmp(str, "System RAM\n", 11) == 0) {
+ type = RANGE_RAM;
+ } else if (memcmp(str, "Crash kernel\n", 13) == 0) {
+ /* Reserved memory region. New kernel can
+ * use this region to boot into. */
+ crash_reserved_mem.start = start;
+ crash_reserved_mem.end = end;
+ crash_reserved_mem.type = RANGE_RAM;
+ continue;
+ } else {
+ continue;
+ }
+
+ /* First 640K already registered */
+ if (start >= 0x00000000 && end <= 0x0009ffff)
+ continue;
+
+ crash_memory_range[memory_ranges].start = start;
+ crash_memory_range[memory_ranges].end = end;
+ crash_memory_range[memory_ranges].type = type;
+ memory_ranges++;
+
+ /* Segregate linearly mapped region. */
+ if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) {
+ crash_memory_range[memory_ranges-1].end = MAXMEM -1;
+
+ /* Add segregated region. */
+ crash_memory_range[memory_ranges].start = MAXMEM;
+ crash_memory_range[memory_ranges].end = end;
+ crash_memory_range[memory_ranges].type = type;
+ memory_ranges++;
+ }
+ }
+ fclose(fp);
+ if (exclude_crash_reserve_region(&memory_ranges) < 0)
+ return -1;
+ *range = crash_memory_range;
+ *ranges = memory_ranges;
+#if 0
+ int i;
+ printf("CRASH MEMORY RANGES\n");
+ for(i = 0; i < memory_ranges; i++) {
+ start = crash_memory_range[i].start;
+ end = crash_memory_range[i].end;
+ printf("%016Lx-%016Lx\n", start, end);
+ }
+#endif
+ return 0;
+}
+
+/* Removes crash reserve region from list of memory chunks for whom elf program
+ * headers have to be created. Assuming crash reserve region to be a single
+ * continuous area fully contained inside one of the memory chunks */
+static int exclude_crash_reserve_region(int *nr_ranges)
+{
+ int i, j, tidx = -1;
+ unsigned long long cstart, cend;
+ struct memory_range temp_region;
+
+ /* Crash reserved region. */
+ cstart = crash_reserved_mem.start;
+ cend = crash_reserved_mem.end;
+
+ for (i = 0; i < (*nr_ranges); i++) {
+ unsigned long long mstart, mend;
+ mstart = crash_memory_range[i].start;
+ mend = crash_memory_range[i].end;
+ if (cstart < mend && cend > mstart) {
+ if (cstart != mstart && cend != mend) {
+ /* Split memory region */
+ crash_memory_range[i].end = cstart - 1;
+ temp_region.start = cend + 1;
+ temp_region.end = mend;
+ temp_region.type = RANGE_RAM;
+ tidx = i+1;
+ } else if (cstart != mstart)
+ crash_memory_range[i].end = cstart - 1;
+ else
+ crash_memory_range[i].start = cend + 1;
+ }
+ }
+ /* Insert split memory region, if any. */
+ if (tidx >= 0) {
+ if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) {
+ /* No space to insert another element. */
+ fprintf(stderr, "Error: Number of crash memory ranges"
+ " excedeed the max limit\n");
+ return -1;
+ }
+ for (j = (*nr_ranges - 1); j >= tidx; j--)
+ crash_memory_range[j+1] = crash_memory_range[j];
+ crash_memory_range[tidx].start = temp_region.start;
+ crash_memory_range[tidx].end = temp_region.end;
+ crash_memory_range[tidx].type = temp_region.type;
+ (*nr_ranges)++;
+ }
+ return 0;
+}
+
+/* Adds a segment from list of memory regions which new kernel can use to
+ * boot. Segment start and end should be aligned to 1K boundary. */
+static int add_memmap(struct memory_range *memmap_p, unsigned long long addr,
+ size_t size)
+{
+ int i, j, nr_entries = 0, tidx = 0, align = 1024;
+ unsigned long long mstart, mend;
+
+ /* Do alignment check. */
+ if ((addr%align) || (size%align))
+ return -1;
+
+ /* Make sure at least one entry in list is free. */
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (!mstart && !mend)
+ break;
+ else
+ nr_entries++;
+ }
+ if (nr_entries == CRASH_MAX_MEMMAP_NR)
+ return -1;
+
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (mstart == 0 && mend == 0)
+ break;
+ if (mstart <= (addr+size-1) && mend >=addr)
+ /* Overlapping region. */
+ return -1;
+ else if (addr > mend)
+ tidx = i+1;
+ }
+ /* Insert the memory region. */
+ for (j = nr_entries-1; j >= tidx; j--)
+ memmap_p[j+1] = memmap_p[j];
+ memmap_p[tidx].start = addr;
+ memmap_p[tidx].end = addr + size - 1;
+#if 0
+ printf("Memmap after adding segment\n");
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (mstart == 0 && mend == 0)
+ break;
+ printf("%016llx - %016llx\n",
+ mstart, mend);
+ }
+#endif
+ return 0;
+}
+
+/* Removes a segment from list of memory regions which new kernel can use to
+ * boot. Segment start and end should be aligned to 1K boundary. */
+static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr,
+ size_t size)
+{
+ int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024;
+ unsigned long long mstart, mend;
+ struct memory_range temp_region;
+
+ /* Do alignment check. */
+ if ((addr%align) || (size%align))
+ return -1;
+
+ /* Make sure at least one entry in list is free. */
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (!mstart && !mend)
+ break;
+ else
+ nr_entries++;
+ }
+ if (nr_entries == CRASH_MAX_MEMMAP_NR)
+ /* List if full */
+ return -1;
+
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (mstart == 0 && mend == 0)
+ /* Did not find the segment in the list. */
+ return -1;
+ if (mstart <= addr && mend >= (addr + size - 1)) {
+ if (mstart == addr && mend == (addr + size - 1)) {
+ /* Exact match. Delete region */
+ operation = -1;
+ tidx = i;
+ break;
+ }
+ if (mstart != addr && mend != (addr + size - 1)) {
+ /* Split in two */
+ memmap_p[i].end = addr - 1;
+ temp_region.start = addr + size;
+ temp_region.end = mend;
+ operation = 1;
+ tidx = i;
+ break;
+ }
+
+ /* No addition/deletion required. Adjust the existing.*/
+ if (mstart != addr) {
+ memmap_p[i].end = addr - 1;
+ break;
+ } else {
+ memmap_p[i].start = addr + size;
+ break;
+ }
+ }
+ }
+ if ((operation == 1) && tidx >=0) {
+ /* Insert the split memory region. */
+ for (j = nr_entries-1; j > tidx; j--)
+ memmap_p[j+1] = memmap_p[j];
+ memmap_p[tidx+1] = temp_region;
+ }
+ if ((operation == -1) && tidx >=0) {
+ /* Delete the exact match memory region. */
+ for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++)
+ memmap_p[j-1] = memmap_p[j];
+ memmap_p[j-1].start = memmap_p[j-1].end = 0;
+ }
+#if 0
+ printf("Memmap after deleting segment\n");
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (mstart == 0 && mend == 0) {
+ break;
+ }
+ printf("%016llx - %016llx\n",
+ mstart, mend);
+ }
+#endif
+ return 0;
+}
+
+/* Converts unsigned long to ascii string. */
+static void ultoa(unsigned long i, char *str)
+{
+ int j = 0, k;
+ char tmp;
+
+ do {
+ str[j++] = i % 10 + '0';
+ } while ((i /=10) > 0);
+ str[j] = '\0';
+
+ /* Reverse the string. */
+ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
+ tmp = str[k];
+ str[k] = str[j];
+ str[j] = tmp;
+ }
+}
+
+/* Adds the appropriate memmap= options to command line, indicating the
+ * memory regions the new kernel can use to boot into. */
+static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p)
+{
+ int i, cmdlen, len, min_sizek = 100;
+ char str_mmap[256], str_tmp[20];
+
+ /* Exact map */
+ strcpy(str_mmap, " memmap=exactmap");
+ len = strlen(str_mmap);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str_mmap);
+
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ unsigned long startk, endk;
+ startk = (memmap_p[i].start/1024);
+ endk = ((memmap_p[i].end + 1)/1024);
+ if (!startk && !endk)
+ /* All regions traversed. */
+ break;
+
+ /* A region is not worth adding if region size < 100K. It eats
+ * up precious command line length. */
+ if ((endk - startk) < min_sizek)
+ continue;
+ strcpy (str_mmap, " memmap=");
+ ultoa((endk-startk), str_tmp);
+ strcat (str_mmap, str_tmp);
+ strcat (str_mmap, "K@");
+ ultoa(startk, str_tmp);
+ strcat (str_mmap, str_tmp);
+ strcat (str_mmap, "K");
+ len = strlen(str_mmap);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str_mmap);
+ }
+
+#if 0
+ printf("Command line after adding memmap\n");
+ printf("%s\n", cmdline);
+#endif
+ return 0;
+}
+
+/* Adds the elfcorehdr= command line parameter to command line. */
+static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr)
+{
+ int cmdlen, len, align = 1024;
+ char str[30], *ptr;
+
+ /* Passing in elfcorehdr=xxxK format. Saves space required in cmdline.
+ * Ensure 1K alignment*/
+ if (addr%align)
+ return -1;
+ addr = addr/align;
+ ptr = str;
+ strcpy(str, " elfcorehdr=");
+ ptr += strlen(str);
+ ultoa(addr, ptr);
+ strcat(str, "K");
+ len = strlen(str);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str);
+#if 0
+ printf("Command line after adding elfcorehdr\n");
+ printf("%s\n", cmdline);
+#endif
+ return 0;
+}
+
+
+/*
+ * This routine is specific to i386 architecture to maintain the
+ * backward compatibility, other architectures can use the per
+ * cpu version get_crash_notes_per_cpu() directly.
+ */
+static int get_crash_notes(int cpu, uint64_t *addr)
+{
+ char crash_notes[PATH_MAX];
+ char line[MAX_LINE];
+ FILE *fp;
+ unsigned long vaddr;
+ int count;
+
+ sprintf(crash_notes, "/sys/kernel/crash_notes");
+ fp = fopen(crash_notes, "r");
+ if (fp) {
+ if (fgets(line, sizeof(line), fp) != 0) {
+ count = sscanf(line, "%lx", &vaddr);
+ if (count != 1)
+ die("Cannot parse %s: %s\n", crash_notes,
+ strerror(errno));
+ }
+ *addr = __pa(vaddr + (cpu * MAX_NOTE_BYTES));
+#if 0
+ printf("crash_notes addr = %Lx\n", *addr);
+#endif
+ return 0;
+ } else
+ return get_crash_notes_per_cpu(cpu, addr);
+}
+
+/* Prepares the crash memory elf64 headers and stores in supplied buffer. */
+static int prepare_crash_memory_elf64_headers(struct kexec_info *info,
+ void *buf, unsigned long size)
+{
+ Elf64_Ehdr *elf;
+ Elf64_Phdr *phdr;
+ int i;
+ char *bufp;
+ long int nr_cpus = 0;
+ uint64_t notes_addr;
+
+ bufp = (char*) buf;
+
+ /* Setup ELF Header*/
+ elf = (Elf64_Ehdr *) bufp;
+ bufp += sizeof(Elf64_Ehdr);
+ memcpy(elf->e_ident, ELFMAG, SELFMAG);
+ elf->e_ident[EI_CLASS] = ELFCLASS64;
+ elf->e_ident[EI_DATA] = ELFDATA2LSB;
+ elf->e_ident[EI_VERSION]= EV_CURRENT;
+ elf->e_ident[EI_OSABI] = ELFOSABI_NONE;
+ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+ elf->e_type = ET_CORE;
+ elf->e_machine = EM_386;
+ elf->e_version = EV_CURRENT;
+ elf->e_entry = 0;
+ elf->e_phoff = sizeof(Elf64_Ehdr);
+ elf->e_shoff = 0;
+ elf->e_flags = 0;
+ elf->e_ehsize = sizeof(Elf64_Ehdr);
+ elf->e_phentsize= sizeof(Elf64_Phdr);
+ elf->e_phnum = 0;
+ elf->e_shentsize= 0;
+ elf->e_shnum = 0;
+ elf->e_shstrndx = 0;
+
+ /* PT_NOTE program headers. One per cpu*/
+ nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+ if (nr_cpus < 0) {
+ return -1;
+ }
+
+ for (i = 0; i < nr_cpus; i++) {
+ if (get_crash_notes(i, &notes_addr) < 0) {
+ /* This cpu is not present. Skip it. */
+ continue;
+ }
+ phdr = (Elf64_Phdr *) bufp;
+ bufp += sizeof(Elf64_Phdr);
+ phdr->p_type = PT_NOTE;
+ phdr->p_flags = 0;
+ phdr->p_offset = phdr->p_paddr = notes_addr;
+ phdr->p_vaddr = 0;
+ phdr->p_filesz = phdr->p_memsz = MAX_NOTE_BYTES;
+ /* Do we need any alignment of segments? */
+ phdr->p_align = 0;
+
+ /* Increment number of program headers. */
+ (elf->e_phnum)++;
+ }
+
+ /* Setup PT_LOAD type program header for every system RAM chunk.
+ * A seprate program header for Backup Region*/
+ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+ unsigned long long mstart, mend;
+ 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 + 1;
+ /* Do we need any alignment of segments? */
+ phdr->p_align = 0;
+
+ /* Increment number of program headers. */
+ (elf->e_phnum)++;
+ }
+ return 0;
+}
+
+/* Prepares the crash memory elf32 headers and stores in supplied buffer. */
+static int prepare_crash_memory_elf32_headers(struct kexec_info *info,
+ void *buf, unsigned long size)
+{
+ Elf32_Ehdr *elf;
+ Elf32_Phdr *phdr;
+ int i;
+ char *bufp;
+ long int nr_cpus = 0;
+ uint64_t notes_addr;
+
+ bufp = (char*) buf;
+
+ /* Setup ELF Header*/
+ elf = (Elf32_Ehdr *) bufp;
+ bufp += sizeof(Elf32_Ehdr);
+ memcpy(elf->e_ident, ELFMAG, SELFMAG);
+ elf->e_ident[EI_CLASS] = ELFCLASS32;
+ elf->e_ident[EI_DATA] = ELFDATA2LSB;
+ elf->e_ident[EI_VERSION]= EV_CURRENT;
+ elf->e_ident[EI_OSABI] = ELFOSABI_NONE;
+ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+ elf->e_type = ET_CORE;
+ elf->e_machine = EM_386;
+ elf->e_version = EV_CURRENT;
+ elf->e_entry = 0;
+ elf->e_phoff = sizeof(Elf32_Ehdr);
+ elf->e_shoff = 0;
+ elf->e_flags = 0;
+ elf->e_ehsize = sizeof(Elf32_Ehdr);
+ elf->e_phentsize= sizeof(Elf32_Phdr);
+ elf->e_phnum = 0;
+ elf->e_shentsize= 0;
+ elf->e_shnum = 0;
+ elf->e_shstrndx = 0;
+
+ /* PT_NOTE program headers. One per cpu*/
+ nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+ if (nr_cpus < 0) {
+ return -1;
+ }
+
+ /* Need to find a better way to determine per cpu notes section size. */
+#define MAX_NOTE_BYTES 1024
+ for (i = 0; i < nr_cpus; i++) {
+ if (get_crash_notes(i, &notes_addr) < 0) {
+ /* This cpu is not present. Skip it. */
+ return -1;
+ }
+ phdr = (Elf32_Phdr *) bufp;
+ bufp += sizeof(Elf32_Phdr);
+ phdr->p_type = PT_NOTE;
+ phdr->p_flags = 0;
+ phdr->p_offset = phdr->p_paddr = notes_addr;
+ phdr->p_vaddr = 0;
+ phdr->p_filesz = phdr->p_memsz = MAX_NOTE_BYTES;
+ /* Do we need any alignment of segments? */
+ phdr->p_align = 0;
+
+ /* Increment number of program headers. */
+ (elf->e_phnum)++;
+ }
+
+ /* Setup PT_LOAD type program header for every system RAM chunk.
+ * A seprate program header for Backup Region*/
+ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+ unsigned long long mstart, mend;
+ mstart = crash_memory_range[i].start;
+ mend = crash_memory_range[i].end;
+ if (!mstart && !mend)
+ break;
+ 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 2005-12-14 15:57:17.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 2005-12-14 16:00:38.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 2005-12-14 15:57:15.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 2005-12-14 15:57:18.000000000 +0530
@@ -32,10 +32,12 @@
#include <elf.h>
#include <x86/x86-linux.h>
#include "../../kexec.h"
+#include "../../kexec-syscall.h"
#include "../../kexec-elf.h"
#include "../../kexec-elf-boot.h"
#include "x86-linux-setup.h"
#include "kexec-x86.h"
+#include "crashdump-x86.h"
#include <arch/options.h>
static const int probe_debug = 0;
@@ -86,7 +88,9 @@ int elf_x86_load(int argc, char **argv,
{
struct mem_ehdr ehdr;
const char *command_line;
+ char *modified_cmdline;
int command_line_len;
+ int modified_cmdline_len;
const char *ramdisk;
unsigned long entry, max_addr;
int arg_style;
@@ -119,6 +123,8 @@ int elf_x86_load(int argc, char **argv,
*/
arg_style = ARG_STYLE_ELF;
command_line = 0;
+ modified_cmdline = 0;
+ modified_cmdline_len = 0;
ramdisk = 0;
while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
switch(opt) {
@@ -156,6 +162,20 @@ int elf_x86_load(int argc, char **argv,
command_line_len = strlen(command_line) +1;
}
+ /* Need to append some command line parameters internally in case of
+ * taking crash dumps.
+ */
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
+ memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
+ if (command_line) {
+ strncpy(modified_cmdline, command_line,
+ COMMAND_LINE_SIZE);
+ modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+ }
+ modified_cmdline_len = strlen(modified_cmdline);
+ }
+
/* Load the ELF executable */
elf_exec_build_load(info, &ehdr, buf, len);
@@ -203,10 +223,20 @@ int elf_x86_load(int argc, char **argv,
const unsigned char *ramdisk_buf;
off_t ramdisk_length;
struct entry32_regs regs;
+ int rc = 0;
/* Get the linux parameter header */
hdr = xmalloc(sizeof(*hdr));
- param_base = add_buffer(info, hdr, sizeof(*hdr), sizeof(*hdr),
+
+ /* Hack: With some ld versions, vmlinux program headers show
+ * a gap of two pages between bss segment and data segment
+ * but effectively kernel considers it as bss segment and
+ * overwrites the any data placed there. Hence bloat the
+ * memsz of parameter segment to 16K to avoid being placed
+ * in such gaps.
+ * This is a makeshift solution until it is fixed in kernel
+ */
+ param_base = add_buffer(info, hdr, sizeof(*hdr), 16*1024,
16, 0, max_addr, 1);
/* Initialize the parameter header */
@@ -216,9 +246,19 @@ int elf_x86_load(int argc, char **argv,
/* Add a ramdisk to the current image */
ramdisk_buf = NULL;
ramdisk_length = 0;
- if (ramdisk) {
- unsigned char *ramdisk_buf;
+ if (ramdisk)
ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
+
+ /* If panic kernel is being loaded, additional segments need
+ * to be created. */
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ rc = load_crashdump_segments(info, modified_cmdline,
+ max_addr, 0);
+ if (rc < 0)
+ return -1;
+ /* Use new command line. */
+ command_line = modified_cmdline;
+ command_line_len = strlen(modified_cmdline) + 1;
}
/* Tell the kernel what is going on */
@@ -228,7 +268,7 @@ int elf_x86_load(int argc, char **argv,
ramdisk_buf, ramdisk_length);
/* Fill in the information bios calls would usually provide */
- setup_linux_system_parameters(&hdr->hdr);
+ setup_linux_system_parameters(&hdr->hdr, info->kexec_flags);
/* Initialize the registers */
elf_rel_get_symbol(&info->rhdr, "entry32_regs", &regs, sizeof(regs));
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/i386/kexec-multiboot-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-multiboot-x86.c
--- kexec-tools-1.101/kexec/arch/i386/kexec-multiboot-x86.c 2005-01-25 01:28:04.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/i386/kexec-multiboot-x86.c 2005-12-14 15:57:15.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 2005-12-15 11:55:22.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 2005-12-14 15:57:16.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 2005-12-14 15:57:16.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 2005-12-14 15:57:15.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) {
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 2005-12-14 15:57:15.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 2005-12-15 11:55:22.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 2005-12-15 11:55:22.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/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 2005-12-14 15:57:18.000000000 +0530
@@ -0,0 +1,340 @@
+/*
+ * 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-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];
+
+extern unsigned long initrd_base;
+extern unsigned long initrd_size;
+static int initrd_found = 0;
+
+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,initrd-start")) {
+ if (initrd_base)
+ *(unsigned long long *) data = initrd_base;
+ base = *(unsigned long long *)data;
+ initrd_found = 1;
+ }
+ 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;
+ else if (!strcmp(name, "linux,initrd-end")) {
+ if (initrd_size) {
+ *(unsigned long long *) data = initrd_base +
+ initrd_size;
+ size = initrd_size;
+ } else
+ end = *(unsigned long long *)data;
+ initrd_found = 1;
+ }
+ 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;
+}
+
+/* put all properties (files) in the property structure */
+void putprops(char *fn, DIR *dir)
+{
+ struct dirent *dp;
+
+ while ((dp = readdir(dir)) != NULL) {
+ strcpy(fn, dp->d_name);
+
+ if (lstat(pathname, statbuf))
+ err(pathname, ERR_STAT);
+
+ /* skip initrd entries if 2nd kernel does not need them */
+ if (!initrd_base && !strcmp(fn,"linux,initrd-end"))
+ continue;
+
+ if (!initrd_base && !strcmp(fn,"linux,initrd-start"))
+ 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, "htab_base") ||
+ !strcmp(dp->d_name, "htab_size") ||
+ !strcmp(dp->d_name, "kernel_end"))
+ continue;
+
+ if (S_ISREG(statbuf[0].st_mode)) {
+ int fd, len = statbuf[0].st_size;
+
+ *dt++ = 3;
+ *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);
+ close(fd);
+
+ checkprop(fn, dt);
+
+ dt += (len + 3)/4;
+ }
+ }
+ fn[0] = '\0';
+ if(errno == ENOSYS)
+ errno = 0;
+ if (errno)
+ err(pathname, ERR_READDIR);
+ checkprop(pathname, NULL);
+}
+
+/*
+ * put a node (directory) in the property structure. first properties
+ * then children.
+ */
+void putnode(void)
+{
+ DIR *dir;
+ char *dn;
+ struct dirent *dp;
+ char *basename;
+
+ *dt++ = 1;
+ strcpy((void *)dt, *pathstart ? pathstart : "/");
+ while(*dt)
+ dt++;
+ if (dt[-1] & 0xff)
+ dt++;
+
+ dir = opendir(pathname);
+
+ if (!dir)
+ err(pathname, ERR_OPENDIR);
+
+ basename = strrchr(pathname,'/');
+
+ strcat(pathname, "/");
+ dn = pathname + strlen(pathname);
+
+ putprops(dn, dir);
+
+ /* 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,8);
+ dt += (len + 3)/4;
+
+ reserve(initrd_base, initrd_size);
+ }
+
+ rewinddir(dir);
+
+ while ((dp = readdir(dir)) != NULL) {
+ strcpy(dn, dp->d_name);
+
+ 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;
+ closedir(dir);
+ dn[-1] = '\0';
+}
+
+struct bootblock bb[1];
+
+int create_flatten_tree(struct kexec_info *info, unsigned char **bufp, unsigned long *sizep)
+{
+ 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;
+
+ 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 *) realloc(*bufp, *sizep + bb->totalsize);
+ *bufp = buf;
+ memcpy(buf+(*sizep), bb, bb->off_mem_rsvmap);
+ tlen = *sizep + 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/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 2005-12-14 16:00:37.000000000 +0530
@@ -3,6 +3,7 @@
*
* Copyright (C) 2004 Adam Litke (agl@us.ibm.com)
* Copyright (C) 2004 IBM Corp.
+ * Copyright (C) 2005 R Sharada (sharada@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
@@ -33,45 +34,15 @@
#include "../../kexec.h"
#include "../../kexec-elf.h"
#include "kexec-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,
- },
-};
+int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *);
+int parse_options(char *);
+int setup_memory_ranges(void);
int elf_ppc64_probe(const char *buf, off_t len)
{
@@ -94,12 +65,69 @@ int elf_ppc64_probe(const char *buf, off
return result;
}
-int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
+int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
struct mem_ehdr ehdr;
+ const char *command_line;
+ const char *input_options;
+ int command_line_len;
+ const char *ramdisk;
+ const char *devicetreeblob;
+ unsigned long *lp;
+ int result;
+ int opt;
+#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
+ { "append", 1, NULL, OPT_APPEND },
+ { "ramdisk", 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;
+ command_line = 0;
+ input_options = 0;
+ ramdisk = 0;
+ devicetreeblob = 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:
+ input_options = optarg;
+ break;
+ case OPT_RAMDISK:
+ ramdisk = optarg;
+ break;
+ case OPT_DEVICETREEBLOB:
+ devicetreeblob = optarg;
+ break;
+ }
+ }
+
+ command_line_len = 0;
+ if (command_line) {
+ command_line_len = strlen(command_line) + 1;
+ }
+
+ if (input_options)
+ parse_options(input_options);
/* Parse the Elf file */
result = build_elf_exec_info(buf, len, &ehdr);
@@ -109,15 +137,180 @@ int elf_ppc64_load(int argc, char **argv
}
/* Load the Elf data */
+ setup_memory_ranges();
+ /* Load the Elf data. Physical load addresses in elf64 header do not
+ * show up correctly. Use user supplied address for now to patch the
+ * elf header
+ */
+ unsigned long long base_addr;
+ struct mem_phdr *phdr;
+ size_t size;
+
+ phdr = &ehdr.e_phdr[0];
+ size = phdr->p_filesz;
+ if (size > phdr->p_memsz) {
+ size = phdr->p_memsz;
+ }
+
+ base_addr = (unsigned long)locate_hole(info, size, 0, 0,
+ 0xFFFFFFFFFFFFFFFFUL, 1);
+ ehdr.e_phdr[0].p_paddr = base_addr;
result = elf_exec_load(&ehdr, info);
if (result < 0) {
free_elf_info(&ehdr);
return result;
}
- return 1;
+
+ /* Add a ram-disk to the current image */
+ if (ramdisk) {
+ if (devicetreeblob) {
+ fprintf(stderr, "Can't use ramdisk with device tree blob input\n");
+ return -1;
+ }
+ unsigned char *ramdisk_buf = NULL;
+ off_t ramdisk_size = 0;
+ unsigned long long ramdisk_addr;
+
+ ramdisk_buf = slurp_file(ramdisk, &ramdisk_size);
+ add_buffer(info, ramdisk_buf, ramdisk_size, ramdisk_size, 0, 0,
+ 0xFFFFFFFFFFFFFFFFUL, 1);
+ ramdisk_addr = (unsigned long long)info->segment[info->nr_segments-1].mem;
+ initrd_base = ramdisk_addr;
+ initrd_size = ramdisk_size;
+ }
+
+ /* Add v2wrap to the current image */
+ unsigned char *v2wrap_buf = NULL;
+ off_t v2wrap_size = 0;
+ unsigned long long *rsvmap_ptr;
+ struct bootblock *bb_ptr;
+ unsigned int devtree_size;
+
+ v2wrap_buf = (char *) malloc(purgatory_size);
+ if (v2wrap_buf == NULL) {
+ free_elf_info(&ehdr);
+ return -1;
+ }
+ memcpy(v2wrap_buf, purgatory, purgatory_size);
+ v2wrap_size = purgatory_size;
+ if (devicetreeblob) {
+ unsigned char *blob_buf = NULL;
+ off_t blob_size = 0;
+ unsigned char *tmp_buf = NULL;
+
+ /* Grab device tree from buffer */
+ blob_buf = slurp_file(devicetreeblob, &blob_size);
+
+ /* Append to purgatory */
+ tmp_buf = (unsigned char *) realloc(v2wrap_buf, v2wrap_size + blob_size);
+ v2wrap_buf = tmp_buf;
+ memcpy(v2wrap_buf+v2wrap_size, blob_buf, blob_size);
+ v2wrap_size += blob_size;
+
+ } else {
+ /* create from fs2dt */
+ create_flatten_tree(info, &v2wrap_buf, &v2wrap_size);
+ }
+ add_buffer(info, v2wrap_buf, v2wrap_size, v2wrap_size, 0, 0,
+ 0xFFFFFFFFFFFFFFFFUL, -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 +
+ 0x100);
+ rsvmap_ptr = (long long *)(
+ (unsigned char *)info->segment[(info->nr_segments)-1].buf +
+ bb_ptr->off_mem_rsvmap + 0x100);
+ while (*rsvmap_ptr || *(rsvmap_ptr+1)){
+ rsvmap_ptr += 2;
+ }
+ rsvmap_ptr -= 2;
+ *rsvmap_ptr = (unsigned long long)(
+ info->segment[(info->nr_segments)-1].mem + 0x100);
+ rsvmap_ptr++;
+ *rsvmap_ptr = (unsigned long long)bb_ptr->totalsize;
+
+ unsigned int nr_segments;
+ nr_segments = info->nr_segments;
+ lp = info->segment[nr_segments-1].buf + 0x100;
+ lp--;
+ *lp = info->segment[0].mem;
+ info->entry = info->segment[nr_segments-1].mem;
+
+ unsigned int i;
+ for (i = 0; i < nr_segments; i++)
+ printf("segment[i].mem:%lx\n", info->segment[i].mem);
+
+ return 0;
}
void elf_ppc64_usage(void)
{
fprintf(stderr, "elf support is still broken\n");
}
+
+struct param_struct {
+ const char *name;
+ void *val;
+};
+struct param_struct params;
+
+static char *next_arg(char *args, char **param, char **val)
+{
+ unsigned int i, equals = 0;
+ char *next;
+
+ /* Chew any extra spaces */
+ while (*args == ' ') args++;
+ for (i = 0; args[i]; i++) {
+ if (args[i] == ' ')
+ break;
+ if (equals == 0) {
+ if (args[i] == '=')
+ equals = i;
+ }
+ }
+ *param = args;
+ if (!equals)
+ *val = NULL;
+ else {
+ args[equals] = '\0';
+ *val = args + equals + 1;
+ }
+
+ if (args[i]) {
+ args[i] = '\0';
+ next = args + i + 1;
+ } else
+ next = args + i;
+ return next;
+}
+
+static int add_arg(char *param, char*val)
+{
+ int ret = 0;
+ if (strcmp(param, "initrd-base")==0)
+ initrd_base=strtoul(val, NULL, 0);
+ else if (strcmp(param, "initrd-size")==0)
+ initrd_size=strtoul(val, NULL, 0);
+ else {
+ printf("invalid option\n");
+ ret = 1;
+ }
+ return ret;
+}
+
+int parse_options(char *options)
+{
+ char *param, *val;
+ /* initrd-addr , initrd-size */
+ while (*options) {
+ int ret;
+ options = next_arg(options, &param, &val);
+ ret = add_arg(param, val);
+ }
+ /* All parsed OK */
+ return 0;
+}
diff -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 2005-12-14 15:57:19.000000000 +0530
@@ -22,7 +22,7 @@ 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];
+ shdr_end = &ehdr->e_shdr[ehdr->e_shnum];
for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
if (strcmp(shdr->sh_name, ".toc") == 0) {
return shdr;
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 2005-12-14 16:00:37.000000000 +0530
@@ -0,0 +1,527 @@
+/*
+ * 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 <arch/options.h>
+
+#define MAX_MEMORY_RANGES 64
+#define MAX_LINE 160
+#define MAXBYTES 128
+/* Platforms supported by kexec on PPC64 */
+#define PLATFORM_PSERIES 0x0100
+#define PLATFORM_PSERIES_LPAR 0x0101
+
+struct exclude_range {
+ unsigned long long start, end;
+};
+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;
+static int nr_exclude_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;
+ unsigned long long start, end;
+
+ 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++;
+#if 0
+ 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);
+ }
+ memory_max = base_memory_range[local_memory_ranges - 1].end;
+ closedir(dmem);
+ }
+ closedir(dir);
+ nr_memory_ranges = local_memory_ranges;
+ fprintf(stderr, "get base memory ranges:%d\n", nr_memory_ranges);
+ 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 */
+static int get_devtree_details()
+{
+ unsigned long long rmo_base;
+ unsigned long long tce_base;
+ unsigned int tce_size;
+ 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, "/kernel_end");
+ if ((file = fopen(fname, "r")) == NULL) {
+ perror(fname);
+ closedir(cdir);
+ closedir(dir);
+ return -1;
+ }
+ unsigned long long kernel_end;
+ if (fread(&kernel_end, sizeof(unsigned long), 1, file) != 1) {
+ perror(fname);
+ fclose(file);
+ closedir(cdir);
+ closedir(dir);
+ return -1;
+ }
+ /* Add kernel memory to exclude_range */
+ exclude_range[i].start = 0x0UL;
+ exclude_range[i].end = kernel_end;
+ i++;
+ /* 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, "/htab_base");
+ if ((file = fopen(fname, "r")) == NULL) {
+ perror(fname);
+ closedir(cdir);
+ closedir(dir);
+ return -1;
+ }
+ unsigned long long htab_base, htab_size;
+ 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, "/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;
+ }
+ unsigned int rtas_base, rtas_size;
+ 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++;
+ } /* 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 (memory_max > 0x40000000UL? (rmo_top = 0x40000000UL) : (rmo_top = memory_max));
+ 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++;
+ closedir(cdir);
+ } /* pci */
+ }
+ closedir(dir);
+
+ nr_exclude_ranges = i;
+
+ sort_ranges();
+#if 0
+ 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(void)
+{
+ 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();
+
+ 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;
+
+#if 0
+ int k;
+ for (k = 0; k < j; k++)
+ fprintf(stderr, "seup_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)
+{
+ setup_memory_ranges();
+ *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");
+}
+
+static struct {
+} arch_options = {
+};
+
+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;
+ }
+ }
+ /* 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, unsigned long *flags)
+{
+ 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
+ */
+ *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 2005-12-14 15:57:19.000000000 +0530
@@ -6,4 +6,17 @@ int elf_ppc64_load(int argc, char **argv
struct kexec_info *info);
void elf_ppc64_usage(void);
-#endif /* KEXEC_PPC_H */
+unsigned long initrd_base;
+unsigned long 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;
+};
+#endif /* KEXEC_PPC64_H */
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 2005-12-14 15:57:18.000000000 +0530
@@ -2,6 +2,9 @@
# 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_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 2005-12-14 16:00:40.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 2005-12-14 16:00:40.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 2005-12-14 16:00:40.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 2005-12-14 16:00:40.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 2005-12-14 16:00:40.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 2005-12-14 16:00:40.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 2005-12-15 16:57:30.415686864 +0530
@@ -0,0 +1,766 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Murali M Chakravarthy (muralim@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ * Heavily borrowed from kexec/arch/i386/crashdump-x86.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "../../crashdump.h"
+#include "kexec-x86_64.h"
+#include "crashdump-x86_64.h"
+#include <x86/x86-linux.h>
+
+extern struct arch_options_t arch_options;
+
+/* Forward Declaration. */
+static int exclude_crash_reserve_region(int *nr_ranges);
+
+/* Stores a sorted list of RAM memory ranges for which to create elf headers.
+ * A separate program header is created for backup region */
+static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
+
+/* Memory region reserved for storing panic kernel and other data. */
+static struct memory_range crash_reserved_mem;
+
+/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
+ * create Elf headers. Keeping it separate from get_memory_ranges() as
+ * requirements are different in the case of normal kexec and crashdumps.
+ *
+ * Normal kexec needs to look at all of available physical memory irrespective
+ * of the fact how much of it is being used by currently running kernel.
+ * Crashdumps need to have access to memory regions actually being used by
+ * running kernel. Expecting a different file/data structure than /proc/iomem
+ * to look into down the line. May be something like /proc/kernelmem or may
+ * be zone data structures exported from kernel.
+ */
+static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+{
+ const char iomem[]= "/proc/iomem";
+ int memory_ranges = 0;
+ char line[MAX_LINE];
+ FILE *fp;
+ unsigned long long start, end;
+
+ fp = fopen(iomem, "r");
+ if (!fp) {
+ fprintf(stderr, "Cannot open %s: %s\n",
+ iomem, strerror(errno));
+ return -1;
+ }
+
+ /* First entry is for first 640K region. Different bios report first
+ * 640K in different manner hence hardcoding it */
+ crash_memory_range[0].start = 0x00000000;
+ crash_memory_range[0].end = 0x0009ffff;
+ crash_memory_range[0].type = RANGE_RAM;
+ memory_ranges++;
+
+ while(fgets(line, sizeof(line), fp) != 0) {
+ char *str;
+ int type, consumed, count;
+ if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
+ break;
+ count = sscanf(line, "%Lx-%Lx : %n",
+ &start, &end, &consumed);
+ if (count != 2)
+ continue;
+ str = line + consumed;
+#if 0
+ printf("%016Lx-%016Lx : %s",
+ start, end, str);
+#endif
+ /* Only Dumping memory of type System RAM. */
+ if (memcmp(str, "System RAM\n", 11) == 0) {
+ type = RANGE_RAM;
+ } else if (memcmp(str, "Crash kernel\n", 13) == 0) {
+ /* Reserved memory region. New kernel can
+ * use this region to boot into. */
+ crash_reserved_mem.start = start;
+ crash_reserved_mem.end = end;
+ crash_reserved_mem.type = RANGE_RAM;
+ continue;
+ } else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
+ /*
+ * ACPI Tables area need to be passed to new
+ * kernel with appropriate memmap= option. This
+ * is needed so that x86_64 kernel creates linear
+ * mapping for this region which is required for
+ * initializing acpi tables in second kernel.
+ */
+ type = RANGE_ACPI;
+ } else {
+ continue;
+ }
+
+ /* First 640K already registered */
+ if (start >= 0x00000000 && end <= 0x0009ffff)
+ continue;
+
+ crash_memory_range[memory_ranges].start = start;
+ crash_memory_range[memory_ranges].end = end;
+ crash_memory_range[memory_ranges].type = type;
+ memory_ranges++;
+
+ /* Segregate linearly mapped region. */
+ if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) {
+ crash_memory_range[memory_ranges-1].end = MAXMEM -1;
+
+ /* Add segregated region. */
+ crash_memory_range[memory_ranges].start = MAXMEM;
+ crash_memory_range[memory_ranges].end = end;
+ crash_memory_range[memory_ranges].type = type;
+ memory_ranges++;
+ }
+ }
+ fclose(fp);
+ if (exclude_crash_reserve_region(&memory_ranges) < 0)
+ return -1;
+ *range = crash_memory_range;
+ *ranges = memory_ranges;
+#if 0
+ int i;
+ printf("CRASH MEMORY RANGES\n");
+ for(i = 0; i < memory_ranges; i++) {
+ start = crash_memory_range[i].start;
+ end = crash_memory_range[i].end;
+ printf("%016Lx-%016Lx\n", start, end);
+ }
+#endif
+ return 0;
+}
+
+/* Removes crash reserve region from list of memory chunks for whom elf program
+ * headers have to be created. Assuming crash reserve region to be a single
+ * continuous area fully contained inside one of the memory chunks */
+static int exclude_crash_reserve_region(int *nr_ranges)
+{
+ int i, j, tidx = -1;
+ unsigned long long cstart, cend;
+ struct memory_range temp_region;
+
+ /* Crash reserved region. */
+ cstart = crash_reserved_mem.start;
+ cend = crash_reserved_mem.end;
+
+ for (i = 0; i < (*nr_ranges); i++) {
+ unsigned long long mstart, mend;
+ mstart = crash_memory_range[i].start;
+ mend = crash_memory_range[i].end;
+ if (cstart < mend && cend > mstart) {
+ if (cstart != mstart && cend != mend) {
+ /* Split memory region */
+ crash_memory_range[i].end = cstart - 1;
+ temp_region.start = cend + 1;
+ temp_region.end = mend;
+ temp_region.type = RANGE_RAM;
+ tidx = i+1;
+ } else if (cstart != mstart)
+ crash_memory_range[i].end = cstart - 1;
+ else
+ crash_memory_range[i].start = cend + 1;
+ }
+ }
+ /* Insert split memory region, if any. */
+ if (tidx >= 0) {
+ if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) {
+ /* No space to insert another element. */
+ fprintf(stderr, "Error: Number of crash memory ranges"
+ " excedeed the max limit\n");
+ return -1;
+ }
+ for (j = (*nr_ranges - 1); j >= tidx; j--)
+ crash_memory_range[j+1] = crash_memory_range[j];
+ crash_memory_range[tidx].start = temp_region.start;
+ crash_memory_range[tidx].end = temp_region.end;
+ crash_memory_range[tidx].type = temp_region.type;
+ (*nr_ranges)++;
+ }
+ return 0;
+}
+
+/* Adds a segment from list of memory regions which new kernel can use to
+ * boot. Segment start and end should be aligned to 1K boundary. */
+static int add_memmap(struct memory_range *memmap_p, unsigned long long addr,
+ size_t size)
+{
+ int i, j, nr_entries = 0, tidx = 0, align = 1024;
+ unsigned long long mstart, mend;
+
+ /* Do alignment check. */
+ if ((addr%align) || (size%align))
+ return -1;
+
+ /* Make sure at least one entry in list is free. */
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (!mstart && !mend)
+ break;
+ else
+ nr_entries++;
+ }
+ if (nr_entries == CRASH_MAX_MEMMAP_NR)
+ return -1;
+
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (mstart == 0 && mend == 0)
+ break;
+ if (mstart <= (addr+size-1) && mend >=addr)
+ /* Overlapping region. */
+ return -1;
+ else if (addr > mend)
+ tidx = i+1;
+ }
+ /* Insert the memory region. */
+ for (j = nr_entries-1; j >= tidx; j--)
+ memmap_p[j+1] = memmap_p[j];
+ memmap_p[tidx].start = addr;
+ memmap_p[tidx].end = addr + size - 1;
+#if 0
+ printf("Memmap after adding segment\n");
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (mstart == 0 && mend == 0)
+ break;
+ printf("%016llx - %016llx\n",
+ mstart, mend);
+ }
+#endif
+ return 0;
+}
+
+/* Removes a segment from list of memory regions which new kernel can use to
+ * boot. Segment start and end should be aligned to 1K boundary. */
+static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr,
+ size_t size)
+{
+ int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024;
+ unsigned long long mstart, mend;
+ struct memory_range temp_region;
+
+ /* Do alignment check. */
+ if ((addr%align) || (size%align))
+ return -1;
+
+ /* Make sure at least one entry in list is free. */
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (!mstart && !mend)
+ break;
+ else
+ nr_entries++;
+ }
+ if (nr_entries == CRASH_MAX_MEMMAP_NR)
+ /* List if full */
+ return -1;
+
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (mstart == 0 && mend == 0)
+ /* Did not find the segment in the list. */
+ return -1;
+ if (mstart <= addr && mend >= (addr + size - 1)) {
+ if (mstart == addr && mend == (addr + size - 1)) {
+ /* Exact match. Delete region */
+ operation = -1;
+ tidx = i;
+ break;
+ }
+ if (mstart != addr && mend != (addr + size - 1)) {
+ /* Split in two */
+ memmap_p[i].end = addr - 1;
+ temp_region.start = addr + size;
+ temp_region.end = mend;
+ operation = 1;
+ tidx = i;
+ break;
+ }
+
+ /* No addition/deletion required. Adjust the existing.*/
+ if (mstart != addr) {
+ memmap_p[i].end = addr - 1;
+ break;
+ } else {
+ memmap_p[i].start = addr + size;
+ break;
+ }
+ }
+ }
+ if ((operation == 1) && tidx >=0) {
+ /* Insert the split memory region. */
+ for (j = nr_entries-1; j > tidx; j--)
+ memmap_p[j+1] = memmap_p[j];
+ memmap_p[tidx+1] = temp_region;
+ }
+ if ((operation == -1) && tidx >=0) {
+ /* Delete the exact match memory region. */
+ for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++)
+ memmap_p[j-1] = memmap_p[j];
+ memmap_p[j-1].start = memmap_p[j-1].end = 0;
+ }
+#if 0
+ printf("Memmap after deleting segment\n");
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ mstart = memmap_p[i].start;
+ mend = memmap_p[i].end;
+ if (mstart == 0 && mend == 0) {
+ break;
+ }
+ printf("%016llx - %016llx\n",
+ mstart, mend);
+ }
+#endif
+ return 0;
+}
+
+/* Converts unsigned long to ascii string. */
+static void ultoa(unsigned long i, char *str)
+{
+ int j = 0, k;
+ char tmp;
+
+ do {
+ str[j++] = i % 10 + '0';
+ } while ((i /=10) > 0);
+ str[j] = '\0';
+
+ /* Reverse the string. */
+ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
+ tmp = str[k];
+ str[k] = str[j];
+ str[j] = tmp;
+ }
+}
+
+/* Adds the appropriate memmap= options to command line, indicating the
+ * memory regions the new kernel can use to boot into. */
+static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p)
+{
+ int i, cmdlen, len, min_sizek = 100;
+ char str_mmap[256], str_tmp[20];
+
+ /* Exact map */
+ strcpy(str_mmap, " memmap=exactmap");
+ len = strlen(str_mmap);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str_mmap);
+
+ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) {
+ unsigned long startk, endk;
+ startk = (memmap_p[i].start/1024);
+ endk = ((memmap_p[i].end + 1)/1024);
+ if (!startk && !endk)
+ /* All regions traversed. */
+ break;
+
+ /* A region is not worth adding if region size < 100K. It eats
+ * up precious command line length. */
+ if ((endk - startk) < min_sizek)
+ continue;
+ strcpy (str_mmap, " memmap=");
+ ultoa((endk-startk), str_tmp);
+ strcat (str_mmap, str_tmp);
+ strcat (str_mmap, "K@");
+ ultoa(startk, str_tmp);
+ strcat (str_mmap, str_tmp);
+ strcat (str_mmap, "K");
+ len = strlen(str_mmap);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str_mmap);
+ }
+#if 0
+ printf("Command line after adding memmap\n");
+ printf("%s\n", cmdline);
+#endif
+ return 0;
+}
+
+/* Adds the elfcorehdr= command line parameter to command line. */
+static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr)
+{
+ int cmdlen, len, align = 1024;
+ char str[30], *ptr;
+
+ /* Passing in elfcorehdr=xxxK format. Saves space required in cmdline.
+ * Ensure 1K alignment*/
+ if (addr%align)
+ return -1;
+ addr = addr/align;
+ ptr = str;
+ strcpy(str, " elfcorehdr=");
+ ptr += strlen(str);
+ ultoa(addr, ptr);
+ strcat(str, "K");
+ len = strlen(str);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str);
+#if 0
+ printf("Command line after adding elfcorehdr\n");
+ printf("%s\n", cmdline);
+#endif
+ return 0;
+}
+
+/* Appends memmap=X#Y commandline for ACPI to command line*/
+static int cmdline_add_memmap_acpi(char *cmdline, unsigned long start,
+ unsigned long end)
+{
+ int cmdlen, len, align = 1024;
+ unsigned long startk, endk;
+ char str_mmap[256], str_tmp[20];
+
+ if (!(end - start))
+ return 0;
+
+ startk = start/1024;
+ endk = (end + align - 1)/1024;
+ strcpy (str_mmap, " memmap=");
+ ultoa((endk - startk), str_tmp);
+ strcat (str_mmap, str_tmp);
+ strcat (str_mmap, "K#");
+ ultoa(startk, str_tmp);
+ strcat (str_mmap, str_tmp);
+ strcat (str_mmap, "K");
+ len = strlen(str_mmap);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str_mmap);
+
+#if 0
+ printf("Command line after adding acpi memmap\n");
+ printf("%s\n", cmdline);
+#endif
+ return 0;
+}
+
+/* Prepares the crash memory elf64 headers and stores in supplied buffer. */
+static int prepare_crash_memory_elf64_headers(struct kexec_info *info,
+ void *buf, unsigned long size)
+{
+ Elf64_Ehdr *elf;
+ Elf64_Phdr *phdr;
+ int i;
+ char *bufp;
+ long int nr_cpus = 0;
+ uint64_t notes_addr;
+
+ bufp = (char*) buf;
+
+ /* Setup ELF Header*/
+ elf = (Elf64_Ehdr *) bufp;
+ bufp += sizeof(Elf64_Ehdr);
+ memcpy(elf->e_ident, ELFMAG, SELFMAG);
+ elf->e_ident[EI_CLASS] = ELFCLASS64;
+ elf->e_ident[EI_DATA] = ELFDATA2LSB;
+ elf->e_ident[EI_VERSION]= EV_CURRENT;
+ elf->e_ident[EI_OSABI] = ELFOSABI_NONE;
+ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+ elf->e_type = ET_CORE;
+ elf->e_machine = EM_X86_64;
+ elf->e_version = EV_CURRENT;
+ elf->e_entry = 0;
+ elf->e_phoff = sizeof(Elf64_Ehdr);
+ elf->e_shoff = 0;
+ elf->e_flags = 0;
+ elf->e_ehsize = sizeof(Elf64_Ehdr);
+ elf->e_phentsize= sizeof(Elf64_Phdr);
+ elf->e_phnum = 0;
+ elf->e_shentsize= 0;
+ elf->e_shnum = 0;
+ elf->e_shstrndx = 0;
+
+ /* PT_NOTE program headers. One per cpu*/
+ nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
+ if (nr_cpus < 0) {
+ return -1;
+ }
+
+ /* Need to find a better way to determine per cpu notes section size. */
+#define MAX_NOTE_BYTES 1024
+ for (i = 0; i < nr_cpus; i++) {
+ if (get_crash_notes_per_cpu(i, &notes_addr) < 0) {
+ /* This cpu is not present. Skip it. */
+ continue;
+ }
+
+ phdr = (Elf64_Phdr *) bufp;
+ bufp += sizeof(Elf64_Phdr);
+ phdr->p_type = PT_NOTE;
+ phdr->p_flags = 0;
+ phdr->p_offset = phdr->p_paddr = notes_addr;
+ phdr->p_vaddr = 0;
+ phdr->p_filesz = phdr->p_memsz = MAX_NOTE_BYTES;
+ /* Do we need any alignment of segments? */
+ phdr->p_align = 0;
+
+ /* Increment number of program headers. */
+ (elf->e_phnum)++;
+ }
+
+ /* Setup PT_LOAD type program header for every system RAM chunk.
+ * A seprate program header for Backup Region*/
+ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+ unsigned long long mstart, mend;
+ 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.*/
+
+ /* 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;
+}
+
+/* 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_X86_64;
+ 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_per_cpu(i, &notes_addr) < 0) {
+ /* This cpu is not present. Skip it. */
+ return -1;
+ }
+ phdr = (Elf32_Phdr *) bufp;
+ bufp += sizeof(Elf32_Phdr);
+ phdr->p_type = PT_NOTE;
+ phdr->p_flags = 0;
+ phdr->p_offset = phdr->p_paddr = notes_addr;
+ phdr->p_vaddr = 0;
+ phdr->p_filesz = phdr->p_memsz = MAX_NOTE_BYTES;
+ /* Do we need any alignment of segments? */
+ phdr->p_align = 0;
+
+ /* Increment number of program headers. */
+ (elf->e_phnum)++;
+ }
+
+ /* Setup PT_LOAD type program header for every system RAM chunk.
+ * A seprate program header for Backup Region*/
+ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
+ unsigned long long mstart, mend;
+ mstart = crash_memory_range[i].start;
+ mend = crash_memory_range[i].end;
+ if (!mstart && !mend)
+ break;
+ 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.*/
+
+ /* 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 = 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, 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;
+ }
+ 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);
+
+ /* 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 2005-12-14 16:00:44.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/include/arch/options.h kexec-tools-1.101-kdump/kexec/arch/x86_64/include/arch/options.h
--- kexec-tools-1.101/kexec/arch/x86_64/include/arch/options.h 2004-12-22 02:24:02.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/x86_64/include/arch/options.h 2005-12-14 16:00:44.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/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 2005-12-14 16:00:58.000000000 +0530
@@ -32,10 +32,12 @@
#include <elf.h>
#include <x86/x86-linux.h>
#include "../../kexec.h"
+#include "../../kexec-syscall.h"
#include "../../kexec-elf.h"
#include "../../kexec-elf-boot.h"
#include "../i386/x86-linux-setup.h"
#include "kexec-x86_64.h"
+#include "crashdump-x86_64.h"
#include <arch/options.h>
static const int probe_debug = 0;
@@ -85,7 +87,9 @@ int elf_x86_64_load(int argc, char **arg
{
struct mem_ehdr ehdr;
const char *command_line;
+ char *modified_cmdline;
int command_line_len;
+ int modified_cmdline_len;
const char *ramdisk;
unsigned long entry, max_addr;
int arg_style;
@@ -118,6 +122,8 @@ int elf_x86_64_load(int argc, char **arg
*/
arg_style = ARG_STYLE_ELF;
command_line = 0;
+ modified_cmdline = 0;
+ modified_cmdline_len = 0;
ramdisk = 0;
while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
switch(opt) {
@@ -156,6 +162,20 @@ int elf_x86_64_load(int argc, char **arg
command_line_len = strlen(command_line) +1;
}
+ /* Need to append some command line parameters internally in case of
+ * taking crash dumps.
+ */
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
+ memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
+ if (command_line) {
+ strncpy(modified_cmdline, command_line,
+ COMMAND_LINE_SIZE);
+ modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+ }
+ modified_cmdline_len = strlen(modified_cmdline);
+ }
+
/* Load the ELF executable */
elf_exec_build_load(info, &ehdr, buf, len);
@@ -197,6 +217,7 @@ int elf_x86_64_load(int argc, char **arg
const unsigned char *ramdisk_buf;
off_t ramdisk_length;
struct entry64_regs regs;
+ int rc=0;
/* Get the linux parameter header */
hdr = xmalloc(sizeof(*hdr));
@@ -210,9 +231,19 @@ int elf_x86_64_load(int argc, char **arg
/* Add a ramdisk to the current image */
ramdisk_buf = 0;
ramdisk_length = 0;
- if (ramdisk) {
- unsigned char *ramdisk_buf;
+ if (ramdisk)
ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
+
+ /* If panic kernel is being loaded, additional segments need
+ * to be created. */
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ rc = load_crashdump_segments(info, modified_cmdline,
+ max_addr, 0);
+ if (rc < 0)
+ return -1;
+ /* Use new command line. */
+ command_line = modified_cmdline;
+ command_line_len = strlen(modified_cmdline) + 1;
}
/* Tell the kernel what is going on */
@@ -222,7 +253,7 @@ int elf_x86_64_load(int argc, char **arg
ramdisk_buf, ramdisk_length);
/* Fill in the information bios calls would usually provide */
- setup_linux_system_parameters(&hdr->hdr);
+ setup_linux_system_parameters(&hdr->hdr, info->kexec_flags);
/* Initialize the registers */
elf_rel_get_symbol(&info->rhdr, "entry64_regs", &regs, sizeof(regs));
diff -urNp -X dontdiff kexec-tools-1.101/kexec/arch/x86_64/kexec-x86_64.c kexec-tools-1.101-kdump/kexec/arch/x86_64/kexec-x86_64.c
--- kexec-tools-1.101/kexec/arch/x86_64/kexec-x86_64.c 2005-02-06 04:55:01.000000000 +0530
+++ kexec-tools-1.101-kdump/kexec/arch/x86_64/kexec-x86_64.c 2005-12-15 11:55:22.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;
}
@@ -121,21 +136,25 @@ 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 {
+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)
@@ -199,6 +218,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 */
@@ -207,7 +232,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 +247,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 +259,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 +271,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 2005-12-14 16:00:44.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 2005-12-15 16:56:46.389379880 +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 2005-12-15 11:55:22.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 2005-12-14 15:57:17.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, ...)
{
@@ -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.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 2005-12-15 11:55:22.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 2005-12-15 11:09:09.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 2005-12-15 11:55:22.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 2005-12-14 16:00:56.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 2005-12-14 15:57:15.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 2005-12-14 15:57:15.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 2005-12-14 15:57:15.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 2005-12-14 15:57:15.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 2005-12-14 15:57:15.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/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 2005-12-14 15:57:19.000000000 +0530
@@ -3,5 +3,5 @@
#
PURGATORY_C_SRCS+=
-PURGATORY_S_SRCS+=
+PURGATORY_S_SRCS+= purgatory/arch/ppc64/v2wrap.S
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 2005-12-14 15:57:19.000000000 +0530
@@ -0,0 +1,114 @@
+#
+# kexec: Linux boots Linux
+#
+# Copyright (C) 2004 - 2005, Milton D Miller II, 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 place in front of a v2 device tree
+# to call a 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 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.
+
+
+# look a bit like a Linux kernel here ...
+ .machine ppc64
+ .org 0
+start: b master
+ tweq 0,0
+secondary_hold:
+ .llong 0
+
+ .org 0x20 # need a bit more space than after slave,
+master:
+ std 4,secondary_hold@l(0) # bring slaves up here to this copy
+ sync # try to get the slaves to see this
+ or 1,1,1 # low priority to let other thread catchup
+ isync
+ mr 5,3 # save cpu id to r5
+ addi 3,4,0x100 # r3 = boot param block
+ lwz 6,20(3) # fetch version number
+ cmpwi 0,6,2 # v2 ?
+ blt 80f
+ stw 5,28(3) # save my cpu number as boot_cpu_phys
+80: b 81f
+
+ .org 0x60 # ABI: slaves start at 60 with r3=phys
+slave: ld 4,secondary_hold@l(0);
+ cmpdi 0,4,0
+ beq slave
+
+ # ahh, master told us where he is running from
+ # jump into our copy of the code up there so this code can change
+ addi 5,4,1f-start
+ mtctr 5
+ bctr
+
+ # ok, now wait for the master to tell is to go back to the new block
+1: ld 5,copied@l(4)
+ cmpdi 0,5,0
+ beq 1b
+ ba 0x60
+
+
+
+ .long 0 # just an eye-catcher, delete if space needed
+ .long 0 # just an eye-catcher, delete if space needed
+
+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
+
+ ld 4,-8(3) # kernel pointer is at -8(bb) by loader
+ 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
+ std 6,-16(3) # send slaves back down
+ bctr # start kernel
+
+ .org 0xf0
+copied: .llong 0
+kernel: .llong 0
+ .org 0x100
+__end_stub:
+ .equ boot_block, . - start
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 2005-12-14 16:00:40.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 2005-12-14 16:00:40.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 2005-12-14 16:00:40.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 2005-12-14 16:00:56.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 2005-12-14 16:00:56.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 2005-12-14 15:57:15.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 2005-12-14 15:57:19.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 \
@@ -17,9 +22,11 @@ PCFLAGS += $(call cc-option, -fnostdinc)
PCFLAGS += $(call cc-option, -fno-zero-initialized-in-bss)
PURGATORY_C_SRCS:=
+ifneq ($(ARCH),ppc64)
PURGATORY_C_SRCS += purgatory/purgatory.c
PURGATORY_C_SRCS += purgatory/printf.c
PURGATORY_C_SRCS += purgatory/string.c
+endif
PURGATORY_S_OBJS:=
include purgatory/arch/$(ARCH)/Makefile
@@ -54,7 +61,12 @@ $(PURGATORY_S_OBJS): $(OBJDIR)/%.o: %.S
$(PURGATORY): $(PURGATORY_OBJS) $(UTIL_LIB)
$(MKDIR) -p $(@D)
+ifneq ($(ARCH),ppc64)
$(LD) $(LDFLAGS) --no-undefined -e purgatory_start -r -o $@ $(PURGATORY_OBJS) $(UTIL_LIB)
+else
+ $(LD) -Ttext=0 -e 0 -o $(OBJDIR)/purgatory/v2wrap.elf $(PURGATORY_OBJS)
+ objcopy -O binary $(OBJDIR)/purgatory/v2wrap.elf $@
+endif
echo::
@echo "PURGATORY_C_SRCS $(PURGATORY_C_SRCS)"
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 2005-12-14 15:57:15.000000000 +0530
@@ -44,4 +44,5 @@ void purgatory(void)
printf("I'm in purgatory\n");
setup_arch();
verify_sha256_digest();
+ post_verification_setup_arch();
}