[PATCH 4/6] ppc64-kdump-crash-segments-support.patch
R Sharada
sharada at in.ibm.com
Tue Jan 17 02:12:45 EST 2006
This patch provides the basic functionality for
loading crash dump segment and required features.
- Code for loading the crashdump segments
- It modifies the crash dump cmdline parameter to
add the new parameters, elfcorehdr and savemaxmem
- other miscellaneous cleanups and re-ordering
of some existing code in kexec-elf-ppc64.c
Signed-off-by: R Sharada <sharada at in.ibm.com>
---
diff -puN kexec/arch/ppc64/kexec-elf-ppc64.c~ppc64-kdump-crash-segments-support kexec/arch/ppc64/kexec-elf-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-ppc64.c~ppc64-kdump-crash-segments-support 2006-01-15 08:11:27.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-elf-ppc64.c 2006-01-15 08:38:42.000000000 +0530
@@ -33,18 +33,18 @@
#include <linux/elf.h>
#include "../../kexec.h"
#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
#include "kexec-ppc64.h"
+#include "crashdump-ppc64.h"
#include <arch/options.h>
#define BOOTLOADER "kexec"
#define BOOTLOADER_VERSION VERSION
-#define MAX_COMMAND_LINE 256
unsigned long initrd_base, initrd_size;
-int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *);
-int parse_options(char *);
-int setup_memory_ranges(void);
+int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *,
+ char *);
int elf_ppc64_probe(const char *buf, off_t len)
{
@@ -68,23 +68,29 @@ int elf_ppc64_probe(const char *buf, off
}
int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
- struct kexec_info *info)
+ struct kexec_info *info)
{
struct mem_ehdr ehdr;
- const char *command_line;
- const char *input_options;
- int command_line_len;
- const char *ramdisk;
- const char *devicetreeblob;
- unsigned long *lp;
- int result;
- int opt;
+ char *cmdline, *modified_cmdline;
+ const char *ramdisk, *devicetreeblob;
+ int cmdline_len, modified_cmdline_len;
+ unsigned long long max_addr, hole_addr;
+ unsigned char *seg_buf = NULL;
+ off_t seg_size = 0;
+ struct mem_phdr *phdr;
+ size_t size;
+ unsigned long long *rsvmap_ptr;
+ struct bootblock *bb_ptr;
+ unsigned int nr_segments, i;
+ int result, opt;
+
#define OPT_APPEND (OPT_ARCH_MAX+0)
#define OPT_RAMDISK (OPT_ARCH_MAX+1)
#define OPT_DEVICETREEBLOB (OPT_ARCH_MAX+2)
static const struct option options[] = {
KEXEC_ARCH_OPTIONS
+ { "command-line", 1, NULL, OPT_APPEND },
{ "append", 1, NULL, OPT_APPEND },
{ "ramdisk", 1, NULL, OPT_RAMDISK },
{ "devicetreeblob", 1, NULL, OPT_DEVICETREEBLOB },
@@ -96,23 +102,24 @@ int elf_ppc64_load(int argc, char **argv
/* Parse command line arguments */
initrd_base = 0;
initrd_size = 0;
- command_line = 0;
- input_options = 0;
+ cmdline = 0;
ramdisk = 0;
devicetreeblob = 0;
+ max_addr = 0xFFFFFFFFFFFFFFFFUL;
+ hole_addr = 0;
- while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
+ while ((opt = getopt_long(argc, argv, short_options,
+ options, 0)) != -1) {
switch (opt) {
default:
/* Ignore core options */
- if (opt < OPT_ARCH_MAX) {
+ if (opt < OPT_ARCH_MAX)
break;
- }
case '?':
usage();
return -1;
case OPT_APPEND:
- input_options = optarg;
+ cmdline = optarg;
break;
case OPT_RAMDISK:
ramdisk = optarg;
@@ -123,13 +130,24 @@ int elf_ppc64_load(int argc, char **argv
}
}
- command_line_len = 0;
- if (command_line) {
- command_line_len = strlen(command_line) + 1;
- }
+ cmdline_len = 0;
+ if (cmdline)
+ cmdline_len = strlen(cmdline) + 1;
+
+ setup_memory_ranges(info->kexec_flags);
- if (input_options)
- parse_options(input_options);
+ /* 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 (cmdline) {
+ strncpy(modified_cmdline, cmdline, COMMAND_LINE_SIZE);
+ modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+ }
+ modified_cmdline_len = strlen(modified_cmdline);
+ }
/* Parse the Elf file */
result = build_elf_exec_info(buf, len, &ehdr);
@@ -138,25 +156,19 @@ int elf_ppc64_load(int argc, char **argv
return result;
}
- /* Load the Elf data */
- setup_memory_ranges();
/* Load the Elf data. Physical load addresses in elf64 header do not
* show up correctly. Use user supplied address for now to patch the
* elf header
*/
- unsigned long long base_addr;
- struct mem_phdr *phdr;
- size_t size;
phdr = &ehdr.e_phdr[0];
size = phdr->p_filesz;
- if (size > phdr->p_memsz) {
+ if (size > phdr->p_memsz)
size = phdr->p_memsz;
- }
- base_addr = (unsigned long)locate_hole(info, size, 0, 0,
+ hole_addr = (unsigned long)locate_hole(info, size, 0, 0,
0xFFFFFFFFFFFFFFFFUL, 1);
- ehdr.e_phdr[0].p_paddr = base_addr;
+ ehdr.e_phdr[0].p_paddr = hole_addr;
result = elf_exec_load(&ehdr, info);
if (result < 0) {
free_elf_info(&ehdr);
@@ -165,10 +177,10 @@ int elf_ppc64_load(int argc, char **argv
/* Add a ram-disk to the current image */
if (ramdisk) {
- if (devicetreeblob) {
- fprintf(stderr, "Can't use ramdisk with device tree blob input\n");
- return -1;
- }
+ if (devicetreeblob) {
+ fprintf(stderr, "Can't use ramdisk with device tree blob input\n");
+ return -1;
+ }
unsigned char *ramdisk_buf = NULL;
off_t ramdisk_size = 0;
unsigned long long ramdisk_addr;
@@ -181,6 +193,19 @@ int elf_ppc64_load(int argc, char **argv
initrd_size = ramdisk_size;
}
+ /* If panic kernel is being loaded, additional segments need
+ * to be created.
+ */
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ result = load_crashdump_segments(info, modified_cmdline,
+ max_addr, 0);
+ if (result < 0)
+ return -1;
+ /* Use new command line. */
+ cmdline = modified_cmdline;
+ cmdline_len = strlen(modified_cmdline) + 1;
+ }
+
/* Add v2wrap to the current image */
unsigned char *v2wrap_buf = NULL;
off_t v2wrap_size = 0;
@@ -229,7 +254,7 @@ int elf_ppc64_load(int argc, char **argv
rsvmap_ptr += 2;
}
rsvmap_ptr -= 2;
- *rsvmap_ptr = (unsigned long long)(
+ *rsvmap_ptr = (unsigned long long)(
info->segment[(info->nr_segments)-1].mem + 0x100);
rsvmap_ptr++;
*rsvmap_ptr = (unsigned long long)bb_ptr->totalsize;
@@ -252,67 +277,3 @@ void elf_ppc64_usage(void)
{
fprintf(stderr, "elf support is still broken\n");
}
-
-struct param_struct {
- const char *name;
- void *val;
-};
-struct param_struct params;
-
-static char *next_arg(char *args, char **param, char **val)
-{
- unsigned int i, equals = 0;
- char *next;
-
- /* Chew any extra spaces */
- while (*args == ' ') args++;
- for (i = 0; args[i]; i++) {
- if (args[i] == ' ')
- break;
- if (equals == 0) {
- if (args[i] == '=')
- equals = i;
- }
- }
- *param = args;
- if (!equals)
- *val = NULL;
- else {
- args[equals] = '\0';
- *val = args + equals + 1;
- }
-
- if (args[i]) {
- args[i] = '\0';
- next = args + i + 1;
- } else
- next = args + i;
- return next;
-}
-
-static int add_arg(char *param, char*val)
-{
- int ret = 0;
- if (strcmp(param, "initrd-base")==0)
- initrd_base=strtoul(val, NULL, 0);
- else if (strcmp(param, "initrd-size")==0)
- initrd_size=strtoul(val, NULL, 0);
- else {
- printf("invalid option\n");
- ret = 1;
- }
- return ret;
-}
-
-int parse_options(char *options)
-{
- char *param, *val;
- /* initrd-addr , initrd-size */
- while (*options) {
- int ret;
- options = next_arg(options, ¶m, &val);
- ret = add_arg(param, val);
- }
- /* All parsed OK */
- return 0;
-}
diff -puN kexec/arch/ppc64/Makefile~ppc64-kdump-crash-segments-support kexec/arch/ppc64/Makefile
--- kexec-tools-1.101/kexec/arch/ppc64/Makefile~ppc64-kdump-crash-segments-support 2006-01-15 08:14:47.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/Makefile 2006-01-15 08:15:40.000000000 +0530
@@ -6,5 +6,6 @@ KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-zI
KEXEC_C_SRCS+= kexec/arch/ppc64/fs2dt.c
KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-elf-ppc64.c
KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-ppc64.c
+KEXEC_C_SRCS+= kexec/arch/ppc64/crashdump-ppc64.c
KEXEC_S_SRCS+=
diff -puN kexec/arch/ppc64/crashdump-ppc64.c~ppc64-kdump-crash-segments-support kexec/arch/ppc64/crashdump-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/crashdump-ppc64.c~ppc64-kdump-crash-segments-support 2006-01-15 08:40:23.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/crashdump-ppc64.c 2006-01-15 09:11:45.000000000 +0530
@@ -31,6 +31,8 @@
#include "kexec-ppc64.h"
#include "crashdump-ppc64.h"
+extern struct arch_options_t arch_options;
+
/* Stores a sorted list of RAM memory ranges for which to create elf headers.
* A separate program header is created for backup region
*/
@@ -45,6 +47,17 @@ mem_rgns_t usablemem_rgns = {0, };
/* array to store memory regions to be excluded from elf header creation */
mem_rgns_t exclude_rgns = {0, };
+/*
+ * To store the memory size of the first kernel and this value will be
+ * passed to the second kernel as command line (savemaxmem=xM).
+ * The second kernel will be calculated saved_max_pfn based on this
+ * variable.
+ * Since we are creating/using usable-memory property, there is no way
+ * we can determine the RAM size unless parsing the device-tree/memoy@/reg
+ * property in the kernel.
+ */
+unsigned long saved_max_mem = 0;
+
static int sort_regions(mem_rgns_t *rgn);
/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
@@ -192,6 +205,116 @@ static int get_crash_memory_ranges(struc
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;
+ }
+}
+
+static int add_cmdline_param(char *cmdline, unsigned long addr,
+ char *cmdstr, char *byte)
+{
+ int cmdlen, len, align = 1024;
+ char str[COMMAND_LINE_SIZE], *ptr;
+
+ /* Passing in =xxxK / =xxxM format. Saves space required in cmdline.*/
+ switch (byte[0]) {
+ case 'K':
+ if (addr%align)
+ return -1;
+ addr = addr/align;
+ break;
+ case 'M':
+ addr = addr/(align *align);
+ break;
+ }
+ ptr = str;
+ strcpy(str, cmdstr);
+ ptr += strlen(str);
+ ultoa(addr, ptr);
+ strcat(str, byte);
+ len = strlen(str);
+ cmdlen = strlen(cmdline) + len;
+ if (cmdlen > (COMMAND_LINE_SIZE - 1))
+ die("Command line overflow\n");
+ strcat(cmdline, str);
+#if DEBUG
+ fprintf(stderr, "Command line after adding elfcorehdr: %s\n", cmdline);
+#endif
+ 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;
+
+ if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
+ return -1;
+
+ /* 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);
+ reserve(info->backup_start, sz);
+ /* 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;
+ }
+
+ elfcorehdr = add_buffer(info, tmp, sz, sz, align, min_base,
+ max_addr, 1);
+ reserve(elfcorehdr, sz);
+ /* modify and store the cmdline in a global array. This is later
+ * read by flatten_device_tree and modified if required
+ */
+ add_cmdline_param(mod_cmdline, elfcorehdr, " elfcorehdr=", "K");
+ add_cmdline_param(mod_cmdline, saved_max_mem, " savemaxmem=", "M");
+ return 0;
+}
+
/*
* Used to save various memory regions needed for the captured kernel.
*/
_
More information about the Linuxppc64-dev
mailing list