static int get_dyn_reconf_crash_memory_ranges(void) { uint64_t start, end; char fname[128], buf[32]; FILE *file; unsigned int i; int 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 = be64_to_cpu(((uint64_t *)buf)[DRCONF_ADDR]); end = start + lmb_size; if (start == 0 && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; flags = be32_to_cpu((*((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. * * 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) { char device_tree[256] = "/proc/device-tree/"; char fname[256]; char buf[MAXBYTES]; DIR *dir, *dmem; FILE *file; struct dirent *dentry, *mentry; int i, n, crash_rng_len = 0; unsigned long long start, end; int page_size; crash_max_memory_ranges = max_memory_ranges + 6; crash_rng_len = sizeof(struct memory_range) * crash_max_memory_ranges; crash_memory_range = (struct memory_range *) malloc(crash_rng_len); if (!crash_memory_range) { fprintf(stderr, "Allocation for crash memory range failed\n"); return -1; } memset(crash_memory_range, 0, crash_rng_len); /* create a separate program header for the backup region */ crash_memory_range[0].start = BACKUP_SRC_START; crash_memory_range[0].end = BACKUP_SRC_END + 1; crash_memory_range[0].type = RANGE_RAM; memory_ranges++; if ((dir = opendir(device_tree)) == NULL) { 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; strcpy(fname, device_tree); strcat(fname, dentry->d_name); if ((dmem = opendir(fname)) == NULL) { perror(fname); closedir(dir); goto err; } while ((mentry = readdir(dmem)) != NULL) { if (strcmp(mentry->d_name, "reg")) continue; strcat(fname, "/reg"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); closedir(dmem); closedir(dir); goto err; } if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); fclose(file); closedir(dmem); closedir(dir); goto err; } 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"); goto err; } start = ((unsigned long long *)buf)[0]; end = start + ((unsigned long long *)buf)[1]; if (start == 0 && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; exclude_crash_region(start, end); fclose(file); } closedir(dmem); } closedir(dir); /* * If RTAS region is overlapped with crashkernel, need to create ELF * Program header for the overlapped memory. */ if (crash_base < rtas_base + rtas_size && rtas_base < crash_base + crash_size) { page_size = getpagesize(); cstart = rtas_base; cend = rtas_base + rtas_size; if (cstart < crash_base) cstart = crash_base; if (cend > crash_base + crash_size) cend = crash_base + crash_size; /* * The rtas section created here is formed by reading rtas-base * and rtas-size from /proc/device-tree/rtas. Unfortunately * rtas-size is not required to be a multiple of PAGE_SIZE * The remainder of the page it ends on is just garbage, and is * safe to read, its just not accounted in rtas-size. Since * we're creating an elf section here though, lets round it up * to the next page size boundary though, so makedumpfile can * read it safely without going south on us. */ cend = (cend + page_size - 1) & (~(page_size - 1)); crash_memory_range[memory_ranges].start = cstart; crash_memory_range[memory_ranges++].end = cend; } /* * Can not trust the memory regions order that we read from * device-tree. Hence, get the MAX end value. */ for (i = 0; i < memory_ranges; i++) if (saved_max_mem < crash_memory_range[i].end) saved_max_mem = crash_memory_range[i].end; *range = crash_memory_range; *ranges = memory_ranges; #if DEBUG int j; printf("CRASH MEMORY RANGES\n"); for(j = 0; j < *ranges; j++) { start = crash_memory_range[j].start; end = crash_memory_range[j].end; fprintf(stderr, "%016Lx-%016Lx\n", start, end); } #endif return 0; err: if (crash_memory_range) free(crash_memory_range); return -1; }
static int get_dyn_reconf_crash_memory_ranges(void) { uint64_t start, end; uint64_t startrange, endrange; uint64_t size; char fname[128], buf[32]; FILE *file; unsigned int i; int n; uint32_t flags; strcpy(fname, "/proc/device-tree/"); strcat(fname, "ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory"); if (is_dyn_mem_v2) strcat(fname, "-v2"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); return -1; } fseek(file, 4, SEEK_SET); startrange = endrange = 0; size = lmb_size; for (i = 0; i < num_of_lmb_sets; i++) { if ((n = fread(buf, 1, LMB_ENTRY_SIZE, 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; } /* * If the property is ibm,dynamic-memory-v2, the first 4 bytes * tell the number of sequential LMBs in this entry. */ if (is_dyn_mem_v2) size = be32_to_cpu(((unsigned int *)buf)[0]) * lmb_size; start = be64_to_cpu(*((uint64_t *)&buf[DRCONF_ADDR])); end = start + size; if (start == 0 && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; flags = be32_to_cpu((*((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; if (start != endrange) { if (startrange != endrange) exclude_crash_region(startrange, endrange); startrange = start; } endrange = end; } if (startrange != endrange) exclude_crash_region(startrange, endrange); fclose(file); return 0; }