diff options
author | R Sharada <sharada@in.ibm.com> | 2006-07-27 10:45:21 -0600 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2006-07-27 10:45:21 -0600 |
commit | 34d39f48bb5534a3f48b942ca53f57e1c5f8e48d (patch) | |
tree | 8ade43d8a05f2b52ffe9a81d8af8c7b7b097a132 | |
parent | cf917def9fcb8bdc12e222b7751630669e59009e (diff) |
ppc64 kdump prepare device tree
This patch provides the extra functionality and features in
the flattened device-tree that is required for crashdump
functionality.
- create add_usable_mem_property in device-tree which is
used by the second kernel for booting with restricted
memory. This provides similar feature as the
memmap= option on other archs
- move initrd creation/modification code to putnode
- add code to prepare correct commandline for bootargs.
If "root=" option is not specified in user cmdline,
add it from existing bootargs
- include mem_rgns_t definition in kexec-ppc64.h. Move
initrd variables out to .c file
Signed-off-by: R Sharada <sharada@in.ibm.com>
Signed-off-by: Haren Myneni <hbabu@us.ibm.com>
Signed-off-by: Mohan Kumar M <mohan@in.ibm.com>
Signed-off-by: Maneesh Soni <maneesh@in.ibm.com>
-rw-r--r-- | kexec/arch/ppc64/crashdump-ppc64.h | 27 | ||||
-rw-r--r-- | kexec/arch/ppc64/fs2dt.c | 147 | ||||
-rw-r--r-- | kexec/arch/ppc64/kexec-elf-ppc64.c | 2 | ||||
-rw-r--r-- | kexec/arch/ppc64/kexec-ppc64.h | 10 |
4 files changed, 158 insertions, 28 deletions
diff --git a/kexec/arch/ppc64/crashdump-ppc64.h b/kexec/arch/ppc64/crashdump-ppc64.h new file mode 100644 index 0000000..e080cb3 --- /dev/null +++ b/kexec/arch/ppc64/crashdump-ppc64.h @@ -0,0 +1,27 @@ +#ifndef CRASHDUMP_PPC64_H +#define CRASHDUMP_PPC64_H + +void add_usable_mem_rgns(unsigned long long base, unsigned long long size); + +#define PAGE_OFFSET 0xC000000000000000 +#define KERNELBASE PAGE_OFFSET +#define VMALLOCBASE 0xD000000000000000 + +#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) + +#define MAXMEM (-KERNELBASE-VMALLOCBASE) + +#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 6) + +#define COMMAND_LINE_SIZE 512 /* from kernel */ +/* Backup Region, First 32K of System RAM. */ +#define BACKUP_START 0x0000 +#define BACKUP_END 0x8000 +#define BACKUP_SIZE (BACKUP_END - BACKUP_START + 1) + +#define KDUMP_BACKUP_LIMIT 0x8000 +#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1))) +#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1))) +#define PAGE_SIZE 4096 + +#endif /* CRASHDUMP_PPC64_H */ diff --git a/kexec/arch/ppc64/fs2dt.c b/kexec/arch/ppc64/fs2dt.c index 8d22b19..447da64 100644 --- a/kexec/arch/ppc64/fs2dt.c +++ b/kexec/arch/ppc64/fs2dt.c @@ -28,7 +28,9 @@ #include <string.h> #include <errno.h> #include <stdio.h> +#include "../../kexec.h" #include "kexec-ppc64.h" +#include "crashdump-ppc64.h" #define MAXPATH 1024 /* max path name length */ #define NAMESPACE 16384 /* max bytes for property names */ @@ -62,9 +64,12 @@ char propnames[NAMESPACE]; dvt dtstruct[TREEWORDS], *dt; unsigned long long mem_rsrv[2*MEMRESERVE]; -extern unsigned long initrd_base; -extern unsigned long initrd_size; static int initrd_found = 0; +static int crash_param = 0; +char local_cmdline[COMMAND_LINE_SIZE] = { "" }; +dvt *dt_len; /* changed len of modified cmdline in flat device-tree */ +extern mem_rgns_t usablemem_rgns; +struct bootblock bb[1]; void reserve(unsigned long long where, unsigned long long length) { @@ -88,26 +93,12 @@ void checkprop(char *name, dvt *data) err((void *)data, ERR_RESERVE); else if (!strcmp(name, "linux,rtas-base")) base = *data; - else if (!strcmp(name, "linux,initrd-start")) { - if (initrd_base) - *(unsigned long long *) data = initrd_base; - base = *(unsigned long long *)data; - initrd_found = 1; - } else if (!strcmp(name, "linux,tce-base")) base = *(unsigned long long *) data; else if (!strcmp(name, "rtas-size") || !strcmp(name, "linux,tce-size")) size = *data; - else if (!strcmp(name, "linux,initrd-end")) { - if (initrd_size) { - *(unsigned long long *) data = initrd_base + - initrd_size; - size = initrd_size; - } else - end = *(unsigned long long *)data; - initrd_found = 1; - } + if (size && end) err(name, ERR_RESERVE); if (base && size) { @@ -139,6 +130,67 @@ dvt propnum(const char *name) return offset; } +void add_usable_mem_property(int fd, int len) +{ + char fname[MAXPATH], *bname; + char buf[MAXBYTES +1]; + unsigned long ranges[2*MAX_MEMORY_RANGES]; + unsigned long long base, end, loc_base, loc_end; + int range, rlen = 0; + + strcpy(fname, pathname); + bname = strrchr(fname,'/'); + bname[0] = '\0'; + bname = strrchr(fname,'/'); + if (strncmp(bname, "/memory@", 8)) + return; + + lseek(fd, 0, SEEK_SET); + if (read(fd, buf, len) != len) + err(pathname, ERR_READ); + + base = ((unsigned long long *)buf)[0]; + end = base + ((unsigned long long *)buf)[1]; + + for (range = 0; range < usablemem_rgns.size; range++) { + loc_base = usablemem_rgns.ranges[range].start; + loc_end = usablemem_rgns.ranges[range].end; + if (loc_base >= base && loc_end <= end) { + ranges[rlen++] = loc_base; + ranges[rlen++] = loc_end - loc_base; + } else if (base < loc_end && end > loc_base) { + if (loc_base < base) + loc_base = base; + if (loc_end > end) + loc_end = end; + ranges[rlen++] = loc_base; + ranges[rlen++] = loc_end - loc_base; + } + } + + if (!rlen) { + /* + * User did not pass any ranges for thsi region. Hence, write + * (0,0) duple in linux,usable-memory property such that + * this region will be ignored. + */ + ranges[rlen++] = 0; + ranges[rlen++] = 0; + } + + rlen = rlen * sizeof(unsigned long); + /* + * No add linux,usable-memory property. + */ + *dt++ = 3; + *dt++ = rlen; + *dt++ = propnum("linux,usable-memory"); + if ((rlen >= 8) && ((unsigned long)dt & 0x4)) + dt++; + memcpy(dt,&ranges,rlen); + dt += (rlen + 3)/4; +} + /* put all properties (files) in the property structure */ void putprops(char *fn, DIR *dir) { @@ -150,11 +202,10 @@ void putprops(char *fn, DIR *dir) if (lstat(pathname, statbuf)) err(pathname, ERR_STAT); - /* skip initrd entries if 2nd kernel does not need them */ - if (!initrd_base && !strcmp(fn,"linux,initrd-end")) + if (!crash_param && !strcmp(fn,"linux,crashkernel-base")) continue; - if (!initrd_base && !strcmp(fn,"linux,initrd-start")) + if (!crash_param && !strcmp(fn,"linux,crashkernel-size")) continue; /* @@ -165,12 +216,20 @@ void putprops(char *fn, DIR *dir) !strcmp(dp->d_name, "linux,htab-base") || !strcmp(dp->d_name, "linux,htab-size") || !strcmp(dp->d_name, "linux,kernel-end")) - continue; + continue; + + /* This property will be created/modified later in putnode() + * So ignore it. + */ + if (!strcmp(dp->d_name, "linux,initrd-start") || + !strcmp(dp->d_name, "linux,initrd-end")) + continue; if (S_ISREG(statbuf[0].st_mode)) { int fd, len = statbuf[0].st_size; *dt++ = 3; + dt_len = dt; *dt++ = len; *dt++ = propnum(fn); @@ -182,11 +241,45 @@ void putprops(char *fn, DIR *dir) err(pathname, ERR_OPEN); if (read(fd, dt, len) != len) err(pathname, ERR_READ); - close(fd); checkprop(fn, dt); + /* Get the cmdline from the device-tree and modify it */ + if (!strcmp(dp->d_name, "bootargs")) { + int cmd_len; + char temp_cmdline[COMMAND_LINE_SIZE] = { "" }; + char *param = NULL; + cmd_len = strlen(local_cmdline); + if (cmd_len != 0) { + param = strstr(local_cmdline, + "crashkernel="); + if (param) + crash_param = 1; + param = NULL; + param = strstr(local_cmdline, "root="); + } + if (!param) { + char *old_param; + memcpy(temp_cmdline, dt, len); + param = strstr(temp_cmdline, "root="); + old_param = strtok(param, " "); + if (cmd_len != 0) + strcat(local_cmdline, " "); + strcat(local_cmdline, old_param); + } + strcat(local_cmdline, " "); + cmd_len = strlen(local_cmdline); + cmd_len = cmd_len + 1; + memcpy(dt,local_cmdline,cmd_len); + len = cmd_len; + *dt_len = cmd_len; + fprintf(stderr, "Modified cmdline:%s\n", local_cmdline); + } + dt += (len + 3)/4; + if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size) + add_usable_mem_property(fd, len); + close(fd); } } fn[0] = '\0'; @@ -252,7 +345,7 @@ void putnode(void) if ((len >= 8) && ((unsigned long)dt & 0x4)) dt++; - memcpy(dt,&initrd_end,8); + memcpy(dt,&initrd_end,len); dt += (len + 3)/4; reserve(initrd_base, initrd_size); @@ -280,9 +373,8 @@ void putnode(void) dn[-1] = '\0'; } -struct bootblock bb[1]; - -int create_flatten_tree(struct kexec_info *info, unsigned char **bufp, unsigned long *sizep) +int create_flatten_tree(struct kexec_info *info, unsigned char **bufp, + unsigned long *sizep, char *cmdline) { unsigned long len; unsigned long tlen; @@ -296,6 +388,9 @@ int create_flatten_tree(struct kexec_info *info, unsigned char **bufp, unsigned pathstart = pathname + strlen(pathname); dt = dtstruct; + if (cmdline) + strcpy(local_cmdline, cmdline); + putnode(); *dt++ = 9; diff --git a/kexec/arch/ppc64/kexec-elf-ppc64.c b/kexec/arch/ppc64/kexec-elf-ppc64.c index 4423636..581b846 100644 --- a/kexec/arch/ppc64/kexec-elf-ppc64.c +++ b/kexec/arch/ppc64/kexec-elf-ppc64.c @@ -40,6 +40,8 @@ #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); diff --git a/kexec/arch/ppc64/kexec-ppc64.h b/kexec/arch/ppc64/kexec-ppc64.h index 6d04ff1..c6175a3 100644 --- a/kexec/arch/ppc64/kexec-ppc64.h +++ b/kexec/arch/ppc64/kexec-ppc64.h @@ -5,9 +5,9 @@ int elf_ppc64_probe(const char *buf, off_t len); int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void elf_ppc64_usage(void); +void reserve(unsigned long long where, unsigned long long length); -unsigned long initrd_base; -unsigned long initrd_size; +extern unsigned long initrd_base, initrd_size; /* boot block version 2 as defined by the linux kernel */ struct bootblock { unsigned magic, @@ -19,4 +19,10 @@ struct bootblock { last_comp_version, boot_physid; }; + +typedef struct mem_rgns { + unsigned int size; + struct exclude_range ranges[MAX_MEMORY_RANGES]; +} mem_rgns_t; + #endif /* KEXEC_PPC64_H */ |