diff --git a/kexec-tools-1.101-kdump.patch b/kexec-tools-1.101-kdump.patch index 70386b5..ced9cf5 100644 --- a/kexec-tools-1.101-kdump.patch +++ b/kexec-tools-1.101-kdump.patch @@ -1,7 +1,41 @@ -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/crashdump-x86.c ---- kexec-tools-1.101-orig/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-08-24 15:46:08.636240824 +0530 -@@ -0,0 +1,723 @@ +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 + * @@ -27,15 +61,17 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.c kexec-tools-1. +#include +#include +#include ++#include ++#include ++#include +#include "../../kexec.h" +#include "../../kexec-elf.h" +#include "../../kexec-syscall.h" ++#include "../../crashdump.h" +#include "kexec-x86.h" +#include "crashdump-x86.h" +#include + -+#define MAX_LINE 160 -+ +extern struct arch_options_t arch_options; + +/* Forward Declaration. */ @@ -430,33 +466,36 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.c kexec-tools-1. + return 0; +} + -+/* Returns the virtual address of start of crash notes section. */ -+static int get_crash_notes_section_addr(unsigned long *addr) ++ ++/* ++ * 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) +{ -+ const char crash_notes[]= "/sys/kernel/crash_notes"; ++ 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) { -+ fprintf(stderr, "Cannot open %s: %s\n", -+ crash_notes, strerror(errno)); -+ fprintf(stderr, "Try mounting sysfs\n"); -+ return -1; -+ } -+ -+ if (fgets(line, sizeof(line), fp) != 0) { -+ int count; -+ count = sscanf(line, "%lx", addr); -+ if (count != 1) { -+ *addr = 0; -+ return -1; ++ 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); ++ printf("crash_notes addr = %Lx\n", *addr); +#endif -+ } -+ return 0; ++ return 0; ++ } else ++ return get_crash_notes_per_cpu(cpu, addr); +} + +/* Prepares the crash memory elf64 headers and stores in supplied buffer. */ @@ -468,7 +507,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.c kexec-tools-1. + int i; + char *bufp; + long int nr_cpus = 0; -+ unsigned long notes_addr, notes_offset; ++ uint64_t notes_addr; + + bufp = (char*) buf; + @@ -501,23 +540,20 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.c kexec-tools-1. + return -1; + } + -+ /* Need to find a better way to determine per cpu notes section size. */ -+#define MAX_NOTE_BYTES 1024 -+ if (get_crash_notes_section_addr (¬es_addr) < 0) { -+ return -1; -+ } -+ notes_offset = __pa(notes_addr); + for (i = 0; i < nr_cpus; i++) { ++ if (get_crash_notes(i, ¬es_addr) < 0) { ++ /* This cpu is not present. Skip it. */ ++ continue; ++ } + phdr = (Elf64_Phdr *) bufp; + bufp += sizeof(Elf64_Phdr); + phdr->p_type = PT_NOTE; + phdr->p_flags = 0; -+ phdr->p_offset = notes_offset; -+ phdr->p_vaddr = phdr->p_paddr = notes_offset; ++ 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; -+ notes_offset += MAX_NOTE_BYTES; + + /* Increment number of program headers. */ + (elf->e_phnum)++; @@ -564,7 +600,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.c kexec-tools-1. + int i; + char *bufp; + long int nr_cpus = 0; -+ unsigned long notes_addr, notes_offset; ++ uint64_t notes_addr; + + bufp = (char*) buf; + @@ -599,21 +635,20 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.c kexec-tools-1. + + /* Need to find a better way to determine per cpu notes section size. */ +#define MAX_NOTE_BYTES 1024 -+ if (get_crash_notes_section_addr (¬es_addr) < 0) { -+ return -1; -+ } -+ notes_offset = __pa(notes_addr); + for (i = 0; i < nr_cpus; i++) { ++ if (get_crash_notes(i, ¬es_addr) < 0) { ++ /* This cpu is not present. Skip it. */ ++ return -1; ++ } + phdr = (Elf32_Phdr *) bufp; + bufp += sizeof(Elf32_Phdr); + phdr->p_type = PT_NOTE; + phdr->p_flags = 0; -+ phdr->p_offset = notes_offset; -+ phdr->p_vaddr = phdr->p_paddr = notes_offset; ++ 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; -+ notes_offset += MAX_NOTE_BYTES; + + /* Increment number of program headers. */ + (elf->e_phnum)++; @@ -725,9 +760,9 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.c kexec-tools-1. + cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr); + return 0; +} -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.h kexec-tools-1.101-kdump/kexec/arch/i386/crashdump-x86.h ---- kexec-tools-1.101-orig/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-08-24 15:45:43.461068032 +0530 +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 @@ -750,15 +785,17 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/crashdump-x86.h kexec-tools-1. +#define BACKUP_SIZE (BACKUP_END - BACKUP_START + 1) + +#endif /* CRASHDUMP_X86_H */ -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/include/arch/options.h kexec-tools-1.101-kdump/kexec/arch/i386/include/arch/options.h ---- kexec-tools-1.101-orig/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-08-24 15:45:35.249316408 +0530 -@@ -7,6 +7,8 @@ +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+6) -+#define OPT_ELF64_CORE (OPT_MAX+7) +-#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 \ @@ -771,9 +808,9 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/include/arch/options.h kexec-t #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-bzImage.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-bzImage.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.197388464 +0530 +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. */ @@ -783,9 +820,9 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-bzImage.c kexec-tools-1. } return 0; -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-elf-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-elf-x86.c ---- kexec-tools-1.101-orig/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-08-24 15:46:03.167072264 +0530 +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 #include @@ -892,9 +929,9 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-elf-x86.c kexec-tools-1. /* Initialize the registers */ elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs)); -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-multiboot-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-multiboot-x86.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.014416280 +0530 +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; @@ -905,10 +942,10 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-multiboot-x86.c kexec-to fprintf(stderr, "Cannot get memory information\n"); return -1; } -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101-kdump/kexec/arch/i386/kexec-x86.c ---- kexec-tools-1.101-orig/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-08-24 15:45:35.223320360 +0530 -@@ -30,14 +30,16 @@ +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" @@ -916,8 +953,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- #include -#define MAX_MEMORY_RANGES 64 - #define MAX_LINE 160 -+ +-#define MAX_LINE 160 static struct memory_range memory_range[MAX_MEMORY_RANGES]; /* Return a sorted list of memory ranges. */ @@ -927,7 +963,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- { const char iomem[]= "/proc/iomem"; int memory_ranges = 0; -@@ -79,6 +81,20 @@ int get_memory_ranges(struct memory_rang +@@ -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; } @@ -948,7 +984,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- else { continue; } -@@ -120,21 +136,18 @@ void arch_usage(void) +@@ -120,21 +134,18 @@ void arch_usage(void) " --serial-baud= Specify the serial port baud rate\n" " --console-vga Enable the vga console\n" " --console-serial Enable the serial console\n" @@ -974,7 +1010,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- }; int arch_process_options(int argc, char **argv) -@@ -198,6 +211,12 @@ int arch_process_options(int argc, char +@@ -198,6 +209,12 @@ int arch_process_options(int argc, char } arch_options.serial_baud = value; break; @@ -987,7 +1023,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- } } /* Reset getopt for the next pass; called in other source modules */ -@@ -206,7 +225,7 @@ int arch_process_options(int argc, char +@@ -206,7 +223,7 @@ int arch_process_options(int argc, char return 0; } @@ -996,7 +1032,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- { int result; struct utsname utsname; -@@ -224,11 +243,11 @@ int arch_compat_trampoline(struct kexec_ +@@ -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. */ @@ -1010,7 +1046,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- if (!info->rhdr.e_shdr) { fprintf(stderr, "A trampoline is required for cross architecture support\n"); -@@ -249,6 +268,8 @@ int arch_compat_trampoline(struct kexec_ +@@ -249,6 +266,8 @@ int arch_compat_trampoline(struct kexec_ void arch_update_purgatory(struct kexec_info *info) { @@ -1019,7 +1055,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- 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 +280,11 @@ void arch_update_purgatory(struct kexec_ +@@ -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)); @@ -1031,9 +1067,9 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.c kexec-tools-1.101- + elf_rel_set_symbol(&info->rhdr, "panic_kernel", + &panic_kernel, sizeof(panic_kernel)); } -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.h kexec-tools-1.101-kdump/kexec/arch/i386/kexec-x86.h ---- kexec-tools-1.101-orig/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-08-24 15:45:35.247316712 +0530 +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 @@ -1061,17 +1097,17 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/kexec-x86.h kexec-tools-1.101- 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 -Nurp kexec-tools-1.101-orig/kexec/arch/i386/Makefile kexec-tools-1.101-kdump/kexec/arch/i386/Makefile ---- kexec-tools-1.101-orig/kexec/arch/i386/Makefile 2005-02-06 04:53:58.000000000 +0530 -+++ kexec-tools-1.101-kdump/kexec/arch/i386/Makefile 2005-08-24 15:45:35.248316560 +0530 +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 -Nurp kexec-tools-1.101-orig/kexec/arch/i386/x86-linux-setup.c kexec-tools-1.101-kdump/kexec/arch/i386/x86-linux-setup.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.039412480 +0530 +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'; } @@ -1091,9 +1127,9 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/x86-linux-setup.c kexec-tools- die("Cannot get memory information\n"); } if (ranges > E820MAX) { -diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/x86-linux-setup.h kexec-tools-1.101-kdump/kexec/arch/i386/x86-linux-setup.h ---- kexec-tools-1.101-orig/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-08-24 15:45:28.172392264 +0530 +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, @@ -1104,10 +1140,14 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/i386/x86-linux-setup.h kexec-tools- #define SETUP_BASE 0x90000 -diff -Nurp kexec-tools-1.101-orig/kexec/arch/ia64/kexec-ia64.c kexec-tools-1.101-kdump/kexec/arch/ia64/kexec-ia64.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.040412328 +0530 -@@ -38,7 +38,8 @@ +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 + + #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. */ @@ -1117,7 +1157,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/ia64/kexec-ia64.c kexec-tools-1.101 { int memory_ranges; /* -@@ -103,7 +104,7 @@ int arch_process_options(int argc, char +@@ -103,7 +103,7 @@ int arch_process_options(int argc, char return 0; } @@ -1126,7 +1166,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/ia64/kexec-ia64.c kexec-tools-1.101 { int result; struct utsname utsname; -@@ -115,7 +116,7 @@ int arch_compat_trampoline(struct kexec_ +@@ -115,7 +115,7 @@ int arch_compat_trampoline(struct kexec_ } if (strcmp(utsname.machine, "ia64") == 0) { @@ -1135,7 +1175,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/ia64/kexec-ia64.c kexec-tools-1.101 } else { fprintf(stderr, "Unsupported machine type: %s\n", -@@ -125,7 +126,7 @@ int arch_compat_trampoline(struct kexec_ +@@ -125,7 +125,7 @@ int arch_compat_trampoline(struct kexec_ return 0; } @@ -1144,7 +1184,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/ia64/kexec-ia64.c kexec-tools-1.101 { int result; struct utsname utsname; -@@ -140,7 +141,7 @@ int arch_compat_trampoline(struct kexec_ +@@ -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. */ @@ -1153,10 +1193,14 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/ia64/kexec-ia64.c kexec-tools-1.101 } else { fprintf(stderr, "Unsupported machine type: %s\n", -diff -Nurp kexec-tools-1.101-orig/kexec/arch/ppc/kexec-ppc.c kexec-tools-1.101-kdump/kexec/arch/ppc/kexec-ppc.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.066408376 +0530 -@@ -23,7 +23,8 @@ +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 + + #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. */ @@ -1166,7 +1210,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/ppc/kexec-ppc.c kexec-tools-1.101-k { int memory_ranges = 0; #ifdef CONFIG_GAMECUBE -@@ -120,7 +121,7 @@ int arch_process_options(int argc, char +@@ -120,7 +120,7 @@ int arch_process_options(int argc, char return 0; } @@ -1175,7 +1219,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/ppc/kexec-ppc.c kexec-tools-1.101-k { int result; struct utsname utsname; -@@ -135,7 +136,7 @@ int arch_compat_trampoline(struct kexec_ +@@ -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. */ @@ -1184,10 +1228,2481 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/ppc/kexec-ppc.c kexec-tools-1.101-k } else { fprintf(stderr, "Unsupported machine type: %s\n", -diff -Nurp kexec-tools-1.101-orig/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-orig/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-08-24 15:46:08.634241128 +0530 -@@ -222,7 +222,7 @@ int elf_x86_64_load(int argc, char **arg +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 ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 + + #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, ¶m, &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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../kexec.h" ++#include "../../kexec-syscall.h" ++#include "kexec-ppc64.h" ++#include ++ ++#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= 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 ++ * ++ */ ++ ++#include ++#include ++#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 ++ * Heiko Carstens ++ * ++ */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++ * ++ */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../kexec.h" ++#include "../../kexec-syscall.h" ++#include "kexec-s390.h" ++#include ++ ++#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 ++ * ++ */ ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++ ++extern struct arch_options_t arch_options; ++ ++/* Forward Declaration. */ ++static int exclude_crash_reserve_region(int *nr_ranges); ++ ++/* Stores a sorted list of RAM memory ranges for which to create elf headers. ++ * A separate program header is created for backup region */ ++static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES]; ++ ++/* Memory region reserved for storing panic kernel and other data. */ ++static struct memory_range crash_reserved_mem; ++ ++/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to ++ * create Elf headers. Keeping it separate from get_memory_ranges() as ++ * requirements are different in the case of normal kexec and crashdumps. ++ * ++ * Normal kexec needs to look at all of available physical memory irrespective ++ * of the fact how much of it is being used by currently running kernel. ++ * Crashdumps need to have access to memory regions actually being used by ++ * running kernel. Expecting a different file/data structure than /proc/iomem ++ * to look into down the line. May be something like /proc/kernelmem or may ++ * be zone data structures exported from kernel. ++ */ ++static int get_crash_memory_ranges(struct memory_range **range, int *ranges) ++{ ++ const char iomem[]= "/proc/iomem"; ++ int memory_ranges = 0; ++ char line[MAX_LINE]; ++ FILE *fp; ++ unsigned long long start, end; ++ ++ fp = fopen(iomem, "r"); ++ if (!fp) { ++ fprintf(stderr, "Cannot open %s: %s\n", ++ iomem, strerror(errno)); ++ return -1; ++ } ++ ++ /* First entry is for first 640K region. Different bios report first ++ * 640K in different manner hence hardcoding it */ ++ crash_memory_range[0].start = 0x00000000; ++ crash_memory_range[0].end = 0x0009ffff; ++ crash_memory_range[0].type = RANGE_RAM; ++ memory_ranges++; ++ ++ while(fgets(line, sizeof(line), fp) != 0) { ++ char *str; ++ int type, consumed, count; ++ if (memory_ranges >= CRASH_MAX_MEMORY_RANGES) ++ break; ++ count = sscanf(line, "%Lx-%Lx : %n", ++ &start, &end, &consumed); ++ if (count != 2) ++ continue; ++ str = line + consumed; ++#if 0 ++ printf("%016Lx-%016Lx : %s", ++ start, end, str); ++#endif ++ /* Only Dumping memory of type System RAM. */ ++ if (memcmp(str, "System RAM\n", 11) == 0) { ++ type = RANGE_RAM; ++ } else if (memcmp(str, "Crash kernel\n", 13) == 0) { ++ /* Reserved memory region. New kernel can ++ * use this region to boot into. */ ++ crash_reserved_mem.start = start; ++ crash_reserved_mem.end = end; ++ crash_reserved_mem.type = RANGE_RAM; ++ continue; ++ } else if (memcmp(str, "ACPI Tables\n", 12) == 0) { ++ /* ++ * ACPI Tables area need to be passed to new ++ * kernel with appropriate memmap= option. This ++ * is needed so that x86_64 kernel creates linear ++ * mapping for this region which is required for ++ * initializing acpi tables in second kernel. ++ */ ++ type = RANGE_ACPI; ++ } else { ++ continue; ++ } ++ ++ /* First 640K already registered */ ++ if (start >= 0x00000000 && end <= 0x0009ffff) ++ continue; ++ ++ crash_memory_range[memory_ranges].start = start; ++ crash_memory_range[memory_ranges].end = end; ++ crash_memory_range[memory_ranges].type = type; ++ memory_ranges++; ++ ++ /* Segregate linearly mapped region. */ ++ if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) { ++ crash_memory_range[memory_ranges-1].end = MAXMEM -1; ++ ++ /* Add segregated region. */ ++ crash_memory_range[memory_ranges].start = MAXMEM; ++ crash_memory_range[memory_ranges].end = end; ++ crash_memory_range[memory_ranges].type = type; ++ memory_ranges++; ++ } ++ } ++ fclose(fp); ++ if (exclude_crash_reserve_region(&memory_ranges) < 0) ++ return -1; ++ *range = crash_memory_range; ++ *ranges = memory_ranges; ++#if 0 ++ int i; ++ printf("CRASH MEMORY RANGES\n"); ++ for(i = 0; i < memory_ranges; i++) { ++ start = crash_memory_range[i].start; ++ end = crash_memory_range[i].end; ++ printf("%016Lx-%016Lx\n", start, end); ++ } ++#endif ++ return 0; ++} ++ ++/* Removes crash reserve region from list of memory chunks for whom elf program ++ * headers have to be created. Assuming crash reserve region to be a single ++ * continuous area fully contained inside one of the memory chunks */ ++static int exclude_crash_reserve_region(int *nr_ranges) ++{ ++ int i, j, tidx = -1; ++ unsigned long long cstart, cend; ++ struct memory_range temp_region; ++ ++ /* Crash reserved region. */ ++ cstart = crash_reserved_mem.start; ++ cend = crash_reserved_mem.end; ++ ++ for (i = 0; i < (*nr_ranges); i++) { ++ unsigned long long mstart, mend; ++ mstart = crash_memory_range[i].start; ++ mend = crash_memory_range[i].end; ++ if (cstart < mend && cend > mstart) { ++ if (cstart != mstart && cend != mend) { ++ /* Split memory region */ ++ crash_memory_range[i].end = cstart - 1; ++ temp_region.start = cend + 1; ++ temp_region.end = mend; ++ temp_region.type = RANGE_RAM; ++ tidx = i+1; ++ } else if (cstart != mstart) ++ crash_memory_range[i].end = cstart - 1; ++ else ++ crash_memory_range[i].start = cend + 1; ++ } ++ } ++ /* Insert split memory region, if any. */ ++ if (tidx >= 0) { ++ if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) { ++ /* No space to insert another element. */ ++ fprintf(stderr, "Error: Number of crash memory ranges" ++ " excedeed the max limit\n"); ++ return -1; ++ } ++ for (j = (*nr_ranges - 1); j >= tidx; j--) ++ crash_memory_range[j+1] = crash_memory_range[j]; ++ crash_memory_range[tidx].start = temp_region.start; ++ crash_memory_range[tidx].end = temp_region.end; ++ crash_memory_range[tidx].type = temp_region.type; ++ (*nr_ranges)++; ++ } ++ return 0; ++} ++ ++/* Adds a segment from list of memory regions which new kernel can use to ++ * boot. Segment start and end should be aligned to 1K boundary. */ ++static int add_memmap(struct memory_range *memmap_p, unsigned long long addr, ++ size_t size) ++{ ++ int i, j, nr_entries = 0, tidx = 0, align = 1024; ++ unsigned long long mstart, mend; ++ ++ /* Do alignment check. */ ++ if ((addr%align) || (size%align)) ++ return -1; ++ ++ /* Make sure at least one entry in list is free. */ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (!mstart && !mend) ++ break; ++ else ++ nr_entries++; ++ } ++ if (nr_entries == CRASH_MAX_MEMMAP_NR) ++ return -1; ++ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (mstart == 0 && mend == 0) ++ break; ++ if (mstart <= (addr+size-1) && mend >=addr) ++ /* Overlapping region. */ ++ return -1; ++ else if (addr > mend) ++ tidx = i+1; ++ } ++ /* Insert the memory region. */ ++ for (j = nr_entries-1; j >= tidx; j--) ++ memmap_p[j+1] = memmap_p[j]; ++ memmap_p[tidx].start = addr; ++ memmap_p[tidx].end = addr + size - 1; ++#if 0 ++ printf("Memmap after adding segment\n"); ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (mstart == 0 && mend == 0) ++ break; ++ printf("%016llx - %016llx\n", ++ mstart, mend); ++ } ++#endif ++ return 0; ++} ++ ++/* Removes a segment from list of memory regions which new kernel can use to ++ * boot. Segment start and end should be aligned to 1K boundary. */ ++static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr, ++ size_t size) ++{ ++ int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024; ++ unsigned long long mstart, mend; ++ struct memory_range temp_region; ++ ++ /* Do alignment check. */ ++ if ((addr%align) || (size%align)) ++ return -1; ++ ++ /* Make sure at least one entry in list is free. */ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (!mstart && !mend) ++ break; ++ else ++ nr_entries++; ++ } ++ if (nr_entries == CRASH_MAX_MEMMAP_NR) ++ /* List if full */ ++ return -1; ++ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (mstart == 0 && mend == 0) ++ /* Did not find the segment in the list. */ ++ return -1; ++ if (mstart <= addr && mend >= (addr + size - 1)) { ++ if (mstart == addr && mend == (addr + size - 1)) { ++ /* Exact match. Delete region */ ++ operation = -1; ++ tidx = i; ++ break; ++ } ++ if (mstart != addr && mend != (addr + size - 1)) { ++ /* Split in two */ ++ memmap_p[i].end = addr - 1; ++ temp_region.start = addr + size; ++ temp_region.end = mend; ++ operation = 1; ++ tidx = i; ++ break; ++ } ++ ++ /* No addition/deletion required. Adjust the existing.*/ ++ if (mstart != addr) { ++ memmap_p[i].end = addr - 1; ++ break; ++ } else { ++ memmap_p[i].start = addr + size; ++ break; ++ } ++ } ++ } ++ if ((operation == 1) && tidx >=0) { ++ /* Insert the split memory region. */ ++ for (j = nr_entries-1; j > tidx; j--) ++ memmap_p[j+1] = memmap_p[j]; ++ memmap_p[tidx+1] = temp_region; ++ } ++ if ((operation == -1) && tidx >=0) { ++ /* Delete the exact match memory region. */ ++ for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++) ++ memmap_p[j-1] = memmap_p[j]; ++ memmap_p[j-1].start = memmap_p[j-1].end = 0; ++ } ++#if 0 ++ printf("Memmap after deleting segment\n"); ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (mstart == 0 && mend == 0) { ++ break; ++ } ++ printf("%016llx - %016llx\n", ++ mstart, mend); ++ } ++#endif ++ return 0; ++} ++ ++/* Converts unsigned long to ascii string. */ ++static void ultoa(unsigned long i, char *str) ++{ ++ int j = 0, k; ++ char tmp; ++ ++ do { ++ str[j++] = i % 10 + '0'; ++ } while ((i /=10) > 0); ++ str[j] = '\0'; ++ ++ /* Reverse the string. */ ++ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { ++ tmp = str[k]; ++ str[k] = str[j]; ++ str[j] = tmp; ++ } ++} ++ ++/* Adds the appropriate memmap= options to command line, indicating the ++ * memory regions the new kernel can use to boot into. */ ++static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p) ++{ ++ int i, cmdlen, len, min_sizek = 100; ++ char str_mmap[256], str_tmp[20]; ++ ++ /* Exact map */ ++ strcpy(str_mmap, " memmap=exactmap"); ++ len = strlen(str_mmap); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str_mmap); ++ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ unsigned long startk, endk; ++ startk = (memmap_p[i].start/1024); ++ endk = ((memmap_p[i].end + 1)/1024); ++ if (!startk && !endk) ++ /* All regions traversed. */ ++ break; ++ ++ /* A region is not worth adding if region size < 100K. It eats ++ * up precious command line length. */ ++ if ((endk - startk) < min_sizek) ++ continue; ++ strcpy (str_mmap, " memmap="); ++ ultoa((endk-startk), str_tmp); ++ strcat (str_mmap, str_tmp); ++ strcat (str_mmap, "K@"); ++ ultoa(startk, str_tmp); ++ strcat (str_mmap, str_tmp); ++ strcat (str_mmap, "K"); ++ len = strlen(str_mmap); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str_mmap); ++ } ++#if 0 ++ printf("Command line after adding memmap\n"); ++ printf("%s\n", cmdline); ++#endif ++ return 0; ++} ++ ++/* Adds the elfcorehdr= command line parameter to command line. */ ++static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr) ++{ ++ int cmdlen, len, align = 1024; ++ char str[30], *ptr; ++ ++ /* Passing in elfcorehdr=xxxK format. Saves space required in cmdline. ++ * Ensure 1K alignment*/ ++ if (addr%align) ++ return -1; ++ addr = addr/align; ++ ptr = str; ++ strcpy(str, " elfcorehdr="); ++ ptr += strlen(str); ++ ultoa(addr, ptr); ++ strcat(str, "K"); ++ len = strlen(str); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str); ++#if 0 ++ printf("Command line after adding elfcorehdr\n"); ++ printf("%s\n", cmdline); ++#endif ++ return 0; ++} ++ ++/* Appends memmap=X#Y commandline for ACPI to command line*/ ++static int cmdline_add_memmap_acpi(char *cmdline, unsigned long start, ++ unsigned long end) ++{ ++ int cmdlen, len, align = 1024; ++ unsigned long startk, endk; ++ char str_mmap[256], str_tmp[20]; ++ ++ if (!(end - start)) ++ return 0; ++ ++ startk = start/1024; ++ endk = (end + align - 1)/1024; ++ strcpy (str_mmap, " memmap="); ++ ultoa((endk - startk), str_tmp); ++ strcat (str_mmap, str_tmp); ++ strcat (str_mmap, "K#"); ++ ultoa(startk, str_tmp); ++ strcat (str_mmap, str_tmp); ++ strcat (str_mmap, "K"); ++ len = strlen(str_mmap); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str_mmap); ++ ++#if 0 ++ printf("Command line after adding acpi memmap\n"); ++ printf("%s\n", cmdline); ++#endif ++ return 0; ++} ++ ++/* Prepares the crash memory elf64 headers and stores in supplied buffer. */ ++static int prepare_crash_memory_elf64_headers(struct kexec_info *info, ++ void *buf, unsigned long size) ++{ ++ Elf64_Ehdr *elf; ++ Elf64_Phdr *phdr; ++ int i; ++ char *bufp; ++ long int nr_cpus = 0; ++ uint64_t notes_addr; ++ ++ bufp = (char*) buf; ++ ++ /* Setup ELF Header*/ ++ elf = (Elf64_Ehdr *) bufp; ++ bufp += sizeof(Elf64_Ehdr); ++ memcpy(elf->e_ident, ELFMAG, SELFMAG); ++ elf->e_ident[EI_CLASS] = ELFCLASS64; ++ elf->e_ident[EI_DATA] = ELFDATA2LSB; ++ elf->e_ident[EI_VERSION]= EV_CURRENT; ++ elf->e_ident[EI_OSABI] = ELFOSABI_NONE; ++ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); ++ elf->e_type = ET_CORE; ++ elf->e_machine = EM_X86_64; ++ elf->e_version = EV_CURRENT; ++ elf->e_entry = 0; ++ elf->e_phoff = sizeof(Elf64_Ehdr); ++ elf->e_shoff = 0; ++ elf->e_flags = 0; ++ elf->e_ehsize = sizeof(Elf64_Ehdr); ++ elf->e_phentsize= sizeof(Elf64_Phdr); ++ elf->e_phnum = 0; ++ elf->e_shentsize= 0; ++ elf->e_shnum = 0; ++ elf->e_shstrndx = 0; ++ ++ /* PT_NOTE program headers. One per cpu*/ ++ nr_cpus = sysconf(_SC_NPROCESSORS_CONF); ++ if (nr_cpus < 0) { ++ return -1; ++ } ++ ++ /* Need to find a better way to determine per cpu notes section size. */ ++#define MAX_NOTE_BYTES 1024 ++ for (i = 0; i < nr_cpus; i++) { ++ if (get_crash_notes_per_cpu(i, ¬es_addr) < 0) { ++ /* This cpu is not present. Skip it. */ ++ continue; ++ } ++ ++ phdr = (Elf64_Phdr *) bufp; ++ bufp += sizeof(Elf64_Phdr); ++ phdr->p_type = PT_NOTE; ++ phdr->p_flags = 0; ++ phdr->p_offset = phdr->p_paddr = notes_addr; ++ phdr->p_vaddr = 0; ++ phdr->p_filesz = phdr->p_memsz = MAX_NOTE_BYTES; ++ /* Do we need any alignment of segments? */ ++ phdr->p_align = 0; ++ ++ /* Increment number of program headers. */ ++ (elf->e_phnum)++; ++ } ++ ++ /* Setup PT_LOAD type program header for every system RAM chunk. ++ * A seprate program header for Backup Region*/ ++ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) { ++ unsigned long long mstart, mend; ++ 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, ¬es_addr) < 0) { ++ /* This cpu is not present. Skip it. */ ++ return -1; ++ } ++ phdr = (Elf32_Phdr *) bufp; ++ bufp += sizeof(Elf32_Phdr); ++ phdr->p_type = PT_NOTE; ++ phdr->p_flags = 0; ++ phdr->p_offset = phdr->p_paddr = notes_addr; ++ phdr->p_vaddr = 0; ++ phdr->p_filesz = phdr->p_memsz = MAX_NOTE_BYTES; ++ /* Do we need any alignment of segments? */ ++ phdr->p_align = 0; ++ ++ /* Increment number of program headers. */ ++ (elf->e_phnum)++; ++ } ++ ++ /* Setup PT_LOAD type program header for every system RAM chunk. ++ * A seprate program header for Backup Region*/ ++ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) { ++ unsigned long long mstart, mend; ++ 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 + #include + #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 + + 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 */ @@ -1196,10 +3711,18 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/x86_64/kexec-elf-x86_64.c kexec-too /* Initialize the registers */ elf_rel_get_symbol(&info->rhdr, "entry64_regs", ®s, sizeof(regs)); -diff -Nurp kexec-tools-1.101-orig/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-orig/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-08-24 15:46:08.635240976 +0530 -@@ -37,7 +37,8 @@ +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 + + #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. */ @@ -1209,7 +3732,33 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/x86_64/kexec-x86_64.c kexec-tools-1 { const char iomem[]= "/proc/iomem"; int memory_ranges = 0; -@@ -124,7 +125,7 @@ void arch_usage(void) +@@ -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= 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" ); } @@ -1218,7 +3767,33 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/x86_64/kexec-x86_64.c kexec-tools-1 uint8_t reset_vga; uint16_t serial_base; uint32_t serial_baud; -@@ -207,7 +208,7 @@ int arch_process_options(int argc, char + 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; } @@ -1227,7 +3802,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/x86_64/kexec-x86_64.c kexec-tools-1 { int result; struct utsname utsname; -@@ -222,7 +223,7 @@ int arch_compat_trampoline(struct kexec_ +@@ -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. */ @@ -1236,20 +3811,124 @@ diff -Nurp kexec-tools-1.101-orig/kexec/arch/x86_64/kexec-x86_64.c kexec-tools-1 } else { fprintf(stderr, "Unsupported machine type: %s\n", -diff -Nurp kexec-tools-1.101-orig/kexec/arch/x86_64/Makefile kexec-tools-1.101-kdump/kexec/arch/x86_64/Makefile ---- kexec-tools-1.101-orig/kexec/arch/x86_64/Makefile 2005-02-06 04:55:19.000000000 +0530 -+++ kexec-tools-1.101-kdump/kexec/arch/x86_64/Makefile 2005-08-24 15:46:08.634241128 +0530 -@@ -1,6 +1,7 @@ - # - # kexec x86_64 (linux booting linux) - # -+KEXEC_C_SRCS+= kexec/arch/i386/crashdump-x86.c - KEXEC_C_SRCS+= kexec/arch/i386/kexec-elf-x86.c - KEXEC_C_SRCS+= kexec/arch/i386/kexec-bzImage.c - KEXEC_C_SRCS+= kexec/arch/i386/kexec-multiboot-x86.c -diff -Nurp kexec-tools-1.101-orig/kexec/kexec.c kexec-tools-1.101-kdump/kexec/kexec.c ---- kexec-tools-1.101-orig/kexec/kexec.c 2005-01-13 18:54:29.000000000 +0530 -+++ kexec-tools-1.101-kdump/kexec/kexec.c 2005-08-24 15:45:57.670907808 +0530 +@@ -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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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" @@ -1328,9 +4007,9 @@ diff -Nurp kexec-tools-1.101-orig/kexec/kexec.c kexec-tools-1.101-kdump/kexec/ke print_segments(stderr, &info); } return result; -diff -Nurp kexec-tools-1.101-orig/kexec/kexec.h kexec-tools-1.101-kdump/kexec/kexec.h ---- kexec-tools-1.101-orig/kexec/kexec.h 2005-01-13 18:33:00.000000000 +0530 -+++ kexec-tools-1.101-kdump/kexec/kexec.h 2005-08-24 15:45:28.093404272 +0530 +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 @@ -1355,7 +4034,7 @@ diff -Nurp kexec-tools-1.101-orig/kexec/kexec.h kexec-tools-1.101-kdump/kexec/ke 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,7 @@ extern size_t purgatory_size; +@@ -188,7 +193,8 @@ extern size_t purgatory_size; void arch_usage(void); int arch_process_options(int argc, char **argv); @@ -1363,11 +4042,49 @@ diff -Nurp kexec-tools-1.101-orig/kexec/kexec.h kexec-tools-1.101-kdump/kexec/ke +int arch_compat_trampoline(struct kexec_info *info); void arch_update_purgatory(struct kexec_info *info); ++#define MAX_LINE 160 #endif /* KEXEC_H */ -diff -Nurp kexec-tools-1.101-orig/purgatory/arch/i386/crashdump_backup.c kexec-tools-1.101-kdump/purgatory/arch/i386/crashdump_backup.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.094404120 +0530 -@@ -0,0 +1,44 @@ +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 + * @@ -1395,7 +4112,9 @@ diff -Nurp kexec-tools-1.101-orig/purgatory/arch/i386/crashdump_backup.c kexec-t +#define BACKUP_REGION_SIZE 0xa0000 + +/* Backup region start gets set after /proc/iomem has been parsed. */ -+uint32_t backup_start = 0; ++/* 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 @@ -1412,17 +4131,17 @@ diff -Nurp kexec-tools-1.101-orig/purgatory/arch/i386/crashdump_backup.c kexec-t + memcpy(dest, src, BACKUP_REGION_SIZE); + } +} -diff -Nurp kexec-tools-1.101-orig/purgatory/arch/i386/Makefile kexec-tools-1.101-kdump/purgatory/arch/i386/Makefile ---- kexec-tools-1.101-orig/purgatory/arch/i386/Makefile 2005-01-11 06:37:58.000000000 +0530 -+++ kexec-tools-1.101-kdump/purgatory/arch/i386/Makefile 2005-08-24 15:45:28.119400320 +0530 +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 -Nurp kexec-tools-1.101-orig/purgatory/arch/i386/purgatory-x86.c kexec-tools-1.101-kdump/purgatory/arch/i386/purgatory-x86.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.119400320 +0530 +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; @@ -1441,9 +4160,9 @@ diff -Nurp kexec-tools-1.101-orig/purgatory/arch/i386/purgatory-x86.c kexec-tool +{ + if (panic_kernel) crashdump_backup_memory(); +} -diff -Nurp kexec-tools-1.101-orig/purgatory/arch/i386/purgatory-x86.h kexec-tools-1.101-kdump/purgatory/arch/i386/purgatory-x86.h ---- kexec-tools-1.101-orig/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-08-24 15:45:28.120400168 +0530 +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); @@ -1451,9 +4170,9 @@ diff -Nurp kexec-tools-1.101-orig/purgatory/arch/i386/purgatory-x86.h kexec-tool +void crashdump_backup_memory(void); #endif /* PURGATORY_X86_H */ -diff -Nurp kexec-tools-1.101-orig/purgatory/arch/ia64/purgatory-ia64.c kexec-tools-1.101-kdump/purgatory/arch/ia64/purgatory-ia64.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.145396368 +0530 +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 */ @@ -1464,9 +4183,9 @@ diff -Nurp kexec-tools-1.101-orig/purgatory/arch/ia64/purgatory-ia64.c kexec-too +{ + /* Nothing for now */ +} -diff -Nurp kexec-tools-1.101-orig/purgatory/arch/ppc/purgatory-ppc.c kexec-tools-1.101-kdump/purgatory/arch/ppc/purgatory-ppc.c ---- kexec-tools-1.101-orig/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-08-24 15:45:28.170392568 +0530 +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 */ @@ -1477,10 +4196,253 @@ diff -Nurp kexec-tools-1.101-orig/purgatory/arch/ppc/purgatory-ppc.c kexec-tools +{ + /* Nothing for now */ +} -diff -Nurp kexec-tools-1.101-orig/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-orig/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-08-24 15:45:28.171392416 +0530 -@@ -10,3 +10,9 @@ void setup_arch(void) +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(); } @@ -1488,11 +4450,11 @@ diff -Nurp kexec-tools-1.101-orig/purgatory/arch/x86_64/purgatory-x86_64.c kexec +/* This function can be used to execute after the SHA256 verification. */ +void post_verification_setup_arch(void) +{ -+ /* Nothing for now */ ++ if (panic_kernel) crashdump_backup_memory(); +} -diff -Nurp kexec-tools-1.101-orig/purgatory/include/purgatory.h kexec-tools-1.101-kdump/purgatory/include/purgatory.h ---- kexec-tools-1.101-orig/purgatory/include/purgatory.h 2004-12-18 18:42:15.000000000 +0530 -+++ kexec-tools-1.101-kdump/purgatory/include/purgatory.h 2005-08-24 15:45:28.145396368 +0530 +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, ...); @@ -1500,9 +4462,49 @@ diff -Nurp kexec-tools-1.101-orig/purgatory/include/purgatory.h kexec-tools-1.10 +void post_verification_setup_arch(void); #endif /* PURGATORY_H */ -diff -Nurp kexec-tools-1.101-orig/purgatory/purgatory.c kexec-tools-1.101-kdump/purgatory/purgatory.c ---- kexec-tools-1.101-orig/purgatory/purgatory.c 2004-12-22 00:21:03.000000000 +0530 -+++ kexec-tools-1.101-kdump/purgatory/purgatory.c 2005-08-24 15:45:28.144396520 +0530 +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(); diff --git a/kexec-tools.spec b/kexec-tools.spec index e482309..566b433 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -1,6 +1,6 @@ Name: kexec-tools Version: 1.101 -Release: 5.1 +Release: 6 License: GPL Group: Applications/System Summary: The kexec/kdump userspace component. @@ -104,6 +104,9 @@ exit 0 %doc TODO %changelog +* Mon Jan 30 2006 Thomas Graf +- New kdump patch to support x86_64 userspace + * Fri Dec 16 2005 Jesse Keating - rebuilt for new gcj