diff -up kexec-tools-2.0.0/kexec/arch/ppc64/crashdump-ppc64.c.orig kexec-tools-2.0.0/kexec/arch/ppc64/crashdump-ppc64.c --- kexec-tools-2.0.0/kexec/arch/ppc64/crashdump-ppc64.c.orig 2010-06-02 09:19:34.000000000 -0400 +++ kexec-tools-2.0.0/kexec/arch/ppc64/crashdump-ppc64.c 2010-06-02 09:14:31.000000000 -0400 @@ -84,6 +84,90 @@ mem_rgns_t usablemem_rgns = {0, NULL}; */ uint64_t saved_max_mem = 0; +static unsigned long long cstart, cend; +static int memory_ranges; + +/* + * Exclude the region that lies within crashkernel + */ +static void exclude_crash_region(uint64_t start, uint64_t end) +{ + if (cstart < end && cend > start) { + if (start < cstart && end > cend) { + crash_memory_range[memory_ranges].start = start; + crash_memory_range[memory_ranges].end = cstart; + crash_memory_range[memory_ranges].type = RANGE_RAM; + memory_ranges++; + crash_memory_range[memory_ranges].start = cend; + crash_memory_range[memory_ranges].end = end; + crash_memory_range[memory_ranges].type = RANGE_RAM; + memory_ranges++; + } else if (start < cstart) { + crash_memory_range[memory_ranges].start = start; + crash_memory_range[memory_ranges].end = cstart; + crash_memory_range[memory_ranges].type = RANGE_RAM; + memory_ranges++; + } else if (end > cend) { + crash_memory_range[memory_ranges].start = cend; + crash_memory_range[memory_ranges].end = end; + crash_memory_range[memory_ranges].type = RANGE_RAM; + memory_ranges++; + } + } else { + crash_memory_range[memory_ranges].start = start; + crash_memory_range[memory_ranges].end = end; + crash_memory_range[memory_ranges].type = RANGE_RAM; + memory_ranges++; + } +} + +static int get_dyn_reconf_crash_memory_ranges() +{ + uint64_t start, end; + char fname[128], buf[32]; + FILE *file; + int i, n; + uint32_t flags; + + strcpy(fname, "/proc/device-tree/"); + strcat(fname, "ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory"); + if ((file = fopen(fname, "r")) == NULL) { + perror(fname); + return -1; + } + + fseek(file, 4, SEEK_SET); + for (i = 0; i < num_of_lmbs; i++) { + if ((n = fread(buf, 1, 24, file)) < 0) { + perror(fname); + fclose(file); + return -1; + } + if (memory_ranges >= (max_memory_ranges + 1)) { + /* No space to insert another element. */ + fprintf(stderr, + "Error: Number of crash memory ranges" + " excedeed the max limit\n"); + return -1; + } + + start = ((uint64_t *)buf)[DRCONF_ADDR]; + end = start + lmb_size; + if (start == 0 && end >= (BACKUP_SRC_END + 1)) + start = BACKUP_SRC_END + 1; + + flags = (*((uint32_t *)&buf[DRCONF_FLAGS])); + /* skip this block if the reserved bit is set in flags (0x80) + or if the block is not assigned to this partition (0x8) */ + if ((flags & 0x80) || !(flags & 0x8)) + continue; + + exclude_crash_region(start, end); + } + fclose(file); + return 0; +} + /* 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. @@ -98,7 +182,6 @@ uint64_t saved_max_mem = 0; static int get_crash_memory_ranges(struct memory_range **range, int *ranges) { - int memory_ranges = 0; char device_tree[256] = "/proc/device-tree/"; char fname[256]; char buf[MAXBYTES]; @@ -106,7 +189,7 @@ static int get_crash_memory_ranges(struc FILE *file; struct dirent *dentry, *mentry; int i, n, crash_rng_len = 0; - unsigned long long start, end, cstart, cend; + unsigned long long start, end; int page_size; crash_max_memory_ranges = max_memory_ranges + 6; @@ -129,7 +212,16 @@ static int get_crash_memory_ranges(struc perror(device_tree); goto err; } + + cstart = crash_base; + cend = crash_base + crash_size; + while ((dentry = readdir(dir)) != NULL) { + if (!strncmp(dentry->d_name, + "ibm,dynamic-reconfiguration-memory", 35)){ + get_dyn_reconf_crash_memory_ranges(); + continue; + } if (strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory")) continue; @@ -170,38 +262,7 @@ static int get_crash_memory_ranges(struc if (start == 0 && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; - cstart = crash_base; - cend = crash_base + crash_size; - /* - * Exclude the region that lies within crashkernel - */ - if (cstart < end && cend > start) { - if (start < cstart && end > cend) { - crash_memory_range[memory_ranges].start = start; - crash_memory_range[memory_ranges].end = cstart; - crash_memory_range[memory_ranges].type = RANGE_RAM; - memory_ranges++; - crash_memory_range[memory_ranges].start = cend; - crash_memory_range[memory_ranges].end = end; - crash_memory_range[memory_ranges].type = RANGE_RAM; - memory_ranges++; - } else if (start < cstart) { - crash_memory_range[memory_ranges].start = start; - crash_memory_range[memory_ranges].end = cstart; - crash_memory_range[memory_ranges].type = RANGE_RAM; - memory_ranges++; - } else if (end > cend){ - crash_memory_range[memory_ranges].start = cend; - crash_memory_range[memory_ranges].end = end; - crash_memory_range[memory_ranges].type = RANGE_RAM; - memory_ranges++; - } - } else { - crash_memory_range[memory_ranges].start = start; - crash_memory_range[memory_ranges].end = end; - crash_memory_range[memory_ranges].type = RANGE_RAM; - memory_ranges++; - } + exclude_crash_region(start, end); fclose(file); } closedir(dmem); diff -up kexec-tools-2.0.0/kexec/arch/ppc64/crashdump-ppc64.h.orig kexec-tools-2.0.0/kexec/arch/ppc64/crashdump-ppc64.h --- kexec-tools-2.0.0/kexec/arch/ppc64/crashdump-ppc64.h.orig 2010-06-02 09:19:34.000000000 -0400 +++ kexec-tools-2.0.0/kexec/arch/ppc64/crashdump-ppc64.h 2010-06-02 09:14:31.000000000 -0400 @@ -30,4 +30,10 @@ extern uint64_t crash_size; extern unsigned int rtas_base; extern unsigned int rtas_size; +uint64_t lmb_size; +unsigned int num_of_lmbs; + +#define DRCONF_ADDR 0 +#define DRCONF_FLAGS 20 + #endif /* CRASHDUMP_PPC64_H */ diff -up kexec-tools-2.0.0/kexec/arch/ppc64/fs2dt.c.orig kexec-tools-2.0.0/kexec/arch/ppc64/fs2dt.c --- kexec-tools-2.0.0/kexec/arch/ppc64/fs2dt.c.orig 2010-06-02 09:19:34.000000000 -0400 +++ kexec-tools-2.0.0/kexec/arch/ppc64/fs2dt.c 2010-06-02 09:14:08.000000000 -0400 @@ -122,6 +122,74 @@ static unsigned propnum(const char *name return offset; } +static void add_dyn_reconf_usable_mem_property(int fd) +{ + char fname[MAXPATH], *bname; + uint64_t buf[32]; + uint64_t ranges[2*MAX_MEMORY_RANGES]; + uint64_t base, end, loc_base, loc_end; + int range, rlen = 0, i; + int rngs_cnt, tmp_indx; + + strcpy(fname, pathname); + bname = strrchr(fname, '/'); + bname[0] = '\0'; + bname = strrchr(fname, '/'); + if (strncmp(bname, "/ibm,dynamic-reconfiguration-memory", 36)) + return; + + if (lseek(fd, 4, SEEK_SET) < 0) + die("unrecoverable error: error seeking in \"%s\": %s\n", + pathname, strerror(errno)); + + rlen = 0; + for (i = 0; i < num_of_lmbs; i++) { + if (read(fd, buf, 24) < 0) + die("unrecoverable error: error reading \"%s\": %s\n", + pathname, strerror(errno)); + + base = (uint64_t) buf[0]; + end = base + lmb_size; + if (~0ULL - base < end) + die("unrecoverable error: mem property overflow\n"); + + tmp_indx = rlen++; + + rngs_cnt = 0; + 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; + rngs_cnt++; + } 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; + rngs_cnt++; + } + } + /* Store the count of (base, size) duple */ + ranges[tmp_indx] = rngs_cnt; + } + + rlen = rlen * sizeof(uint64_t); + /* + * Add linux,drconf-usable-memory property. + */ + *dt++ = 3; + *dt++ = rlen; + *dt++ = propnum("linux,drconf-usable-memory"); + if ((rlen >= 8) && ((unsigned long)dt & 0x4)) + dt++; + memcpy(dt, &ranges, rlen); + dt += (rlen + 3)/4; +} + static void add_usable_mem_property(int fd, int len) { char fname[MAXPATH], *bname; @@ -267,6 +335,10 @@ static void putprops(char *fn, struct di dt += (len + 3)/4; if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size) add_usable_mem_property(fd, len); + if (!strcmp(dp->d_name, "ibm,dynamic-memory") && + usablemem_rgns.size) + add_dyn_reconf_usable_mem_property(fd); + close(fd); } diff -up kexec-tools-2.0.0/kexec/arch/ppc64/kexec-ppc64.c.orig kexec-tools-2.0.0/kexec/arch/ppc64/kexec-ppc64.c --- kexec-tools-2.0.0/kexec/arch/ppc64/kexec-ppc64.c.orig 2010-06-02 09:19:34.000000000 -0400 +++ kexec-tools-2.0.0/kexec/arch/ppc64/kexec-ppc64.c 2010-06-02 09:19:31.000000000 -0400 @@ -96,39 +96,109 @@ err1: } -/* - * Count the memory nodes under /proc/device-tree and populate the - * max_memory_ranges variable. This variable replaces MAX_MEMORY_RANGES - * macro used earlier. - */ -static int count_memory_ranges(void) +static int realloc_memory_ranges(void) { - char device_tree[256] = "/proc/device-tree/"; - struct dirent *dentry; - DIR *dir; + size_t memory_range_len; - if ((dir = opendir(device_tree)) == NULL) { - perror(device_tree); + max_memory_ranges++; + memory_range_len = sizeof(struct memory_range) * max_memory_ranges; + + memory_range = (struct memory_range *) realloc(memory_range, memory_range_len); + if (!memory_range) + goto err; + + base_memory_range = (struct memory_range *) realloc(base_memory_range, memory_range_len); + if (!base_memory_range) + goto err; + + exclude_range = (struct memory_range *) realloc(exclude_range, memory_range_len); + if (!exclude_range) + goto err; + + usablemem_rgns.ranges = (struct memory_range *) + realloc(usablemem_rgns.ranges, memory_range_len); + if (!(usablemem_rgns.ranges)) + goto err; + + return 0; + +err: + fprintf(stderr, "memory range structure re-allocation failure\n"); + return -1; +} + + +static void add_base_memory_range(uint64_t start, uint64_t end) +{ + base_memory_range[nr_memory_ranges].start = start; + base_memory_range[nr_memory_ranges].end = end; + base_memory_range[nr_memory_ranges].type = RANGE_RAM; + nr_memory_ranges++; + if (nr_memory_ranges >= max_memory_ranges) + realloc_memory_ranges(); + + dbgprintf("%016llx-%016llx : %x\n", + base_memory_range[nr_memory_ranges-1].start, + base_memory_range[nr_memory_ranges-1].end, + base_memory_range[nr_memory_ranges-1].type); +} + +static int get_dyn_reconf_base_ranges(void) +{ + uint64_t start, end; + char fname[128], buf[32]; + FILE *file; + int i, n; + + strcpy(fname, "/proc/device-tree/"); + strcat(fname, "ibm,dynamic-reconfiguration-memory/ibm,lmb-size"); + if ((file = fopen(fname, "r")) == NULL) { + perror(fname); return -1; } + if (fread(buf, 1, 8, file) != 8) { + perror(fname); + fclose(file); + return -1; + } + /* + * lmb_size, num_of_lmbs(global variables) are + * initialized once here. + */ + lmb_size = ((uint64_t *)buf)[0]; + fclose(file); - while ((dentry = readdir(dir)) != NULL) { - if (strncmp(dentry->d_name, "memory@", 7) && - strcmp(dentry->d_name, "memory") && - strncmp(dentry->d_name, "pci@", 4)) - continue; - max_memory_ranges++; + strcpy(fname, "/proc/device-tree/"); + strcat(fname, + "ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory"); + if ((file = fopen(fname, "r")) == NULL) { + perror(fname); + return -1; } - /* need to add extra region for retained initrd */ - if (reuse_initrd) { - max_memory_ranges++; + /* first 4 bytes tell the number of lmbs */ + if (fread(buf, 1, 4, file) != 4) { + perror(fname); + fclose(file); + return -1; } + num_of_lmbs = ((unsigned int *)buf)[0]; - closedir(dir); + for (i = 0; i < num_of_lmbs; i++) { + if ((n = fread(buf, 1, 24, file)) < 0) { + perror(fname); + fclose(file); + return -1; + } + if (nr_memory_ranges >= max_memory_ranges) + return -1; + start = ((uint64_t *)buf)[0]; + end = start + lmb_size; + add_base_memory_range(start, end); + } + fclose(file); return 0; } - /* Sort the base ranges in memory - this is useful for ensuring that our * ranges are in ascending order, even if device-tree read of memory nodes * is done differently. Also, could be used for other range coalescing later @@ -156,7 +226,7 @@ static int sort_base_ranges(void) /* Get base memory ranges */ static int get_base_ranges(void) { - int local_memory_ranges = 0; + uint64_t start, end; char device_tree[256] = "/proc/device-tree/"; char fname[256]; char buf[MAXBYTES]; @@ -170,6 +240,11 @@ static int get_base_ranges(void) return -1; } while ((dentry = readdir(dir)) != NULL) { + if (!strncmp(dentry->d_name, + "ibm,dynamic-reconfiguration-memory", 35)) { + get_dyn_reconf_base_ranges(); + continue; + } if (strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory")) continue; @@ -197,27 +272,18 @@ static int get_base_ranges(void) closedir(dir); return -1; } - if (local_memory_ranges >= max_memory_ranges) { - fclose(file); - break; + if (nr_memory_ranges >= max_memory_ranges) { + if (realloc_memory_ranges() < 0) + break; } - base_memory_range[local_memory_ranges].start = - ((uint64_t *)buf)[0]; - base_memory_range[local_memory_ranges].end = - base_memory_range[local_memory_ranges].start + - ((uint64_t *)buf)[1]; - base_memory_range[local_memory_ranges].type = RANGE_RAM; - local_memory_ranges++; - dbgprintf("%016llx-%016llx : %x\n", - base_memory_range[local_memory_ranges-1].start, - base_memory_range[local_memory_ranges-1].end, - base_memory_range[local_memory_ranges-1].type); + start = ((uint64_t *)buf)[0]; + end = start + ((uint64_t *)buf)[1]; + add_base_memory_range(start, end); fclose(file); } closedir(dmem); } closedir(dir); - nr_memory_ranges = local_memory_ranges; sort_base_ranges(); memory_max = base_memory_range[nr_memory_ranges - 1].end; #ifdef DEBUG @@ -276,7 +342,7 @@ static int get_devtree_details(unsigned strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory") && strncmp(dentry->d_name, "pci@", 4) && - strncmp(dentry->d_name, "rtas", 4)) + strncmp(dentry->d_name, "rtas", 4)) continue; strcpy(fname, device_tree); strcat(fname, dentry->d_name); @@ -301,6 +367,8 @@ static int get_devtree_details(unsigned exclude_range[i].start = 0x0UL; exclude_range[i].end = kernel_end; i++; + if (i >= max_memory_ranges) + realloc_memory_ranges(); if (kexec_flags & KEXEC_ON_CRASH) { memset(fname, 0, sizeof(fname)); @@ -336,7 +404,7 @@ static int get_devtree_details(unsigned mem_min = crash_base; if (crash_base + crash_size < mem_max) mem_max = crash_base + crash_size; - + add_usable_mem_rgns(0, crash_base + crash_size); reserve(KDUMP_BACKUP_LIMIT, crash_base-KDUMP_BACKUP_LIMIT); } @@ -375,6 +443,8 @@ static int get_devtree_details(unsigned exclude_range[i].start = htab_base; exclude_range[i].end = htab_base + htab_size; i++; + if (i >= max_memory_ranges) + realloc_memory_ranges(); /* reserve the initrd_start and end locations. */ if (reuse_initrd) { @@ -420,6 +490,8 @@ static int get_devtree_details(unsigned exclude_range[i].start = initrd_start; exclude_range[i].end = initrd_end; i++; + if (i >= max_memory_ranges) + realloc_memory_ranges(); } } /* chosen */ @@ -450,6 +522,8 @@ static int get_devtree_details(unsigned exclude_range[i].start = rtas_base; exclude_range[i].end = rtas_base + rtas_size; i++; + if (i >= max_memory_ranges) + realloc_memory_ranges(); if (kexec_flags & KEXEC_ON_CRASH) add_usable_mem_rgns(rtas_base, rtas_size); } /* rtas */ @@ -507,6 +581,8 @@ static int get_devtree_details(unsigned exclude_range[i].start = tce_base; exclude_range[i].end = tce_base + tce_size; i++; + if (i >= max_memory_ranges) + realloc_memory_ranges(); if (kexec_flags & KEXEC_ON_CRASH) add_usable_mem_rgns(tce_base, tce_size); closedir(cdir); @@ -560,6 +636,8 @@ int setup_memory_ranges(unsigned long ke memory_range[j].end = exclude_range[i].start - 1; memory_range[j].type = RANGE_RAM; j++; + if (j >= max_memory_ranges) + realloc_memory_ranges(); } } /* i == 0 */ /* If the last exclude range does not end at memory_max, include @@ -572,6 +650,8 @@ int setup_memory_ranges(unsigned long ke memory_range[j].end = memory_max; memory_range[j].type = RANGE_RAM; j++; + if (j >= max_memory_ranges) + realloc_memory_ranges(); /* Limit the end to rmo_top */ if (memory_range[j-1].start >= rmo_top) { j--; @@ -592,6 +672,8 @@ int setup_memory_ranges(unsigned long ke memory_range[j].end = exclude_range[i+1].start - 1; memory_range[j].type = RANGE_RAM; j++; + if (j >= max_memory_ranges) + realloc_memory_ranges(); /* Limit range to rmo_top */ if (memory_range[j-1].start >= rmo_top) { j--; @@ -623,14 +705,24 @@ out: int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { - if (count_memory_ranges()) - return -1; + /* allocate memory_range dynamically */ + max_memory_ranges = 1; + if (alloc_memory_ranges()) return -1; if (setup_memory_ranges(kexec_flags)) return -1; - *range = memory_range; + /* + * copy the memory here, another realloc_memory_ranges might + * corrupt the old memory + */ + *range = calloc(sizeof(struct memory_range), nr_memory_ranges); + if (*range == NULL) + return -1; + memmove(*range, memory_range, + sizeof(struct memory_range) * nr_memory_ranges); + *ranges = nr_memory_ranges; fprintf(stderr, "get memory ranges:%d\n", nr_memory_ranges); return 0;