1512 lines
51 KiB
Diff
1512 lines
51 KiB
Diff
|
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 <stdio.h>
|
||
|
+#include <string.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <limits.h>
|
||
|
+#include <elf.h>
|
||
|
+#include "../../kexec.h"
|
||
|
+#include "../../kexec-elf.h"
|
||
|
+#include "../../kexec-syscall.h"
|
||
|
+#include "kexec-x86.h"
|
||
|
+#include "crashdump-x86.h"
|
||
|
+#include <x86/x86-linux.h>
|
||
|
+
|
||
|
+#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 <elf.h>
|
||
|
#include <x86/x86-linux.h>
|
||
|
#include "../../kexec.h"
|
||
|
+#include "../../kexec-syscall.h"
|
||
|
#include "../../kexec-elf.h"
|
||
|
#include "../../kexec-elf-boot.h"
|
||
|
#include "x86-linux-setup.h"
|
||
|
#include "kexec-x86.h"
|
||
|
+#include "crashdump-x86.h"
|
||
|
#include <arch/options.h>
|
||
|
|
||
|
static const int probe_debug = 0;
|
||
|
@@ -86,7 +88,9 @@ int elf_x86_load(int argc, char **argv,
|
||
|
{
|
||
|
struct mem_ehdr ehdr;
|
||
|
const char *command_line;
|
||
|
+ char *modified_cmdline;
|
||
|
int command_line_len;
|
||
|
+ int modified_cmdline_len;
|
||
|
const char *ramdisk;
|
||
|
unsigned long entry, max_addr;
|
||
|
int arg_style;
|
||
|
@@ -119,6 +123,8 @@ int elf_x86_load(int argc, char **argv,
|
||
|
*/
|
||
|
arg_style = ARG_STYLE_ELF;
|
||
|
command_line = 0;
|
||
|
+ modified_cmdline = 0;
|
||
|
+ modified_cmdline_len = 0;
|
||
|
ramdisk = 0;
|
||
|
while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
|
||
|
switch(opt) {
|
||
|
@@ -156,6 +162,20 @@ int elf_x86_load(int argc, char **argv,
|
||
|
command_line_len = strlen(command_line) +1;
|
||
|
}
|
||
|
|
||
|
+ /* Need to append some command line parameters internally in case of
|
||
|
+ * taking crash dumps.
|
||
|
+ */
|
||
|
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
|
||
|
+ modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
|
||
|
+ memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
|
||
|
+ if (command_line) {
|
||
|
+ strncpy(modified_cmdline, command_line,
|
||
|
+ COMMAND_LINE_SIZE);
|
||
|
+ modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
|
||
|
+ }
|
||
|
+ modified_cmdline_len = strlen(modified_cmdline);
|
||
|
+ }
|
||
|
+
|
||
|
/* Load the ELF executable */
|
||
|
elf_exec_build_load(info, &ehdr, buf, len);
|
||
|
|
||
|
@@ -203,10 +223,20 @@ int elf_x86_load(int argc, char **argv,
|
||
|
const unsigned char *ramdisk_buf;
|
||
|
off_t ramdisk_length;
|
||
|
struct entry32_regs regs;
|
||
|
+ int rc = 0;
|
||
|
|
||
|
/* Get the linux parameter header */
|
||
|
hdr = xmalloc(sizeof(*hdr));
|
||
|
- param_base = add_buffer(info, hdr, sizeof(*hdr), sizeof(*hdr),
|
||
|
+
|
||
|
+ /* Hack: With some ld versions, vmlinux program headers show
|
||
|
+ * a gap of two pages between bss segment and data segment
|
||
|
+ * but effectively kernel considers it as bss segment and
|
||
|
+ * overwrites the any data placed there. Hence bloat the
|
||
|
+ * memsz of parameter segment to 16K to avoid being placed
|
||
|
+ * in such gaps.
|
||
|
+ * This is a makeshift solution until it is fixed in kernel
|
||
|
+ */
|
||
|
+ param_base = add_buffer(info, hdr, sizeof(*hdr), 16*1024,
|
||
|
16, 0, max_addr, 1);
|
||
|
|
||
|
/* Initialize the parameter header */
|
||
|
@@ -216,9 +246,19 @@ int elf_x86_load(int argc, char **argv,
|
||
|
/* Add a ramdisk to the current image */
|
||
|
ramdisk_buf = NULL;
|
||
|
ramdisk_length = 0;
|
||
|
- if (ramdisk) {
|
||
|
- unsigned char *ramdisk_buf;
|
||
|
+ if (ramdisk)
|
||
|
ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
|
||
|
+
|
||
|
+ /* If panic kernel is being loaded, additional segments need
|
||
|
+ * to be created. */
|
||
|
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
|
||
|
+ rc = load_crashdump_segments(info, modified_cmdline,
|
||
|
+ max_addr, 0);
|
||
|
+ if (rc < 0)
|
||
|
+ return -1;
|
||
|
+ /* Use new command line. */
|
||
|
+ command_line = modified_cmdline;
|
||
|
+ command_line_len = strlen(modified_cmdline) + 1;
|
||
|
}
|
||
|
|
||
|
/* Tell the kernel what is going on */
|
||
|
@@ -228,7 +268,7 @@ int elf_x86_load(int argc, char **argv,
|
||
|
ramdisk_buf, ramdisk_length);
|
||
|
|
||
|
/* Fill in the information bios calls would usually provide */
|
||
|
- setup_linux_system_parameters(&hdr->hdr);
|
||
|
+ setup_linux_system_parameters(&hdr->hdr, info->kexec_flags);
|
||
|
|
||
|
/* Initialize the registers */
|
||
|
elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®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 <arch/options.h>
|
||
|
|
||
|
-#define MAX_MEMORY_RANGES 64
|
||
|
#define MAX_LINE 160
|
||
|
+
|
||
|
static struct memory_range memory_range[MAX_MEMORY_RANGES];
|
||
|
|
||
|
/* Return a sorted list of memory ranges. */
|
||
|
-int get_memory_ranges(struct memory_range **range, int *ranges)
|
||
|
+int get_memory_ranges(struct memory_range **range, int *ranges,
|
||
|
+ unsigned long kexec_flags)
|
||
|
{
|
||
|
const char iomem[]= "/proc/iomem";
|
||
|
int memory_ranges = 0;
|
||
|
@@ -79,6 +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=<buad_rate> Specify the serial port baud rate\n"
|
||
|
" --console-vga Enable the vga console\n"
|
||
|
" --console-serial Enable the serial console\n"
|
||
|
+ " --elf32-core-headers Prepare core headers in ELF32 format\n"
|
||
|
+ " --elf64-core-headers Prepare core headers in ELF64 format\n"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
-static struct {
|
||
|
- uint8_t reset_vga;
|
||
|
- uint16_t serial_base;
|
||
|
- uint32_t serial_baud;
|
||
|
- uint8_t console_vga;
|
||
|
- uint8_t console_serial;
|
||
|
-} arch_options = {
|
||
|
+struct arch_options_t arch_options = {
|
||
|
.reset_vga = 0,
|
||
|
.serial_base = 0x3f8,
|
||
|
.serial_baud = 0,
|
||
|
.console_vga = 0,
|
||
|
.console_serial = 0,
|
||
|
+ .core_header_type = CORE_TYPE_ELF64,
|
||
|
};
|
||
|
|
||
|
int arch_process_options(int argc, char **argv)
|
||
|
@@ -198,6 +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 <stdint.h>
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+#define BACKUP_REGION_SOURCE 0x00000000
|
||
|
+#define BACKUP_REGION_SIZE 0xa0000
|
||
|
+
|
||
|
+/* Backup region start gets set after /proc/iomem has been parsed. */
|
||
|
+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();
|
||
|
}
|