add mips64 support to kexec-tools, counterpart of r17768.
authorFlorian Fainelli <florian@openwrt.org>
Sun, 27 Sep 2009 19:13:17 +0000 (19:13 +0000)
committerFlorian Fainelli <florian@openwrt.org>
Sun, 27 Sep 2009 19:13:17 +0000 (19:13 +0000)
SVN-Revision: 17769

package/kexec-tools/Makefile
package/kexec-tools/patches/0005-mips64_support.patch [new file with mode: 0644]

index e7fcb67286a61b328993f1ea666b59fbaf32d18e..d350bb2c8b6157a3b5c8106a7752beb9b9cc811d 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=kexec-tools
 PKG_VERSION:=2.0.1
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=@KERNEL/linux/kernel/people/horms/kexec-tools
diff --git a/package/kexec-tools/patches/0005-mips64_support.patch b/package/kexec-tools/patches/0005-mips64_support.patch
new file mode 100644 (file)
index 0000000..6b53eac
--- /dev/null
@@ -0,0 +1,732 @@
+Index: kexec-tools-2.0.1/kexec/arch/mips/Makefile
+===================================================================
+--- kexec-tools-2.0.1.orig/kexec/arch/mips/Makefile    2008-07-15 02:46:43.000000000 +0200
++++ kexec-tools-2.0.1/kexec/arch/mips/Makefile 2009-09-27 19:07:26.000000000 +0200
+@@ -4,7 +4,7 @@
+ mips_KEXEC_SRCS =  kexec/arch/mips/kexec-mips.c
+ mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-mips.c
+ mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-rel-mips.c
+-mips_KEXEC_SRCS += kexec/arch/mips/mips-setup-simple.S
++mips_KEXEC_SRCS += kexec/arch/mips/crashdump-mips.c
+ mips_ADD_BUFFER =
+ mips_ADD_SEGMENT =
+Index: kexec-tools-2.0.1/kexec/arch/mips/crashdump-mips.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ kexec-tools-2.0.1/kexec/arch/mips/crashdump-mips.c 2009-09-27 19:07:26.000000000 +0200
+@@ -0,0 +1,371 @@
++/*
++ * kexec: Linux boots Linux
++ *
++ * 2005 (C) IBM Corporation.
++ * 2008 (C) MontaVista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation (version 2 of the License).
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <elf.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include "../../kexec.h"
++#include "../../kexec-elf.h"
++#include "../../kexec-syscall.h"
++#include "../../crashdump.h"
++#include "kexec-mips.h"
++#include "crashdump-mips.h"
++
++extern struct arch_options_t arch_options;
++
++/* Stores a sorted list of RAM memory ranges for which to create elf headers.
++ * A separate program header is created for backup region */
++static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
++
++/* Memory region reserved for storing panic kernel and other data. */
++static struct memory_range crash_reserved_mem;
++
++/*
++ * To store the memory size of the first kernel and this value will be
++ * passed to the second kernel as command line (savemaxmem=xM).
++ * The second kernel will be calculated saved_max_pfn based on this
++ * variable.
++ */
++unsigned long long saved_max_mem = 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;
++}
++/* 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 i, 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;
++    }
++
++    /* Separate segment for backup region */
++    crash_memory_range[0].start = BACKUP_SRC_START;
++    crash_memory_range[0].end = BACKUP_SRC_END;
++    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;
++
++        /* Only Dumping memory of type System RAM. */
++        if (memcmp(str, "System RAM\n", 11) == 0) {
++            type = RANGE_RAM;
++        } else if (memcmp(str, "Crash kernel\n", 13) == 0) {
++                /* Reserved memory region. New kernel can
++                 * use this region to boot into. */
++                crash_reserved_mem.start = start;
++                crash_reserved_mem.end = end;
++                crash_reserved_mem.type = RANGE_RAM;
++                continue;
++        } else {
++            continue;
++        }
++
++        if (start == BACKUP_SRC_START && end >= (BACKUP_SRC_END + 1))
++            start = BACKUP_SRC_END + 1;
++
++        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;
++
++    for (i = 0; i < memory_ranges; i++)
++        if (saved_max_mem < crash_memory_range[i].end)
++            saved_max_mem = crash_memory_range[i].end + 1;
++
++    *range = crash_memory_range;
++    *ranges = memory_ranges;
++    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 mem= options to command line, indicating the
++ * memory region the new kernel can use to boot into. */
++static int cmdline_add_mem(char *cmdline, unsigned long addr, unsigned long size)
++{
++    int cmdlen, len;
++    char str[50], *ptr;
++
++    addr = addr/1024;
++    size = size/1024;
++    ptr = str;
++    strcpy (str, " mem=");
++    ptr += strlen(str);
++    ultoa(size, ptr);
++    strcat (str, "K@");
++    ptr = str + 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);
++
++    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);
++    return 0;
++}
++
++/* Adds the elfcorehdr= command line parameter to command line. */
++static int cmdline_add_savemaxmem(char *cmdline, unsigned long addr)
++{
++    int cmdlen, len, align = 1024;
++    char str[30], *ptr;
++
++    /* Passing in savemaxmem=xxxM format. Saves space required in cmdline.*/
++    addr = addr/(align*align);
++    ptr = str;
++    strcpy(str, " savemaxmem=");
++    ptr += strlen(str);
++    ultoa(addr, ptr);
++    strcat(str, "M");
++    len = strlen(str);
++    cmdlen = strlen(cmdline) + len;
++    if (cmdlen > (COMMAND_LINE_SIZE - 1))
++        die("Command line overflow\n");
++    strcat(cmdline, str);
++    return 0;
++}
++
++#ifdef __mips64
++static struct crash_elf_info elf_info64 =
++{
++    class: ELFCLASS64,
++    data: ELFDATA2MSB,
++    machine: EM_MIPS,
++    backup_src_start: BACKUP_SRC_START,
++    backup_src_end: BACKUP_SRC_END,
++    page_offset: PAGE_OFFSET,
++    lowmem_limit: MAXMEM,
++};
++#endif
++static struct crash_elf_info elf_info32 =
++{
++    class: ELFCLASS32,
++    data: ELFDATA2MSB,
++    machine: EM_MIPS,
++    backup_src_start: BACKUP_SRC_START,
++    backup_src_end: BACKUP_SRC_END,
++    page_offset: PAGE_OFFSET,
++    lowmem_limit: MAXMEM,
++};
++
++/* 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;
++    struct memory_range *mem_range;
++
++    if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
++        return -1;
++
++    /* Create a backup region segment to store backup data*/
++    sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
++    tmp = xmalloc(sz);
++    memset(tmp, 0, sz);
++    info->backup_start = add_buffer(info, tmp, sz, sz, align,
++                crash_reserved_mem.start,
++                crash_reserved_mem.end,-1);
++
++#ifdef __mips64
++    /* Create elf header segment and store crash image data. */
++    if (arch_options.core_header_type == CORE_TYPE_ELF64) {
++        if (crash_create_elf64_headers(info, &elf_info64,
++                           crash_memory_range, nr_ranges,
++                           &tmp, &sz,
++                           ELF_CORE_HEADER_ALIGN) < 0)
++            return -1;
++    }
++    else {
++        if (crash_create_elf32_headers(info, &elf_info32,
++                           crash_memory_range, nr_ranges,
++                           &tmp, &sz,
++                           ELF_CORE_HEADER_ALIGN) < 0)
++            return -1;
++    }
++#else
++    if (crash_create_elf32_headers(info, &elf_info32,
++                   crash_memory_range, nr_ranges,
++                   &tmp, &sz,
++                   ELF_CORE_HEADER_ALIGN) < 0)
++        return -1;
++#endif
++    elfcorehdr = add_buffer(info, tmp, sz, sz, align,
++                crash_reserved_mem.start,
++                crash_reserved_mem.end, -1);
++
++    /*
++     * backup segment is after elfcorehdr, so use elfcorehdr as top of
++     * kernel's available memory
++     */
++    cmdline_add_mem(mod_cmdline, crash_reserved_mem.start,
++        elfcorehdr - crash_reserved_mem.start);
++    cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
++    cmdline_add_savemaxmem(mod_cmdline, saved_max_mem);
++    return 0;
++}
++
++int is_crashkernel_mem_reserved(void)
++{
++    uint64_t start, end;
++
++    return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ?
++      (start != end) : 0;
++}
++
+Index: kexec-tools-2.0.1/kexec/arch/mips/crashdump-mips.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ kexec-tools-2.0.1/kexec/arch/mips/crashdump-mips.h 2009-09-27 19:07:26.000000000 +0200
+@@ -0,0 +1,26 @@
++#ifndef CRASHDUMP_MIPS_H
++#define CRASHDUMP_MIPS_H
++
++struct kexec_info;
++int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
++                unsigned long max_addr, unsigned long min_base);
++#ifdef __mips64
++#define PAGE_OFFSET    0xa800000000000000ULL
++#else
++#define PAGE_OFFSET    0x80000000
++#endif
++#define __pa(x)        ((unsigned long)(X)& 0x7fffffff)
++
++#define MAXMEM        0x80000000
++
++#define CRASH_MAX_MEMMAP_NR    (KEXEC_MAX_SEGMENTS + 1)
++#define CRASH_MAX_MEMORY_RANGES    (MAX_MEMORY_RANGES + 2)
++
++#define COMMAND_LINE_SIZE    512
++
++/* Backup Region, First 1M of System RAM. */
++#define BACKUP_SRC_START    0x00000000
++#define BACKUP_SRC_END        0x000fffff
++#define BACKUP_SRC_SIZE    (BACKUP_SRC_END - BACKUP_SRC_START + 1)
++
++#endif /* CRASHDUMP_MIPS_H */
+Index: kexec-tools-2.0.1/kexec/arch/mips/include/arch/options.h
+===================================================================
+--- kexec-tools-2.0.1.orig/kexec/arch/mips/include/arch/options.h      2008-07-15 02:46:43.000000000 +0200
++++ kexec-tools-2.0.1/kexec/arch/mips/include/arch/options.h   2009-09-27 19:18:21.000000000 +0200
+@@ -2,10 +2,21 @@
+ #define KEXEC_ARCH_MIPS_OPTIONS_H
+ #define OPT_ARCH_MAX   (OPT_MAX+0)
++#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
++#ifdef __mips64
++#define OPT_ELF64_CORE        (OPT_MAX+1)
+ #define KEXEC_ARCH_OPTIONS \
+       KEXEC_OPTIONS \
++      { "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \
+ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
++#define OPT_ARCH_MAX       (OPT_MAX+2)
++#else
++#define KEXEC_ARCH_OPTIONS \
++      KEXEC_OPTIONS \
++
++#define OPT_ARCH_MAX   (OPT_MAX+0)
++#endif
+ #endif /* KEXEC_ARCH_MIPS_OPTIONS_H */
+Index: kexec-tools-2.0.1/kexec/arch/mips/kexec-elf-mips.c
+===================================================================
+--- kexec-tools-2.0.1.orig/kexec/arch/mips/kexec-elf-mips.c    2008-07-15 02:46:43.000000000 +0200
++++ kexec-tools-2.0.1/kexec/arch/mips/kexec-elf-mips.c 2009-09-27 19:16:39.000000000 +0200
+@@ -25,51 +25,18 @@
+ #include <ip_checksum.h>
+ #include "../../kexec.h"
+ #include "../../kexec-elf.h"
++#include "../../kexec-syscall.h"
+ #include "kexec-mips.h"
+ #include <arch/options.h>
++#include "crashdump-mips.h"
+ static const int probe_debug = 0;
+ #define BOOTLOADER         "kexec"
+ #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,
+-      },
+-};
+-
+-
+-#define OPT_APPEND    (OPT_ARCH_MAX+0)
++/* 'kexec' in cmdline is used to find cmdline buffer by kernel */
++static char cmdline_buf[256] = "kexec ";
+ int elf_mips_probe(const char *buf, off_t len)
+ {
+@@ -108,16 +75,14 @@
+       struct kexec_info *info)
+ {
+       struct mem_ehdr ehdr;
+-      char *arg_buf;
+-      size_t arg_bytes;
+-      unsigned long arg_base;
+-      struct boot_notes *notes;
+-      size_t note_bytes;
+-      const char *command_line;
+-      int command_line_len;
+-      unsigned char *setup_start;
+-      uint32_t setup_size;
++      unsigned long bss_start, bss_size = 0;
++      const char *command_line = NULL;
++      char *modified_cmdline;
++      int modified_cmdline_len;
++      unsigned long cmdline_addr;
++      int result,i;
+       int opt;
++#define OPT_APPEND     (OPT_ARCH_MAX+0)
+       static const struct option options[] = {
+               KEXEC_ARCH_OPTIONS
+               {"command-line", 1, 0, OPT_APPEND},
+@@ -144,38 +109,81 @@
+                       break;
+               }
+       }
+-      command_line_len = 0;
+-      setup_simple_regs.spr9 = 0;
+-      if (command_line) {
+-              command_line_len = strlen(command_line) + 1;
+-              setup_simple_regs.spr9 = 2;
++      /* 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, 0);
+-
+-      setup_start = setup_simple_start;
+-      setup_size = setup_simple_size;
+-      setup_simple_regs.spr8 = ehdr.e_entry;
+-
+-      note_bytes = sizeof(elf_boot_notes) + ((command_line_len + 3) & ~3);
+-      arg_bytes = note_bytes + ((setup_size + 3) & ~3);
+-
+-      arg_buf = xmalloc(arg_bytes);
+-      arg_base = add_buffer_virt(info,
+-               arg_buf, arg_bytes, arg_bytes, 4, 0, elf_max_addr(&ehdr), 1);
++      /* Parse the Elf file */
++      result = build_elf_exec_info(buf, len, &ehdr, 0);
++      if (result < 0) {
++              die("ELF exec parse failed\n");
++      }
+-      notes = (struct boot_notes *)(arg_buf + ((setup_size + 3) & ~3));
++      /* Read in the PT_LOAD segments and remove CKSEG0 mask from address*/
++      for(i = 0; i < ehdr.e_phnum; i++) {
++              struct mem_phdr *phdr;
++              phdr = &ehdr.e_phdr[i];
++              if (phdr->p_type == PT_LOAD) {
++                      phdr->p_paddr = virt_to_phys(phdr->p_paddr);
++              }
++      }
+-      memcpy(arg_buf, setup_start, setup_size);
+-      memcpy(notes, &elf_boot_notes, sizeof(elf_boot_notes));
+-      memcpy(notes->command_line, command_line, command_line_len);
++      for(i = 0; i < ehdr.e_shnum; i++) {
++              struct mem_shdr *shdr;
++              unsigned char *strtab;
++              strtab = (unsigned char *)ehdr.e_shdr[ehdr.e_shstrndx].sh_data;
++
++              shdr = &ehdr.e_shdr[i];
++              if ( shdr->sh_size &&
++                              strcmp((char *)&strtab[shdr->sh_name],
++                                      ".bss") == 0) {
++                      bss_start = virt_to_phys(shdr->sh_addr);
++                      bss_size = shdr->sh_size;
++                      break;
++              }
++      }
+-      notes->hdr.b_size = note_bytes;
+-      notes->cmd_hdr.n_descsz = command_line_len;
+-      notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes);
++      /* Load the Elf data */
++      result = elf_exec_load(&ehdr, info);
++      if (result < 0) {
++              die("ELF exec load failed\n");
++      }
++      info->entry = (void *)virt_to_phys(ehdr.e_entry);
++      if(!bss_size)
++              die("No .bss segment present\n");
++
++      /* Put cmdline right after bss */
++      cmdline_addr = bss_start + bss_size;
++
++      /* If panic kernel is being loaded, additional segments need
++       * to be created.
++       */
++      if (info->kexec_flags & KEXEC_ON_CRASH) {
++              result = load_crashdump_segments(info, modified_cmdline,
++                                                              0, 0);
++              if (result < 0)
++                      return -1;
++              /* Use new command line. */
++              command_line = modified_cmdline;
++      }
+-      info->entry = (void *)arg_base;
++      if (command_line)
++      {
++              strncat(cmdline_buf,command_line,
++                      sizeof(cmdline_buf) - strlen(cmdline_buf) - 1);
++              add_buffer(info, cmdline_buf, sizeof(cmdline_buf),
++                      sizeof(cmdline_buf), sizeof(void*),
++                      cmdline_addr, 0x0fffffff, 1);
++      }
+       return 0;
+ }
+Index: kexec-tools-2.0.1/kexec/arch/mips/kexec-mips.c
+===================================================================
+--- kexec-tools-2.0.1.orig/kexec/arch/mips/kexec-mips.c        2008-07-15 02:46:43.000000000 +0200
++++ kexec-tools-2.0.1/kexec/arch/mips/kexec-mips.c     2009-09-27 19:20:25.000000000 +0200
+@@ -97,8 +97,18 @@
+ void arch_usage(void)
+ {
++#ifdef __mips64
++       fprintf(stderr, "        --elf32-core-headers Prepare core headers in "
++                       "ELF32 format\n");
++#endif
+ }
++#ifdef __mips64
++struct arch_options_t arch_options = {
++       .core_header_type = CORE_TYPE_ELF64
++};
++#endif
++
+ int arch_process_options(int argc, char **argv)
+ {
+       static const struct option options[] = {
+@@ -113,6 +123,11 @@
+               switch(opt) {
+               default:
+                       break;
++#ifdef __mips64
++              case OPT_ELF64_CORE:
++                      arch_options.core_header_type = CORE_TYPE_ELF64;
++                      break;
++#endif
+               }
+       }
+       /* Reset getopt for the next pass; called in other source modules */
+@@ -126,6 +141,10 @@
+        * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_MIPS here.
+        */
+       { "mips", KEXEC_ARCH_DEFAULT },
++      /* Not using KEXEC_ARCH_DEFAULT because that will fail
++       * in the kernel's compat_sys_kexec_load() routine.
++       */
++      { "mips64", KEXEC_ARCH_MIPS },
+       { 0 },
+ };
+@@ -138,18 +157,9 @@
+ {
+ }
+-/*
+- * Adding a dummy function, so that build on mips will not break.
+- * Need to implement the actual checking code
+- */
+-int is_crashkernel_mem_reserved(void)
+-{
+-      return 1;
+-}
+-
+ unsigned long virt_to_phys(unsigned long addr)
+ {
+-      return addr - 0x80000000;
++      return ((addr)& 0x7fffffff);
+ }
+ /*
+Index: kexec-tools-2.0.1/kexec/arch/mips/kexec-mips.h
+===================================================================
+--- kexec-tools-2.0.1.orig/kexec/arch/mips/kexec-mips.h        2008-07-15 02:46:43.000000000 +0200
++++ kexec-tools-2.0.1/kexec/arch/mips/kexec-mips.h     2009-09-27 19:21:32.000000000 +0200
+@@ -1,17 +1,16 @@
+ #ifndef KEXEC_MIPS_H
+ #define KEXEC_MIPS_H
+-extern unsigned char setup_simple_start[];
+-extern uint32_t setup_simple_size;
+-
+-extern struct {
+-      uint32_t spr8;
+-      uint32_t spr9;
+-} setup_simple_regs;
++#define MAX_MEMORY_RANGES 64
++#define CORE_TYPE_ELF32 1
++#define CORE_TYPE_ELF64 2
+ int elf_mips_probe(const char *buf, off_t len);
+ int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
+       struct kexec_info *info);
+ void elf_mips_usage(void);
++struct arch_options_t {
++      int core_header_type;
++};
+ #endif /* KEXEC_MIPS_H */