From fdf6316037d37a8739a1319b8de7e6acae0db41f Mon Sep 17 00:00:00 2001 From: "Jeffrey E. Moyer" Date: Mon, 29 Aug 2005 20:12:47 +0000 Subject: [PATCH] Initial import of kexec-tools, with added kdump support. --- .cvsignore | 1 + kexec-tools-1.101-kdump.patch | 1511 +++++++++++++++++++++++++++++++++ kexec-tools.spec | 63 ++ sources | 1 + 4 files changed, 1576 insertions(+) create mode 100644 kexec-tools-1.101-kdump.patch create mode 100644 kexec-tools.spec diff --git a/.cvsignore b/.cvsignore index e69de29..aebf1b9 100644 --- a/.cvsignore +++ b/.cvsignore @@ -0,0 +1 @@ +kexec-tools-1.101.tar.gz diff --git a/kexec-tools-1.101-kdump.patch b/kexec-tools-1.101-kdump.patch new file mode 100644 index 0000000..70386b5 --- /dev/null +++ b/kexec-tools-1.101-kdump.patch @@ -0,0 +1,1511 @@ +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 @@ ++/* ++ * kexec: Linux boots Linux ++ * ++ * Created by: Vivek Goyal (vgoyal@in.ibm.com) ++ * Copyright (C) IBM Corporation, 2005. All rights reserved ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation (version 2 of the License). ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../kexec.h" ++#include "../../kexec-elf.h" ++#include "../../kexec-syscall.h" ++#include "kexec-x86.h" ++#include "crashdump-x86.h" ++#include ++ ++#define MAX_LINE 160 ++ ++extern struct arch_options_t arch_options; ++ ++/* Forward Declaration. */ ++static int exclude_crash_reserve_region(int *nr_ranges); ++ ++/* Stores a sorted list of RAM memory ranges for which to create elf headers. ++ * A separate program header is created for backup region */ ++static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES]; ++ ++/* Memory region reserved for storing panic kernel and other data. */ ++static struct memory_range crash_reserved_mem; ++ ++/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to ++ * create Elf headers. Keeping it separate from get_memory_ranges() as ++ * requirements are different in the case of normal kexec and crashdumps. ++ * ++ * Normal kexec needs to look at all of available physical memory irrespective ++ * of the fact how much of it is being used by currently running kernel. ++ * Crashdumps need to have access to memory regions actually being used by ++ * running kernel. Expecting a different file/data structure than /proc/iomem ++ * to look into down the line. May be something like /proc/kernelmem or may ++ * be zone data structures exported from kernel. ++ */ ++static int get_crash_memory_ranges(struct memory_range **range, int *ranges) ++{ ++ const char iomem[]= "/proc/iomem"; ++ int memory_ranges = 0; ++ char line[MAX_LINE]; ++ FILE *fp; ++ unsigned long long start, end; ++ ++ fp = fopen(iomem, "r"); ++ if (!fp) { ++ fprintf(stderr, "Cannot open %s: %s\n", ++ iomem, strerror(errno)); ++ return -1; ++ } ++ ++ /* First entry is for first 640K region. Different bios report first ++ * 640K in different manner hence hardcoding it */ ++ crash_memory_range[0].start = 0x00000000; ++ crash_memory_range[0].end = 0x0009ffff; ++ crash_memory_range[0].type = RANGE_RAM; ++ memory_ranges++; ++ ++ while(fgets(line, sizeof(line), fp) != 0) { ++ char *str; ++ int type, consumed, count; ++ if (memory_ranges >= CRASH_MAX_MEMORY_RANGES) ++ break; ++ count = sscanf(line, "%Lx-%Lx : %n", ++ &start, &end, &consumed); ++ if (count != 2) ++ continue; ++ str = line + consumed; ++#if 0 ++ printf("%016Lx-%016Lx : %s", ++ start, end, str); ++#endif ++ /* Only Dumping memory of type System RAM. */ ++ if (memcmp(str, "System RAM\n", 11) == 0) { ++ type = RANGE_RAM; ++ } else if (memcmp(str, "Crash kernel\n", 13) == 0) { ++ /* Reserved memory region. New kernel can ++ * use this region to boot into. */ ++ crash_reserved_mem.start = start; ++ crash_reserved_mem.end = end; ++ crash_reserved_mem.type = RANGE_RAM; ++ continue; ++ } else { ++ continue; ++ } ++ ++ /* First 640K already registered */ ++ if (start >= 0x00000000 && end <= 0x0009ffff) ++ continue; ++ ++ crash_memory_range[memory_ranges].start = start; ++ crash_memory_range[memory_ranges].end = end; ++ crash_memory_range[memory_ranges].type = type; ++ memory_ranges++; ++ ++ /* Segregate linearly mapped region. */ ++ if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) { ++ crash_memory_range[memory_ranges-1].end = MAXMEM -1; ++ ++ /* Add segregated region. */ ++ crash_memory_range[memory_ranges].start = MAXMEM; ++ crash_memory_range[memory_ranges].end = end; ++ crash_memory_range[memory_ranges].type = type; ++ memory_ranges++; ++ } ++ } ++ fclose(fp); ++ if (exclude_crash_reserve_region(&memory_ranges) < 0) ++ return -1; ++ *range = crash_memory_range; ++ *ranges = memory_ranges; ++#if 0 ++ int i; ++ printf("CRASH MEMORY RANGES\n"); ++ for(i = 0; i < memory_ranges; i++) { ++ start = crash_memory_range[i].start; ++ end = crash_memory_range[i].end; ++ printf("%016Lx-%016Lx\n", start, end); ++ } ++#endif ++ return 0; ++} ++ ++/* Removes crash reserve region from list of memory chunks for whom elf program ++ * headers have to be created. Assuming crash reserve region to be a single ++ * continuous area fully contained inside one of the memory chunks */ ++static int exclude_crash_reserve_region(int *nr_ranges) ++{ ++ int i, j, tidx = -1; ++ unsigned long long cstart, cend; ++ struct memory_range temp_region; ++ ++ /* Crash reserved region. */ ++ cstart = crash_reserved_mem.start; ++ cend = crash_reserved_mem.end; ++ ++ for (i = 0; i < (*nr_ranges); i++) { ++ unsigned long long mstart, mend; ++ mstart = crash_memory_range[i].start; ++ mend = crash_memory_range[i].end; ++ if (cstart < mend && cend > mstart) { ++ if (cstart != mstart && cend != mend) { ++ /* Split memory region */ ++ crash_memory_range[i].end = cstart - 1; ++ temp_region.start = cend + 1; ++ temp_region.end = mend; ++ temp_region.type = RANGE_RAM; ++ tidx = i+1; ++ } else if (cstart != mstart) ++ crash_memory_range[i].end = cstart - 1; ++ else ++ crash_memory_range[i].start = cend + 1; ++ } ++ } ++ /* Insert split memory region, if any. */ ++ if (tidx >= 0) { ++ if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) { ++ /* No space to insert another element. */ ++ fprintf(stderr, "Error: Number of crash memory ranges" ++ " excedeed the max limit\n"); ++ return -1; ++ } ++ for (j = (*nr_ranges - 1); j >= tidx; j--) ++ crash_memory_range[j+1] = crash_memory_range[j]; ++ crash_memory_range[tidx].start = temp_region.start; ++ crash_memory_range[tidx].end = temp_region.end; ++ crash_memory_range[tidx].type = temp_region.type; ++ (*nr_ranges)++; ++ } ++ return 0; ++} ++ ++/* Adds a segment from list of memory regions which new kernel can use to ++ * boot. Segment start and end should be aligned to 1K boundary. */ ++static int add_memmap(struct memory_range *memmap_p, unsigned long long addr, ++ size_t size) ++{ ++ int i, j, nr_entries = 0, tidx = 0, align = 1024; ++ unsigned long long mstart, mend; ++ ++ /* Do alignment check. */ ++ if ((addr%align) || (size%align)) ++ return -1; ++ ++ /* Make sure at least one entry in list is free. */ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (!mstart && !mend) ++ break; ++ else ++ nr_entries++; ++ } ++ if (nr_entries == CRASH_MAX_MEMMAP_NR) ++ return -1; ++ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (mstart == 0 && mend == 0) ++ break; ++ if (mstart <= (addr+size-1) && mend >=addr) ++ /* Overlapping region. */ ++ return -1; ++ else if (addr > mend) ++ tidx = i+1; ++ } ++ /* Insert the memory region. */ ++ for (j = nr_entries-1; j >= tidx; j--) ++ memmap_p[j+1] = memmap_p[j]; ++ memmap_p[tidx].start = addr; ++ memmap_p[tidx].end = addr + size - 1; ++#if 0 ++ printf("Memmap after adding segment\n"); ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (mstart == 0 && mend == 0) ++ break; ++ printf("%016llx - %016llx\n", ++ mstart, mend); ++ } ++#endif ++ return 0; ++} ++ ++/* Removes a segment from list of memory regions which new kernel can use to ++ * boot. Segment start and end should be aligned to 1K boundary. */ ++static int delete_memmap(struct memory_range *memmap_p, unsigned long long addr, ++ size_t size) ++{ ++ int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024; ++ unsigned long long mstart, mend; ++ struct memory_range temp_region; ++ ++ /* Do alignment check. */ ++ if ((addr%align) || (size%align)) ++ return -1; ++ ++ /* Make sure at least one entry in list is free. */ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (!mstart && !mend) ++ break; ++ else ++ nr_entries++; ++ } ++ if (nr_entries == CRASH_MAX_MEMMAP_NR) ++ /* List if full */ ++ return -1; ++ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (mstart == 0 && mend == 0) ++ /* Did not find the segment in the list. */ ++ return -1; ++ if (mstart <= addr && mend >= (addr + size - 1)) { ++ if (mstart == addr && mend == (addr + size - 1)) { ++ /* Exact match. Delete region */ ++ operation = -1; ++ tidx = i; ++ break; ++ } ++ if (mstart != addr && mend != (addr + size - 1)) { ++ /* Split in two */ ++ memmap_p[i].end = addr - 1; ++ temp_region.start = addr + size; ++ temp_region.end = mend; ++ operation = 1; ++ tidx = i; ++ break; ++ } ++ ++ /* No addition/deletion required. Adjust the existing.*/ ++ if (mstart != addr) { ++ memmap_p[i].end = addr - 1; ++ break; ++ } else { ++ memmap_p[i].start = addr + size; ++ break; ++ } ++ } ++ } ++ if ((operation == 1) && tidx >=0) { ++ /* Insert the split memory region. */ ++ for (j = nr_entries-1; j > tidx; j--) ++ memmap_p[j+1] = memmap_p[j]; ++ memmap_p[tidx+1] = temp_region; ++ } ++ if ((operation == -1) && tidx >=0) { ++ /* Delete the exact match memory region. */ ++ for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++) ++ memmap_p[j-1] = memmap_p[j]; ++ memmap_p[j-1].start = memmap_p[j-1].end = 0; ++ } ++#if 0 ++ printf("Memmap after deleting segment\n"); ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ mstart = memmap_p[i].start; ++ mend = memmap_p[i].end; ++ if (mstart == 0 && mend == 0) { ++ break; ++ } ++ printf("%016llx - %016llx\n", ++ mstart, mend); ++ } ++#endif ++ return 0; ++} ++ ++/* Converts unsigned long to ascii string. */ ++static void ultoa(unsigned long i, char *str) ++{ ++ int j = 0, k; ++ char tmp; ++ ++ do { ++ str[j++] = i % 10 + '0'; ++ } while ((i /=10) > 0); ++ str[j] = '\0'; ++ ++ /* Reverse the string. */ ++ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { ++ tmp = str[k]; ++ str[k] = str[j]; ++ str[j] = tmp; ++ } ++} ++ ++/* Adds the appropriate memmap= options to command line, indicating the ++ * memory regions the new kernel can use to boot into. */ ++static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p) ++{ ++ int i, cmdlen, len, min_sizek = 100; ++ char str_mmap[256], str_tmp[20]; ++ ++ /* Exact map */ ++ strcpy(str_mmap, " memmap=exactmap"); ++ len = strlen(str_mmap); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str_mmap); ++ ++ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { ++ unsigned long startk, endk; ++ startk = (memmap_p[i].start/1024); ++ endk = ((memmap_p[i].end + 1)/1024); ++ if (!startk && !endk) ++ /* All regions traversed. */ ++ break; ++ ++ /* A region is not worth adding if region size < 100K. It eats ++ * up precious command line length. */ ++ if ((endk - startk) < min_sizek) ++ continue; ++ strcpy (str_mmap, " memmap="); ++ ultoa((endk-startk), str_tmp); ++ strcat (str_mmap, str_tmp); ++ strcat (str_mmap, "K@"); ++ ultoa(startk, str_tmp); ++ strcat (str_mmap, str_tmp); ++ strcat (str_mmap, "K"); ++ len = strlen(str_mmap); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str_mmap); ++ } ++ ++#if 0 ++ printf("Command line after adding memmap\n"); ++ printf("%s\n", cmdline); ++#endif ++ return 0; ++} ++ ++/* Adds the elfcorehdr= command line parameter to command line. */ ++static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr) ++{ ++ int cmdlen, len, align = 1024; ++ char str[30], *ptr; ++ ++ /* Passing in elfcorehdr=xxxK format. Saves space required in cmdline. ++ * Ensure 1K alignment*/ ++ if (addr%align) ++ return -1; ++ addr = addr/align; ++ ptr = str; ++ strcpy(str, " elfcorehdr="); ++ ptr += strlen(str); ++ ultoa(addr, ptr); ++ strcat(str, "K"); ++ len = strlen(str); ++ cmdlen = strlen(cmdline) + len; ++ if (cmdlen > (COMMAND_LINE_SIZE - 1)) ++ die("Command line overflow\n"); ++ strcat(cmdline, str); ++#if 0 ++ printf("Command line after adding elfcorehdr\n"); ++ printf("%s\n", cmdline); ++#endif ++ return 0; ++} ++ ++/* Returns the virtual address of start of crash notes section. */ ++static int get_crash_notes_section_addr(unsigned long *addr) ++{ ++ const char crash_notes[]= "/sys/kernel/crash_notes"; ++ char line[MAX_LINE]; ++ FILE *fp; ++ ++ 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 0 ++ printf("crash_notes addr = %lx\n", *addr); ++#endif ++ } ++ return 0; ++} ++ ++/* Prepares the crash memory elf64 headers and stores in supplied buffer. */ ++static int prepare_crash_memory_elf64_headers(struct kexec_info *info, ++ void *buf, unsigned long size) ++{ ++ Elf64_Ehdr *elf; ++ Elf64_Phdr *phdr; ++ int i; ++ char *bufp; ++ long int nr_cpus = 0; ++ unsigned long notes_addr, notes_offset; ++ ++ bufp = (char*) buf; ++ ++ /* Setup ELF Header*/ ++ elf = (Elf64_Ehdr *) bufp; ++ bufp += sizeof(Elf64_Ehdr); ++ memcpy(elf->e_ident, ELFMAG, SELFMAG); ++ elf->e_ident[EI_CLASS] = ELFCLASS64; ++ elf->e_ident[EI_DATA] = ELFDATA2LSB; ++ elf->e_ident[EI_VERSION]= EV_CURRENT; ++ elf->e_ident[EI_OSABI] = ELFOSABI_NONE; ++ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); ++ elf->e_type = ET_CORE; ++ elf->e_machine = EM_386; ++ elf->e_version = EV_CURRENT; ++ elf->e_entry = 0; ++ elf->e_phoff = sizeof(Elf64_Ehdr); ++ elf->e_shoff = 0; ++ elf->e_flags = 0; ++ elf->e_ehsize = sizeof(Elf64_Ehdr); ++ elf->e_phentsize= sizeof(Elf64_Phdr); ++ elf->e_phnum = 0; ++ elf->e_shentsize= 0; ++ elf->e_shnum = 0; ++ elf->e_shstrndx = 0; ++ ++ /* PT_NOTE program headers. One per cpu*/ ++ nr_cpus = sysconf(_SC_NPROCESSORS_CONF); ++ if (nr_cpus < 0) { ++ return -1; ++ } ++ ++ /* 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++) { ++ 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_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)++; ++ } ++ ++ /* Setup PT_LOAD type program header for every system RAM chunk. ++ * A seprate program header for Backup Region*/ ++ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) { ++ unsigned long long mstart, mend; ++ mstart = crash_memory_range[i].start; ++ mend = crash_memory_range[i].end; ++ if (!mstart && !mend) ++ break; ++ phdr = (Elf64_Phdr *) bufp; ++ bufp += sizeof(Elf64_Phdr); ++ phdr->p_type = PT_LOAD; ++ phdr->p_flags = PF_R|PF_W|PF_X; ++ if (mstart == BACKUP_START && mend == BACKUP_END) ++ phdr->p_offset = info->backup_start; ++ else ++ phdr->p_offset = mstart; ++ /* Handle linearly mapped region.*/ ++ if (mend <= (MAXMEM - 1)) ++ phdr->p_vaddr = mstart + PAGE_OFFSET; ++ else ++ phdr->p_vaddr = -1ULL; ++ phdr->p_paddr = mstart; ++ phdr->p_filesz = phdr->p_memsz = mend - mstart + 1; ++ /* Do we need any alignment of segments? */ ++ phdr->p_align = 0; ++ ++ /* Increment number of program headers. */ ++ (elf->e_phnum)++; ++ } ++ return 0; ++} ++ ++/* Prepares the crash memory elf32 headers and stores in supplied buffer. */ ++static int prepare_crash_memory_elf32_headers(struct kexec_info *info, ++ void *buf, unsigned long size) ++{ ++ Elf32_Ehdr *elf; ++ Elf32_Phdr *phdr; ++ int i; ++ char *bufp; ++ long int nr_cpus = 0; ++ unsigned long notes_addr, notes_offset; ++ ++ bufp = (char*) buf; ++ ++ /* Setup ELF Header*/ ++ elf = (Elf32_Ehdr *) bufp; ++ bufp += sizeof(Elf32_Ehdr); ++ memcpy(elf->e_ident, ELFMAG, SELFMAG); ++ elf->e_ident[EI_CLASS] = ELFCLASS32; ++ elf->e_ident[EI_DATA] = ELFDATA2LSB; ++ elf->e_ident[EI_VERSION]= EV_CURRENT; ++ elf->e_ident[EI_OSABI] = ELFOSABI_NONE; ++ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); ++ elf->e_type = ET_CORE; ++ elf->e_machine = EM_386; ++ elf->e_version = EV_CURRENT; ++ elf->e_entry = 0; ++ elf->e_phoff = sizeof(Elf32_Ehdr); ++ elf->e_shoff = 0; ++ elf->e_flags = 0; ++ elf->e_ehsize = sizeof(Elf32_Ehdr); ++ elf->e_phentsize= sizeof(Elf32_Phdr); ++ elf->e_phnum = 0; ++ elf->e_shentsize= 0; ++ elf->e_shnum = 0; ++ elf->e_shstrndx = 0; ++ ++ /* PT_NOTE program headers. One per cpu*/ ++ nr_cpus = sysconf(_SC_NPROCESSORS_CONF); ++ if (nr_cpus < 0) { ++ return -1; ++ } ++ ++ /* Need to find a better way to determine per cpu notes section size. */ ++#define MAX_NOTE_BYTES 1024 ++ if (get_crash_notes_section_addr (¬es_addr) < 0) { ++ return -1; ++ } ++ notes_offset = __pa(notes_addr); ++ for (i = 0; i < nr_cpus; i++) { ++ 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_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)++; ++ } ++ ++ /* Setup PT_LOAD type program header for every system RAM chunk. ++ * A seprate program header for Backup Region*/ ++ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) { ++ unsigned long long mstart, mend; ++ mstart = crash_memory_range[i].start; ++ mend = crash_memory_range[i].end; ++ if (!mstart && !mend) ++ break; ++ phdr = (Elf32_Phdr *) bufp; ++ bufp += sizeof(Elf32_Phdr); ++ phdr->p_type = PT_LOAD; ++ phdr->p_flags = PF_R|PF_W|PF_X; ++ if (mstart == BACKUP_START && mend == BACKUP_END) ++ phdr->p_offset = info->backup_start; ++ else ++ phdr->p_offset = mstart; ++ /* Handle linearly mapped region.*/ ++ if (mend <= (MAXMEM - 1)) ++ phdr->p_vaddr = mstart + PAGE_OFFSET; ++ else ++ phdr->p_vaddr = UINT_MAX; ++ phdr->p_paddr = mstart; ++ phdr->p_filesz = phdr->p_memsz = mend - mstart + 1; ++ /* Do we need any alignment of segments? */ ++ phdr->p_align = 0; ++ /* Increment number of program headers. */ ++ (elf->e_phnum)++; ++ } ++ return 0; ++} ++ ++/* Loads additional segments in case of a panic kernel is being loaded. ++ * One segment for backup region, another segment for storing elf headers ++ * for crash memory image. ++ */ ++int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, ++ unsigned long max_addr, unsigned long min_base) ++{ ++ void *tmp; ++ unsigned long sz, elfcorehdr; ++ int nr_ranges, align = 1024; ++ long int nr_cpus = 0; ++ struct memory_range *mem_range, *memmap_p; ++ ++ if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0) ++ return -1; ++ ++ /* Memory regions which panic kernel can safely use to boot into */ ++ sz = (sizeof(struct memory_range) * (KEXEC_MAX_SEGMENTS + 1)); ++ memmap_p = xmalloc(sz); ++ memset(memmap_p, 0, sz); ++ add_memmap(memmap_p, BACKUP_START, BACKUP_SIZE); ++ sz = crash_reserved_mem.end - crash_reserved_mem.start +1; ++ add_memmap(memmap_p, crash_reserved_mem.start, sz); ++ ++ /* Create a backup region segment to store backup data*/ ++ sz = (BACKUP_SIZE + align - 1) & ~(align - 1); ++ tmp = xmalloc(sz); ++ memset(tmp, 0, sz); ++ info->backup_start = add_buffer(info, tmp, sz, sz, align, ++ 0, max_addr, 1); ++ if (delete_memmap(memmap_p, info->backup_start, sz) < 0) ++ return -1; ++ ++ /* Create elf header segment and store crash image data. */ ++ nr_cpus = sysconf(_SC_NPROCESSORS_CONF); ++ if (nr_cpus < 0) { ++ fprintf(stderr,"kexec_load (elf header segment)" ++ " failed: %s\n", strerror(errno)); ++ return -1; ++ } ++ if (arch_options.core_header_type == CORE_TYPE_ELF64) { ++ sz = sizeof(Elf64_Ehdr) + ++ nr_cpus * sizeof(Elf64_Phdr) + ++ nr_ranges * sizeof(Elf64_Phdr); ++ } else { ++ sz = sizeof(Elf32_Ehdr) + ++ nr_cpus * sizeof(Elf32_Phdr) + ++ nr_ranges * sizeof(Elf32_Phdr); ++ } ++ sz = (sz + align - 1) & ~(align -1); ++ tmp = xmalloc(sz); ++ memset(tmp, 0, sz); ++ if (arch_options.core_header_type == CORE_TYPE_ELF64) { ++ if (prepare_crash_memory_elf64_headers(info, tmp, sz) < 0) ++ return -1; ++ } else { ++ if (prepare_crash_memory_elf32_headers(info, tmp, sz) < 0) ++ return -1; ++ } ++ ++ /* Hack: With some ld versions (GNU ld version 2.14.90.0.4 20030523), ++ * vmlinux program headers show a gap of two pages between bss segment ++ * and data segment but effectively kernel considers it as bss segment ++ * and overwrites the any data placed there. Hence bloat the memsz of ++ * elf core header segment to 16K to avoid being placed in such gaps. ++ * This is a makeshift solution until it is fixed in kernel. ++ */ ++ elfcorehdr = add_buffer(info, tmp, sz, 16*1024, align, min_base, ++ max_addr, 1); ++ if (delete_memmap(memmap_p, elfcorehdr, sz) < 0) ++ return -1; ++ cmdline_add_memmap(mod_cmdline, memmap_p); ++ cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr); ++ return 0; ++} +diff -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 +@@ -0,0 +1,21 @@ ++#ifndef CRASHDUMP_X86_H ++#define CRASHDUMP_X86_H ++ ++int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline, ++ unsigned long max_addr, unsigned long min_base); ++ ++#define PAGE_OFFSET 0xc0000000 ++#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) ++ ++#define __VMALLOC_RESERVE (128 << 20) ++#define MAXMEM (-PAGE_OFFSET-__VMALLOC_RESERVE) ++ ++#define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1) ++#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2) ++ ++/* Backup Region, First 640K of System RAM. */ ++#define BACKUP_START 0x00000000 ++#define BACKUP_END 0x0009ffff ++#define BACKUP_SIZE (BACKUP_END - BACKUP_START + 1) ++ ++#endif /* CRASHDUMP_X86_H */ +diff -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 @@ + #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 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 -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 +@@ -214,7 +214,7 @@ int do_bzImage_load(struct kexec_info *i + + /* Fill in the information BIOS calls would normally provide. */ + if (!real_mode_entry) { +- setup_linux_system_parameters(real_mode); ++ setup_linux_system_parameters(real_mode, info->kexec_flags); + } + + return 0; +diff -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 +@@ -32,10 +32,12 @@ + #include + #include + #include "../../kexec.h" ++#include "../../kexec-syscall.h" + #include "../../kexec-elf.h" + #include "../../kexec-elf-boot.h" + #include "x86-linux-setup.h" + #include "kexec-x86.h" ++#include "crashdump-x86.h" + #include + + static const int probe_debug = 0; +@@ -86,7 +88,9 @@ int elf_x86_load(int argc, char **argv, + { + struct mem_ehdr ehdr; + const char *command_line; ++ char *modified_cmdline; + int command_line_len; ++ int modified_cmdline_len; + const char *ramdisk; + unsigned long entry, max_addr; + int arg_style; +@@ -119,6 +123,8 @@ int elf_x86_load(int argc, char **argv, + */ + arg_style = ARG_STYLE_ELF; + command_line = 0; ++ modified_cmdline = 0; ++ modified_cmdline_len = 0; + ramdisk = 0; + while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { + switch(opt) { +@@ -156,6 +162,20 @@ int elf_x86_load(int argc, char **argv, + command_line_len = strlen(command_line) +1; + } + ++ /* Need to append some command line parameters internally in case of ++ * taking crash dumps. ++ */ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ modified_cmdline = xmalloc(COMMAND_LINE_SIZE); ++ memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); ++ if (command_line) { ++ strncpy(modified_cmdline, command_line, ++ COMMAND_LINE_SIZE); ++ modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; ++ } ++ modified_cmdline_len = strlen(modified_cmdline); ++ } ++ + /* Load the ELF executable */ + elf_exec_build_load(info, &ehdr, buf, len); + +@@ -203,10 +223,20 @@ int elf_x86_load(int argc, char **argv, + const unsigned char *ramdisk_buf; + off_t ramdisk_length; + struct entry32_regs regs; ++ int rc = 0; + + /* Get the linux parameter header */ + hdr = xmalloc(sizeof(*hdr)); +- param_base = add_buffer(info, hdr, sizeof(*hdr), sizeof(*hdr), ++ ++ /* Hack: With some ld versions, vmlinux program headers show ++ * a gap of two pages between bss segment and data segment ++ * but effectively kernel considers it as bss segment and ++ * overwrites the any data placed there. Hence bloat the ++ * memsz of parameter segment to 16K to avoid being placed ++ * in such gaps. ++ * This is a makeshift solution until it is fixed in kernel ++ */ ++ param_base = add_buffer(info, hdr, sizeof(*hdr), 16*1024, + 16, 0, max_addr, 1); + + /* Initialize the parameter header */ +@@ -216,9 +246,19 @@ int elf_x86_load(int argc, char **argv, + /* Add a ramdisk to the current image */ + ramdisk_buf = NULL; + ramdisk_length = 0; +- if (ramdisk) { +- unsigned char *ramdisk_buf; ++ if (ramdisk) + ramdisk_buf = slurp_file(ramdisk, &ramdisk_length); ++ ++ /* If panic kernel is being loaded, additional segments need ++ * to be created. */ ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ rc = load_crashdump_segments(info, modified_cmdline, ++ max_addr, 0); ++ if (rc < 0) ++ return -1; ++ /* Use new command line. */ ++ command_line = modified_cmdline; ++ command_line_len = strlen(modified_cmdline) + 1; + } + + /* Tell the kernel what is going on */ +@@ -228,7 +268,7 @@ int elf_x86_load(int argc, char **argv, + ramdisk_buf, ramdisk_length); + + /* Fill in the information bios calls would usually provide */ +- setup_linux_system_parameters(&hdr->hdr); ++ setup_linux_system_parameters(&hdr->hdr, info->kexec_flags); + + /* Initialize the registers */ + elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs)); +diff -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 +@@ -246,7 +246,8 @@ int multiboot_x86_load(int argc, char ** + mbi->boot_loader_name = sizeof(*mbi) + command_line_len; + + /* Memory map */ +- if ((get_memory_ranges(&range, &ranges) < 0) || ranges == 0) { ++ if ((get_memory_ranges(&range, &ranges, info->kexec_flags) < 0) ++ || ranges == 0) { + fprintf(stderr, "Cannot get memory information\n"); + return -1; + } +diff -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 @@ + #include "../../kexec-elf.h" + #include "../../kexec-syscall.h" + #include "kexec-x86.h" ++#include "crashdump-x86.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. */ +-int get_memory_ranges(struct memory_range **range, int *ranges) ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags) + { + const char iomem[]= "/proc/iomem"; + int memory_ranges = 0; +@@ -79,6 +81,20 @@ int get_memory_ranges(struct memory_rang + else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) { + type = RANGE_ACPI_NVS; + } ++ else if (memcmp(str, "Crash kernel\n", 13) == 0) { ++ /* Redefine the memory region boundaries if kernel ++ * exports the limits and if it is panic kernel. ++ * Override user values only if kernel exported values are ++ * subset of user defined values. ++ */ ++ if (kexec_flags & KEXEC_ON_CRASH) { ++ if (start > mem_min) ++ mem_min = start; ++ if (end < mem_max) ++ mem_max = end; ++ } ++ continue; ++ } + else { + continue; + } +@@ -120,21 +136,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" ++ " --elf32-core-headers Prepare core headers in ELF32 format\n" ++ " --elf64-core-headers Prepare core headers in ELF64 format\n" + ); + } + +-static struct { +- uint8_t reset_vga; +- uint16_t serial_base; +- uint32_t serial_baud; +- uint8_t console_vga; +- uint8_t console_serial; +-} arch_options = { ++struct arch_options_t arch_options = { + .reset_vga = 0, + .serial_base = 0x3f8, + .serial_baud = 0, + .console_vga = 0, + .console_serial = 0, ++ .core_header_type = CORE_TYPE_ELF64, + }; + + int arch_process_options(int argc, char **argv) +@@ -198,6 +211,12 @@ int arch_process_options(int argc, char + } + arch_options.serial_baud = value; + break; ++ case OPT_ELF32_CORE: ++ arch_options.core_header_type = CORE_TYPE_ELF32; ++ break; ++ case OPT_ELF64_CORE: ++ arch_options.core_header_type = CORE_TYPE_ELF64; ++ break; + } + } + /* Reset getopt for the next pass; called in other source modules */ +@@ -206,7 +225,7 @@ int arch_process_options(int argc, char + return 0; + } + +-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags) ++int arch_compat_trampoline(struct kexec_info *info) + { + int result; + struct utsname utsname; +@@ -224,11 +243,11 @@ int arch_compat_trampoline(struct kexec_ + /* For compatibility with older patches + * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_386 here. + */ +- *flags |= KEXEC_ARCH_DEFAULT; ++ info->kexec_flags |= KEXEC_ARCH_DEFAULT; + } + else if (strcmp(utsname.machine, "x86_64") == 0) + { +- *flags |= KEXEC_ARCH_X86_64; ++ info->kexec_flags |= KEXEC_ARCH_X86_64; + if (!info->rhdr.e_shdr) { + fprintf(stderr, + "A trampoline is required for cross architecture support\n"); +@@ -249,6 +268,8 @@ int arch_compat_trampoline(struct kexec_ + + void arch_update_purgatory(struct kexec_info *info) + { ++ uint8_t panic_kernel = 0; ++ + elf_rel_set_symbol(&info->rhdr, "reset_vga", + &arch_options.reset_vga, sizeof(arch_options.reset_vga)); + elf_rel_set_symbol(&info->rhdr, "serial_base", +@@ -259,4 +280,11 @@ void arch_update_purgatory(struct kexec_ + &arch_options.console_vga, sizeof(arch_options.console_vga)); + elf_rel_set_symbol(&info->rhdr, "console_serial", + &arch_options.console_serial, sizeof(arch_options.console_serial)); ++ if (info->kexec_flags & KEXEC_ON_CRASH) { ++ panic_kernel = 1; ++ elf_rel_set_symbol(&info->rhdr, "backup_start", ++ &info->backup_start, sizeof(info->backup_start)); ++ } ++ elf_rel_set_symbol(&info->rhdr, "panic_kernel", ++ &panic_kernel, sizeof(panic_kernel)); + } +diff -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 +@@ -1,6 +1,10 @@ + #ifndef KEXEC_X86_H + #define KEXEC_X86_H + ++#define MAX_MEMORY_RANGES 64 ++#define CORE_TYPE_ELF32 1 ++#define CORE_TYPE_ELF64 2 ++ + extern unsigned char compat_x86_64[]; + extern uint32_t compat_x86_64_size, compat_x86_64_entry32; + +@@ -35,6 +39,15 @@ struct entry16_regs { + uint16_t pad; + }; + ++struct arch_options_t { ++ uint8_t reset_vga; ++ uint16_t serial_base; ++ uint32_t serial_baud; ++ uint8_t console_vga; ++ uint8_t console_serial; ++ int core_header_type; ++}; ++ + int multiboot_x86_probe(const char *buf, off_t len); + int multiboot_x86_load(int argc, char **argv, const char *buf, off_t len, + struct kexec_info *info); +diff -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 +@@ -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 +@@ -94,7 +94,8 @@ void setup_linux_bootloader_parameters( + cmdline_ptr[cmdline_len - 1] = '\0'; + } + +-void setup_linux_system_parameters(struct x86_linux_param_header *real_mode) ++void setup_linux_system_parameters(struct x86_linux_param_header *real_mode, ++ unsigned long kexec_flags) + { + /* Fill in information the BIOS would usually provide */ + struct memory_range *range; +@@ -135,7 +136,7 @@ void setup_linux_system_parameters(struc + real_mode->aux_device_info = 0; + + /* Fill in the memory info */ +- if ((get_memory_ranges(&range, &ranges) < 0) || ranges == 0) { ++ if ((get_memory_ranges(&range, &ranges, kexec_flags) < 0) || ranges == 0) { + die("Cannot get memory information\n"); + } + if (ranges > E820MAX) { +diff -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 +@@ -7,7 +7,8 @@ void setup_linux_bootloader_parameters( + unsigned long real_mode_base, unsigned long cmdline_offset, + const char *cmdline, off_t cmdline_len, + const unsigned char *initrd_buf, off_t initrd_size); +-void setup_linux_system_parameters(struct x86_linux_param_header *real_mode); ++void setup_linux_system_parameters(struct x86_linux_param_header *real_mode, ++ unsigned long kexec_flags); + + + #define SETUP_BASE 0x90000 +diff -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 @@ + static struct memory_range memory_range[MAX_MEMORY_RANGES]; + + /* Return a sorted list of available memory ranges. */ +-int get_memory_ranges(struct memory_range **range, int *ranges) ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags) + { + int memory_ranges; + /* +@@ -103,7 +104,7 @@ int arch_process_options(int argc, char + return 0; + } + +-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags) ++int arch_compat_trampoline(struct kexec_info *info) + { + int result; + struct utsname utsname; +@@ -115,7 +116,7 @@ int arch_compat_trampoline(struct kexec_ + } + if (strcmp(utsname.machine, "ia64") == 0) + { +- *flags |= KEXEC_ARCH_X86_64; ++ info->kexec_flags |= KEXEC_ARCH_X86_64; + } + else { + fprintf(stderr, "Unsupported machine type: %s\n", +@@ -125,7 +126,7 @@ int arch_compat_trampoline(struct kexec_ + return 0; + } + +-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags) ++int arch_compat_trampoline(struct kexec_info *info) + { + int result; + struct utsname utsname; +@@ -140,7 +141,7 @@ int arch_compat_trampoline(struct kexec_ + /* For compatibility with older patches + * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_IA64 here. + */ +- *flags |= KEXEC_ARCH_DEFAULT; ++ info->kexec_flags |= KEXEC_ARCH_DEFAULT; + } + else { + fprintf(stderr, "Unsupported machine type: %s\n", +diff -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 @@ + static struct memory_range memory_range[MAX_MEMORY_RANGES]; + + /* Return a sorted list of memory ranges. */ +-int get_memory_ranges(struct memory_range **range, int *ranges) ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags) + { + int memory_ranges = 0; + #ifdef CONFIG_GAMECUBE +@@ -120,7 +121,7 @@ int arch_process_options(int argc, char + return 0; + } + +-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags) ++int arch_compat_trampoline(struct kexec_info *info) + { + int result; + struct utsname utsname; +@@ -135,7 +136,7 @@ int arch_compat_trampoline(struct kexec_ + /* For compatibility with older patches + * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_PPC here. + */ +- *flags |= KEXEC_ARCH_DEFAULT; ++ info->kexec_flags |= KEXEC_ARCH_DEFAULT; + } + else { + fprintf(stderr, "Unsupported machine type: %s\n", +diff -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 + ramdisk_buf, ramdisk_length); + + /* Fill in the information bios calls would usually provide */ +- setup_linux_system_parameters(&hdr->hdr); ++ setup_linux_system_parameters(&hdr->hdr, info->kexec_flags); + + /* Initialize the registers */ + elf_rel_get_symbol(&info->rhdr, "entry64_regs", ®s, sizeof(regs)); +diff -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 @@ + static struct memory_range memory_range[MAX_MEMORY_RANGES]; + + /* Return a sorted list of memory ranges. */ +-int get_memory_ranges(struct memory_range **range, int *ranges) ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags) + { + const char iomem[]= "/proc/iomem"; + int memory_ranges = 0; +@@ -124,7 +125,7 @@ void arch_usage(void) + ); + } + +-static struct { ++struct { + uint8_t reset_vga; + uint16_t serial_base; + uint32_t serial_baud; +@@ -207,7 +208,7 @@ int arch_process_options(int argc, char + return 0; + } + +-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags) ++int arch_compat_trampoline(struct kexec_info *info) + { + int result; + struct utsname utsname; +@@ -222,7 +223,7 @@ int arch_compat_trampoline(struct kexec_ + /* For compatibility with older patches + * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_X86_64 here. + */ +- *flags |= KEXEC_ARCH_DEFAULT; ++ info->kexec_flags |= KEXEC_ARCH_DEFAULT; + } + else { + fprintf(stderr, "Unsupported machine type: %s\n", +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 +@@ -38,8 +38,8 @@ + #include "kexec-elf.h" + #include "kexec-sha256.h" + +-static unsigned long long mem_min = 0; +-static unsigned long long mem_max = ULONG_MAX; ++unsigned long long mem_min = 0; ++unsigned long long mem_max = ULONG_MAX; + + void die(char *fmt, ...) + { +@@ -323,12 +323,17 @@ unsigned long add_buffer(struct kexec_in + { + unsigned long base; + int result; ++ int pagesize; + + result = sort_segments(info); + if (result < 0) { + die("sort_segments failed\n"); + } + ++ /* Round memsz up to a multiple of pagesize */ ++ pagesize = getpagesize(); ++ memsz = (memsz + (pagesize - 1)) & ~(pagesize - 1); ++ + base = locate_hole(info, memsz, buf_align, buf_min, buf_max, buf_end); + if (base == ULONG_MAX) { + die("locate_hole failed\n"); +@@ -507,6 +512,8 @@ static int my_load(const char *type, int + info.segment = NULL; + info.nr_segments = 0; + info.entry = NULL; ++ info.backup_start = 0; ++ info.kexec_flags = kexec_flags; + + result = 0; + if (argc - fileind <= 0) { +@@ -522,7 +529,8 @@ static int my_load(const char *type, int + kernel_buf, kernel_size); + #endif + +- if (get_memory_ranges(&memory_range, &memory_ranges) < 0) { ++ if (get_memory_ranges(&memory_range, &memory_ranges, ++ info.kexec_flags) < 0) { + fprintf(stderr, "Could not get memory layout\n"); + return -1; + } +@@ -564,7 +572,7 @@ static int my_load(const char *type, int + return -1; + } + /* If we are not in native mode setup an appropriate trampoline */ +- if (arch_compat_trampoline(&info, &kexec_flags) < 0) { ++ if (arch_compat_trampoline(&info) < 0) { + return -1; + } + /* Verify all of the segments load to a valid location in memory */ +@@ -585,17 +593,17 @@ static int my_load(const char *type, int + update_purgatory(&info); + #if 0 + fprintf(stderr, "kexec_load: entry = %p flags = %lx\n", +- info.entry, kexec_flags); ++ info.entry, info.kexec_flags); + print_segments(stderr, &info); + #endif + result = kexec_load( +- info.entry, info.nr_segments, info.segment, kexec_flags); ++ info.entry, info.nr_segments, info.segment, info.kexec_flags); + if (result != 0) { + /* The load failed, print some debugging information */ + fprintf(stderr, "kexec_load failed: %s\n", + strerror(errno)); + fprintf(stderr, "entry = %p flags = %lx\n", +- info.entry, kexec_flags); ++ info.entry, info.kexec_flags); + print_segments(stderr, &info); + } + return result; +diff -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 +@@ -91,6 +91,8 @@ do { \ + } while(0) + #endif + ++extern unsigned long long mem_min, mem_max; ++ + struct kexec_segment { + const void *buf; + size_t bufsz; +@@ -112,10 +114,13 @@ struct kexec_info { + int nr_segments; + void *entry; + struct mem_ehdr rhdr; ++ unsigned long backup_start; ++ unsigned long kexec_flags; + }; + + void usage(void); +-int get_memory_ranges(struct memory_range **range, int *ranges); ++int get_memory_ranges(struct memory_range **range, int *ranges, ++ unsigned long kexec_flags); + int valid_memory_range(unsigned long sstart, unsigned long send); + int valid_memory_segment(struct kexec_segment *segment); + void print_segments(FILE *file, struct kexec_info *info); +@@ -188,7 +193,7 @@ extern size_t purgatory_size; + + void arch_usage(void); + int arch_process_options(int argc, char **argv); +-int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags); ++int arch_compat_trampoline(struct kexec_info *info); + void arch_update_purgatory(struct kexec_info *info); + + #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 @@ ++/* ++ * kexec: Linux boots Linux ++ * ++ * Created by: Vivek goyal (vgoyal@in.ibm.com) ++ * Copyright (C) IBM Corporation, 2005. All rights reserved ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation (version 2 of the License). ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++ ++#define BACKUP_REGION_SOURCE 0x00000000 ++#define BACKUP_REGION_SIZE 0xa0000 ++ ++/* Backup region start gets set after /proc/iomem has been parsed. */ ++uint32_t backup_start = 0; ++ ++/* Backup first 640K of memory to backup region as reserved by kexec. ++ * Assuming first 640K has to be present on i386 machines and no address ++ * validity checks have to be performed. */ ++ ++void crashdump_backup_memory(void) ++{ ++ void *dest, *src; ++ ++ src = (void *) BACKUP_REGION_SOURCE; ++ ++ if (backup_start) { ++ dest = (void *)(backup_start); ++ memcpy(dest, src, BACKUP_REGION_SIZE); ++ } ++} +diff -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 +@@ -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 +@@ -30,6 +30,7 @@ void x86_setup_cpu(void) + uint8_t reset_vga = 0; + uint8_t legacy_timer = 0; + uint8_t legacy_pic = 0; ++uint8_t panic_kernel = 0; + + void setup_arch(void) + { +@@ -38,3 +39,9 @@ void setup_arch(void) + if (legacy_pic) x86_setup_legacy_pic(); + /* if (legacy_timer) x86_setup_legacy_timer(); */ + } ++ ++/* This function can be used to execute after the SHA256 verification. */ ++void post_verification_setup_arch(void) ++{ ++ if (panic_kernel) crashdump_backup_memory(); ++} +diff -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 +@@ -4,5 +4,6 @@ + void x86_reset_vga(void); + void x86_setup_legacy_pic(void); + void x86_setup_legacy_timer(void); ++void crashdump_backup_memory(void); + + #endif /* PURGATORY_X86_H */ +diff -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 +@@ -5,3 +5,9 @@ void setup_arch(void) + { + /* Nothing for now */ + } ++ ++/* This function can be used to execute after the SHA256 verification. */ ++void post_verification_setup_arch(void) ++{ ++ /* Nothing for now */ ++} +diff -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 +@@ -5,3 +5,9 @@ void setup_arch(void) + { + /* Nothing for now */ + } ++ ++/* This function can be used to execute after the SHA256 verification. */ ++void post_verification_setup_arch(void) ++{ ++ /* Nothing for now */ ++} +diff -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) + if (reset_vga) x86_reset_vga(); + if (legacy_pic) x86_setup_legacy_pic(); + } ++ ++/* This function can be used to execute after the SHA256 verification. */ ++void post_verification_setup_arch(void) ++{ ++ /* Nothing for now */ ++} +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 +@@ -4,5 +4,6 @@ + void putchar(int ch); + void printf(const char *fmt, ...); + void setup_arch(void); ++void post_verification_setup_arch(void); + + #endif /* PURGATORY_H */ +diff -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 +@@ -44,4 +44,5 @@ void purgatory(void) + printf("I'm in purgatory\n"); + setup_arch(); + verify_sha256_digest(); ++ post_verification_setup_arch(); + } diff --git a/kexec-tools.spec b/kexec-tools.spec new file mode 100644 index 0000000..309692c --- /dev/null +++ b/kexec-tools.spec @@ -0,0 +1,63 @@ +Name: kexec-tools +Version: 1.101 +Release: 2 +License: GPL +Group: Applications/System +Summary: The kexec/kdump userspace component. +ExclusiveArch: %{ix86} +Source0: %{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot + +# +# Patches 0 through 100 are meant for x86 kexec-tools enablement +# +Patch1: kexec-tools-1.101-kdump.patch + +# +# Patches 101 through 200 are meant for x86_64 kexec-tools enablement +# + +# +# Patches 201 through 300 are meant for ia64 kexec-tools enablement +# + +# +# Patches 301 through 400 are meant for ppc64 kexec-tools enablement +# + +%description +kexec-tools provides /sbin/kexec binary that facilitates a new +kernel to boot using the kernel's kexec feature either on a +normal or a panic reboot. This package contains the /sbin/kexec +binary and ancillary utilities that together form the userspace +component of the kernel's kexec feature. + +%prep +%setup -q -n %{name}-%{version} +rm -f ../kexec-tools-1.101.spec +%patch1 -p1 + +%build +%configure +rm -f kexec-tools.spec.in +make + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%{_sbindir}/kexec +%{_sbindir}/kdump +%{_libdir}/kexec-tools/kexec_test +%doc News +%doc COPYING +%doc TODO + +%changelog +* Thu Aug 25 2005 Ananth Mavinakayanahalli +- Initial prototype for RH/FC5 diff --git a/sources b/sources index e69de29..7d706f8 100644 --- a/sources +++ b/sources @@ -0,0 +1 @@ +b4f7ffcc294d41a6a4c40d6e44b7734d kexec-tools-1.101.tar.gz