diff -Nrup kexec-tools-2.0.0.orig/include/x86/x86-linux.h kexec-tools-2.0.0/include/x86/x86-linux.h --- kexec-tools-2.0.0.orig/include/x86/x86-linux.h 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/include/x86/x86-linux.h 2011-03-16 20:19:19.000000000 +0800 @@ -194,7 +194,7 @@ struct x86_linux_param_header { uint8_t _pad8[48]; /* 0xcd0 */ struct edd_info eddbuf[EDDMAXNR]; /* 0xd00 */ /* 0xeec */ -#define COMMAND_LINE_SIZE 2048 +#define COMMAND_LINE_SIZE 8*1024 }; struct x86_linux_faked_param_header { diff -Nrup kexec-tools-2.0.0.orig/kexec/arch/i386/crashdump-x86.c kexec-tools-2.0.0/kexec/arch/i386/crashdump-x86.c --- kexec-tools-2.0.0.orig/kexec/arch/i386/crashdump-x86.c 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/kexec/arch/i386/crashdump-x86.c 2011-03-16 21:09:56.000000000 +0800 @@ -536,6 +536,49 @@ static enum coretype get_core_type(struc } } +static void get_backup_area(unsigned long *start, unsigned long *end) +{ + const char *iomem = proc_iomem(); + char line[MAX_LINE]; + FILE *fp; + + fp = fopen(iomem, "r"); + if (!fp) { + fprintf(stderr, "Cannot open %s: %s\n", + iomem, strerror(errno)); + return; + } + + while(fgets(line, sizeof(line), fp) != 0) { + char *str; + int count, consumed; + unsigned long mstart, mend; + + count = sscanf(line, "%lx-%lx : %n", + &mstart, &mend, &consumed); + if (count != 2) + continue; + str = line + consumed; +#ifdef DEBUG + printf("%016lx-%016lx : %s", + mstart, mend, str); +#endif + /* Hopefully there is only one RAM region in the first 640K */ + if (memcmp(str, "System RAM\n", 11) == 0 && mend <= 0xa0000 ) { +#ifdef DEBUG + printf("%s: %016lx-%016lx : %s", __func__, mstart, mend, str); +#endif + *start = mstart; + *end = mend; + fclose(fp); + return; + } + } + *start = BACKUP_SRC_START; + *end = BACKUP_SRC_END; + fclose(fp); +} + /* 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. @@ -548,6 +591,10 @@ int load_crashdump_segments(struct kexec int nr_ranges, align = 1024; struct memory_range *mem_range, *memmap_p; int i; + unsigned long tmp_backup_end; + + get_backup_area(&info->backup_src_start, &tmp_backup_end); + info->backup_src_size = tmp_backup_end - info->backup_src_start + 1; if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0) return -1; @@ -565,7 +612,7 @@ int load_crashdump_segments(struct kexec sz = (sizeof(struct memory_range) * (KEXEC_MAX_SEGMENTS + 1)); memmap_p = xmalloc(sz); memset(memmap_p, 0, sz); - add_memmap(memmap_p, BACKUP_SRC_START, BACKUP_SRC_SIZE, RANGE_RAM); + add_memmap(memmap_p, info->backup_src_start, info->backup_src_size, RANGE_RAM); sz = crash_reserved_mem.end - crash_reserved_mem.start +1; add_memmap(memmap_p, crash_reserved_mem.start, sz, RANGE_RAM); @@ -580,7 +627,7 @@ int load_crashdump_segments(struct kexec } /* Create a backup region segment to store backup data*/ - sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1); + sz = (info->backup_src_size + align - 1) & ~(align - 1); tmp = xmalloc(sz); memset(tmp, 0, sz); info->backup_start = add_buffer(info, tmp, sz, sz, align, diff -Nrup kexec-tools-2.0.0.orig/kexec/arch/i386/kexec-x86-common.c kexec-tools-2.0.0/kexec/arch/i386/kexec-x86-common.c --- kexec-tools-2.0.0.orig/kexec/arch/i386/kexec-x86-common.c 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/kexec/arch/i386/kexec-x86-common.c 2011-03-16 20:18:29.000000000 +0800 @@ -128,6 +128,78 @@ static int get_memory_ranges_sysfs(struc return 0; } +static void remove_range(struct memory_range *range, int nr_ranges, int index) +{ + int i, j; + + for (i = index; i < (nr_ranges-1); i++) { + j = i+1; + range[i] = range[j]; + } +} + +/** + * Verifies and corrects any overlapping ranges. + * The ranges array is assumed to be sorted already. + * + * @param[out] range pointer that will be set to an array that holds the + * memory ranges + * @param[out] ranges number of ranges valid in @p range + * + * @return 0 on success, any other value on failure. + */ +static int fixup_memory_ranges_sysfs(struct memory_range **range, int *ranges) +{ + int i; + int j; + int change_made; + int nr_ranges = *ranges; + struct memory_range *rp = *range; + +again: + change_made = 0; + for (i = 0; i < (nr_ranges-1); i++) { + j = i+1; + if (rp[i].start > rp[j].start) { + fprintf(stderr, "sysfs memory out of order!!\n"); + return 1; + } + + if (rp[i].type != rp[j].type) + continue; + + if (rp[i].start == rp[j].start) { + if (rp[i].end >= rp[j].end) { + remove_range(rp, nr_ranges, j); + nr_ranges--; + change_made++; + } else { + remove_range(rp, nr_ranges, i); + nr_ranges--; + change_made++; + } + } else { + if (rp[i].end > rp[j].start) { + if (rp[i].end < rp[j].end) { + rp[j].start = rp[i].end; + change_made++; + } else if (rp[i].end >= rp[j].end) { + remove_range(rp, nr_ranges, j); + nr_ranges--; + change_made++; + } + } + } + } + + /* fixing/removing an entry may make it wrong relative to the next */ + if (change_made) + goto again; + + *ranges = nr_ranges; + return 0; +} + /** * Return a sorted list of memory ranges. * @@ -147,9 +219,11 @@ int get_memory_ranges(struct memory_rang { int ret, i; - if (have_sys_firmware_memmap()) + if (have_sys_firmware_memmap()) { ret = get_memory_ranges_sysfs(range, ranges); - else + if (!ret) + ret = fixup_memory_ranges_sysfs(range, ranges); + } else ret = get_memory_ranges_proc_iomem(range, ranges); /* diff -Nrup kexec-tools-2.0.0.orig/kexec/arch/i386/x86-linux-setup.c kexec-tools-2.0.0/kexec/arch/i386/x86-linux-setup.c --- kexec-tools-2.0.0.orig/kexec/arch/i386/x86-linux-setup.c 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/kexec/arch/i386/x86-linux-setup.c 2011-03-16 20:19:08.000000000 +0800 @@ -404,6 +404,7 @@ void setup_linux_system_parameters(struc struct memory_range *range; int i, ranges; int boot_param_fd; + int sgi_uv_fd; /* Default screen size */ real_mode->orig_x = 0; @@ -432,7 +433,8 @@ void setup_linux_system_parameters(struc memset(&real_mode->efi_info, 0, sizeof(struct efi_info)); /* check to see if we're running an EFI firmware here */ boot_param_fd = open("/sys/kernel/debug/boot_params/data", O_RDONLY); - if (boot_param_fd > 0) { + sgi_uv_fd = open("/proc/sgi_uv", O_RDONLY); + if (boot_param_fd > 0 && sgi_uv_fd < 0) { int rc; lseek(boot_param_fd, 0x1c0, SEEK_SET); rc = read(boot_param_fd, &real_mode->efi_info, @@ -440,7 +442,9 @@ void setup_linux_system_parameters(struc if (rc != sizeof(struct efi_info)) printf("ERROR READING EFI INFO\n"); close(boot_param_fd); - } else + } else if (sgi_uv_fd >= 0) + close(sgi_uv_fd); + else printf("UNABLE TO GATHER EFI DATA\n"); /* default yes: this can be overridden on the command line */ diff -Nrup kexec-tools-2.0.0.orig/kexec/arch/x86_64/crashdump-x86_64.c kexec-tools-2.0.0/kexec/arch/x86_64/crashdump-x86_64.c --- kexec-tools-2.0.0.orig/kexec/arch/x86_64/crashdump-x86_64.c 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/kexec/arch/x86_64/crashdump-x86_64.c 2011-03-16 21:33:05.000000000 +0800 @@ -177,13 +177,6 @@ static int get_crash_memory_ranges(struc 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; @@ -231,10 +224,6 @@ static int get_crash_memory_ranges(struc 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; @@ -271,6 +260,9 @@ static int exclude_region(int *nr_ranges { int i, j, tidx = -1; struct memory_range temp_region; + temp_region.start = 0; + temp_region.end = 0; + temp_region.type = 0; for (i = 0; i < (*nr_ranges); i++) { unsigned long long mstart, mend; @@ -406,6 +398,7 @@ static int delete_memmap(struct memory_r memmap_p[i].end = addr - 1; temp_region.start = addr + size; temp_region.end = mend; + temp_region.type = memmap_p[i].type; operation = 1; tidx = i; break; @@ -579,6 +572,49 @@ static int cmdline_add_memmap_type(char return 0; } +static void get_backup_area(unsigned long *start, unsigned long *end) +{ + const char *iomem = proc_iomem(); + char line[MAX_LINE]; + FILE *fp; + + fp = fopen(iomem, "r"); + if (!fp) { + fprintf(stderr, "Cannot open %s: %s\n", + iomem, strerror(errno)); + return; + } + + while(fgets(line, sizeof(line), fp) != 0) { + char *str; + int count, consumed; + unsigned long mstart, mend; + + count = sscanf(line, "%lx-%lx : %n", + &mstart, &mend, &consumed); + if (count != 2) + continue; + str = line + consumed; +#ifdef DEBUG + printf("%016lx-%016lx : %s", + mstart, mend, str); +#endif + /* Hopefully there is only one RAM region in the first 640K */ + if (memcmp(str, "System RAM\n", 11) == 0 && mend <= 0xa0000 ) { +#ifdef DEBUG + printf("%s: %016lx-%016lx : %s", __func__, mstart, mend, str); +#endif + *start = mstart; + *end = mend; + fclose(fp); + return; + } + } + *start = BACKUP_SRC_START; + *end = BACKUP_SRC_END; + fclose(fp); +} + /* 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. @@ -590,6 +626,10 @@ int load_crashdump_segments(struct kexec unsigned long sz, bufsz, memsz, elfcorehdr; int nr_ranges, align = 1024, i; struct memory_range *mem_range, *memmap_p; + unsigned long tmp_backup_end; + + get_backup_area(&info->backup_src_start, &tmp_backup_end); + info->backup_src_size = tmp_backup_end - info->backup_src_start + 1; if (get_kernel_paddr(info)) return -1; @@ -604,12 +644,12 @@ int load_crashdump_segments(struct kexec sz = (sizeof(struct memory_range) * (KEXEC_MAX_SEGMENTS + 1)); memmap_p = xmalloc(sz); memset(memmap_p, 0, sz); - add_memmap(memmap_p, BACKUP_SRC_START, BACKUP_SRC_SIZE); + add_memmap(memmap_p, info->backup_src_start, info->backup_src_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_SRC_SIZE + align - 1) & ~(align - 1); + sz = (info->backup_src_size + align - 1) & ~(align - 1); tmp = xmalloc(sz); memset(tmp, 0, sz); info->backup_start = add_buffer(info, tmp, sz, sz, align, diff -Nrup kexec-tools-2.0.0.orig/kexec/arch/x86_64/kexec-x86_64.c kexec-tools-2.0.0/kexec/arch/x86_64/kexec-x86_64.c --- kexec-tools-2.0.0.orig/kexec/arch/x86_64/kexec-x86_64.c 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/kexec/arch/x86_64/kexec-x86_64.c 2011-03-16 20:54:24.000000000 +0800 @@ -167,6 +167,10 @@ 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)); + elf_rel_set_symbol(&info->rhdr, "backup_src_start", + &info->backup_src_start, sizeof(info->backup_src_start)); + elf_rel_set_symbol(&info->rhdr, "backup_src_size", + &info->backup_src_size, sizeof(info->backup_src_size)); if (info->kexec_flags & KEXEC_ON_CRASH) { panic_kernel = 1; diff -Nrup kexec-tools-2.0.0.orig/kexec/crashdump.h kexec-tools-2.0.0/kexec/crashdump.h --- kexec-tools-2.0.0.orig/kexec/crashdump.h 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/kexec/crashdump.h 2011-03-16 20:18:52.000000000 +0800 @@ -7,8 +7,8 @@ extern int get_xen_vmcoreinfo(uint64_t * /* Need to find a better way to determine per cpu notes section size. */ #define MAX_NOTE_BYTES 1024 -/* Expecting ELF headers to fit in 16K. Increase it if you need more. */ -#define KCORE_ELF_HEADERS_SIZE 16384 +/* Expecting ELF headers to fit in 32K. Increase it if you need more. */ +#define KCORE_ELF_HEADERS_SIZE 32768 /* The address of the ELF header is passed to the secondary kernel * using the kernel command line option memmap=nnn. * The smallest unit the kernel accepts is in kilobytes, diff -Nrup kexec-tools-2.0.0.orig/kexec/kexec.h kexec-tools-2.0.0/kexec/kexec.h --- kexec-tools-2.0.0.orig/kexec/kexec.h 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/kexec/kexec.h 2011-03-16 20:56:44.000000000 +0800 @@ -124,6 +124,8 @@ struct kexec_info { unsigned long kern_vaddr_start; unsigned long kern_paddr_start; unsigned long kern_size; + unsigned long backup_src_start; + unsigned long backup_src_size; }; struct arch_map_entry { diff -Nrup kexec-tools-2.0.0.orig/purgatory/arch/i386/crashdump_backup.c kexec-tools-2.0.0/purgatory/arch/i386/crashdump_backup.c --- kexec-tools-2.0.0.orig/purgatory/arch/i386/crashdump_backup.c 2011-03-16 20:17:26.000000000 +0800 +++ kexec-tools-2.0.0/purgatory/arch/i386/crashdump_backup.c 2011-03-16 20:54:24.000000000 +0800 @@ -20,13 +20,15 @@ #include #include -#include "../../../kexec/arch/i386/crashdump-x86.h" /* Backup region start gets set after /proc/iomem has been parsed. */ /* We reuse the same code for x86_64 also so changing backup_start to unsigned long */ unsigned long backup_start = 0; +unsigned long backup_src_start = 0; +unsigned long backup_src_size = 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. */ @@ -34,11 +36,16 @@ unsigned long backup_start = 0; void crashdump_backup_memory(void) { void *dest, *src; + size_t size; + + src = (void *) backup_src_start; + size = (size_t) backup_src_size; - src = (void *) BACKUP_SRC_START; + if (!size) + return; if (backup_start) { dest = (void *)(backup_start); - memcpy(dest, src, BACKUP_SRC_SIZE); + memcpy(dest, src, size); } }