In PPC64, kexec'ed kernel does not reserve memory for crashkernel. So kexec'ed kernel can not load kdump kernel reliably. reserve-crashkernel-mem patch adds a reserve entry for crashkernel to the reserve memory list, so that kexec'ed kernel reserves memory for kdump kernel. This is done when user passes --append="crashkernel=X@Y" parameter to kexec command. If user does not pass crashkernel option, memory is not reserved for kdump kernel. Signed-off-by: Mohan --- kexec-tools-1.101-kdump9/kexec/arch/ppc64/fs2dt.c | 135 ++++++++++++---- kexec-tools-1.101-kdump9/kexec/arch/ppc64/kexec-ppc64.h | 2 2 files changed, 107 insertions(+), 30 deletions(-) diff -puN kexec-tools-1.101-kdump9/kexec/arch/ppc64/fs2dt.c~reserve-crashkernel kexec-tools-1.101-kdump9/kexec/arch/ppc64/fs2dt.c --- patch/kexec-tools-1.101-kdump9/kexec/arch/ppc64/fs2dt.c~reserve-crashkernel 2006-04-19 18:49:06.000000000 +0530 +++ patch-mohan/kexec-tools-1.101-kdump9/kexec/arch/ppc64/fs2dt.c 2006-04-19 18:55:48.000000000 +0530 @@ -64,8 +64,7 @@ char propnames[NAMESPACE]; dvt dtstruct[TREEWORDS], *dt; unsigned long long mem_rsrv[2*MEMRESERVE]; -static int initrd_found = 0; -static int crash_param = 0; +static unsigned long crashk_base = 0, crashk_size = 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; @@ -191,6 +190,50 @@ void add_usable_mem_property(int fd, int dt += (rlen + 3)/4; } +unsigned long mem_parse(const char *ptr, const char **retptr) +{ + unsigned long ret = strtoul(ptr, (char **)retptr,10); + + switch (**retptr) { + case 'G': + case 'g': + ret <<= 30; + (*retptr)++; + break; + case 'M': + case 'm': + ret <<= 20; + (*retptr)++; + break; + case 'K': + case 'k': + ret <<= 10; + (*retptr)++; + break; + } + + return ret; +} + +void parse_crash_param(char *param) +{ + char *cbase, *csize; + param += 12; + crashk_size = mem_parse(param, (const char **)&csize); + + if (ALIGN(crashk_size, 0x1000000) != crashk_size) + printf("Warning: crashkernel size is not aligned to 16MB\n"); + + if (*csize == '@') { + csize++; + crashk_base = mem_parse(csize, (const char **)&cbase); + if (crashk_base != 0x2000000) + printf("Warning: PPC64 kdump kernel always runs at " + "32 MB\n"); + } + crashk_base = 0x2000000; +} + /* put all properties (files) in the property structure */ void putprops(char *fn, struct dirent **nlist, int numlist) { @@ -207,12 +250,6 @@ void putprops(char *fn, struct dirent ** if (lstat(pathname, statbuf)) err(pathname, ERR_STAT); - if (!crash_param && !strcmp(fn,"linux,crashkernel-base")) - continue; - - if (!crash_param && !strcmp(fn,"linux,crashkernel-size")) - continue; - /* * This property will be created for each node during kexec * boot. So, ignore it. @@ -230,6 +267,13 @@ void putprops(char *fn, struct dirent ** !strcmp(dp->d_name, "linux,initrd-end")) continue; + /* This property will be created/modified later in putnode() + * So ignore it. + */ + if (!strcmp(dp->d_name, "linux,crashkernel-base") || + !strcmp(dp->d_name, "linux,crashkernel-size")) + continue; + if (S_ISREG(statbuf[0].st_mode)) { int fd, len = statbuf[0].st_size; @@ -260,7 +304,7 @@ void putprops(char *fn, struct dirent ** param = strstr(local_cmdline, "crashkernel="); if (param) - crash_param = 1; + parse_crash_param(param); param = strstr(local_cmdline, "root="); } if (!param) { @@ -347,35 +391,66 @@ void putnode(void) putprops(dn, namelist, numlist); - /* Add initrd entries to the second kernel if first kernel does not - * have and second kernel needs. - */ - if (initrd_base && !initrd_found && !strcmp(basename,"/chosen/")) { + if (!strcmp(basename,"/chosen/")) { int len = 8; unsigned long long initrd_end; - *dt++ = 3; - *dt++ = len; - *dt++ = propnum("linux,initrd-start"); - if ((len >= 8) && ((unsigned long)dt & 0x4)) - dt++; + /* Add initrd entries to the second kernel if first + * kernel does not have and second kernel needs. + */ + if (initrd_base) { + *dt++ = 3; + *dt++ = len; + *dt++ = propnum("linux,initrd-start"); + + if ((len >= 8) && ((unsigned long)dt & 0x4)) + dt++; + + memcpy(dt,&initrd_base,len); + dt += (len + 3)/4; + + len = 8; + *dt++ = 3; + *dt++ = len; + *dt++ = propnum("linux,initrd-end"); + + initrd_end = initrd_base + initrd_size; + if ((len >= 8) && ((unsigned long)dt & 0x4)) + dt++; + + memcpy(dt,&initrd_end,len); + dt += (len + 3)/4; + + reserve(initrd_base, initrd_size); + } + + /* Add crashkernel details to the second kernel if first + * kernel does not have and reserve memory for that + */ + if (crashk_base) { + *dt++ = 3; + *dt++ = len; + *dt++ = propnum("linux,crashkernel-base"); - memcpy(dt,&initrd_base,len); - dt += (len + 3)/4; + if ((len >= 8) && ((unsigned long)dt & 0x4)) + dt++; - len = 8; - *dt++ = 3; - *dt++ = len; - *dt++ = propnum("linux,initrd-end"); + memcpy(dt,&crashk_base,len); + dt += (len + 3)/4; - initrd_end = initrd_base + initrd_size; - if ((len >= 8) && ((unsigned long)dt & 0x4)) - dt++; + len = 8; + *dt++ = 3; + *dt++ = len; + *dt++ = propnum("linux,crashkernel-size"); + + if ((len >= 8) && ((unsigned long)dt & 0x4)) + dt++; - memcpy(dt,&initrd_end,len); - dt += (len + 3)/4; + memcpy(dt,&crashk_size,len); + dt += (len + 3)/4; - reserve(initrd_base, initrd_size); + reserve(crashk_base, crashk_size); + } } for (i=0; i < numlist; i++) { diff -puN kexec-tools-1.101-kdump9/kexec/arch/ppc64/kexec-ppc64.h~reserve-crashkernel kexec-tools-1.101-kdump9/kexec/arch/ppc64/kexec-ppc64.h --- patch/kexec-tools-1.101-kdump9/kexec/arch/ppc64/kexec-ppc64.h~reserve-crashkernel 2006-04-19 18:49:54.000000000 +0530 +++ patch-mohan/kexec-tools-1.101-kdump9/kexec/arch/ppc64/kexec-ppc64.h 2006-04-19 18:50:29.000000000 +0530 @@ -7,6 +7,8 @@ #define CORE_TYPE_ELF32 1 #define CORE_TYPE_ELF64 2 +#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) + int setup_memory_ranges(unsigned long kexec_flags); int elf_ppc64_probe(const char *buf, off_t len); _