static int get_crash_memory_ranges(int *ranges) { const char *iomem = proc_iomem(); char line[MAX_LINE]; FILE *fp; unsigned long start, end; crash_memory_range = xmalloc(sizeof(struct memory_range) * max_memory_ranges); fp = fopen(iomem, "r"); if (!fp) { fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno)); return -1; } while(fgets(line, sizeof(line), fp) != 0) { char *str; int type, consumed, count; if (memory_ranges >= max_memory_ranges) break; count = sscanf(line, "%lx-%lx : %n", &start, &end, &consumed); str = line + consumed; if (count != 2) continue; if (memcmp(str, "System RAM\n", 11) == 0) { type = RANGE_RAM; } else if (memcmp(str, "Crash kernel\n", 13) == 0) { /* Reserved memory region. New kernel can * use this region to boot into. */ crash_reserved_mem.start = start; crash_reserved_mem.end = end; crash_reserved_mem.type = RANGE_RAM; continue; } else if (memcmp(str, "Kernel code\n", 12) == 0) { kernel_code_start = start; kernel_code_end = end; continue; } else if (memcmp(str, "Uncached RAM\n", 13) == 0) { type = RANGE_UNCACHED; } else { continue; } crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; memory_ranges++; } fclose(fp); if (exclude_crash_reserve_region(&memory_ranges) < 0) return -1; *ranges = memory_ranges; return 0; }
/* Removes crash reserve region from list of memory chunks for whom elf program * headers have to be created. Assuming crash reserve region to be a single * continuous area fully contained inside one of the memory chunks */ static int exclude_crash_reserve_region(int *nr_ranges) { int i, j, tidx = -1; unsigned long long cstart, cend; struct memory_range temp_region = { .start = 0, .end = 0 }; /* Crash reserved region. */ cstart = crash_reserved_mem.start; cend = crash_reserved_mem.end; for (i = 0; i < (*nr_ranges); i++) { unsigned long long mstart, mend; mstart = crash_memory_range[i].start; mend = crash_memory_range[i].end; if (cstart < mend && cend > mstart) { if (cstart != mstart && cend != mend) { /* Split memory region */ crash_memory_range[i].end = cstart - 1; temp_region.start = cend + 1; temp_region.end = mend; temp_region.type = RANGE_RAM; tidx = i+1; } else if (cstart != mstart) crash_memory_range[i].end = cstart - 1; else crash_memory_range[i].start = cend + 1; } } /* Insert split memory region, if any. */ if (tidx >= 0) { if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) { /* No space to insert another element. */ fprintf(stderr, "Error: Number of crash memory ranges" " excedeed the max limit\n"); return -1; } for (j = (*nr_ranges - 1); j >= tidx; j--) crash_memory_range[j+1] = crash_memory_range[j]; crash_memory_range[tidx].start = temp_region.start; crash_memory_range[tidx].end = temp_region.end; crash_memory_range[tidx].type = temp_region.type; (*nr_ranges)++; } 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) { const char iomem[] = "/proc/iomem"; int i, memory_ranges = 0; char line[MAX_LINE]; FILE *fp; unsigned long long start, end; fp = fopen(iomem, "r"); if (!fp) { fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno)); return -1; } /* Separate segment for backup region */ crash_memory_range[0].start = BACKUP_SRC_START; crash_memory_range[0].end = BACKUP_SRC_END; crash_memory_range[0].type = RANGE_RAM; memory_ranges++; while (fgets(line, sizeof(line), fp) != 0) { char *str; int type, consumed, count; if (memory_ranges >= CRASH_MAX_MEMORY_RANGES) break; count = sscanf(line, "%Lx-%Lx : %n", &start, &end, &consumed); if (count != 2) continue; str = line + consumed; /* Only Dumping memory of type System RAM. */ if (memcmp(str, "System RAM\n", 11) == 0) { type = RANGE_RAM; } else if (memcmp(str, "Crash kernel\n", 13) == 0) { /* Reserved memory region. New kernel can * use this region to boot into. */ crash_reserved_mem.start = start; crash_reserved_mem.end = end; crash_reserved_mem.type = RANGE_RAM; continue; } else continue; if (start == BACKUP_SRC_START && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; memory_ranges++; /* Segregate linearly mapped region. */ if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) { crash_memory_range[memory_ranges - 1].end = MAXMEM - 1; /* Add segregated region. */ crash_memory_range[memory_ranges].start = MAXMEM; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; memory_ranges++; } } fclose(fp); if (exclude_crash_reserve_region(&memory_ranges) < 0) return -1; for (i = 0; i < memory_ranges; i++) if (saved_max_mem < crash_memory_range[i].end) saved_max_mem = crash_memory_range[i].end + 1; *range = crash_memory_range; *ranges = memory_ranges; 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; } }
/* 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) { const char *iomem = proc_iomem(); int memory_ranges = 0; char line[MAX_LINE]; FILE *fp; unsigned long long start, end; fp = fopen(iomem, "r"); if (!fp) { fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno)); return -1; } /* First entry is for first 640K region. Different bios report first * 640K in different manner hence hardcoding it */ crash_memory_range[0].start = 0x00000000; crash_memory_range[0].end = 0x0009ffff; crash_memory_range[0].type = RANGE_RAM; memory_ranges++; while(fgets(line, sizeof(line), fp) != 0) { char *str; int type, consumed, count; if (memory_ranges >= CRASH_MAX_MEMORY_RANGES) break; count = sscanf(line, "%Lx-%Lx : %n", &start, &end, &consumed); if (count != 2) continue; str = line + consumed; #if 0 printf("%016Lx-%016Lx : %s", start, end, str); #endif /* Only Dumping memory of type System RAM. */ if (memcmp(str, "System RAM\n", 11) == 0) { type = RANGE_RAM; } else if (memcmp(str, "Crash kernel\n", 13) == 0) { /* Reserved memory region. New kernel can * use this region to boot into. */ crash_reserved_mem.start = start; crash_reserved_mem.end = end; crash_reserved_mem.type = RANGE_RAM; continue; } else { continue; } /* First 640K already registered */ if (start >= 0x00000000 && end <= 0x0009ffff) continue; crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; memory_ranges++; /* Segregate linearly mapped region. */ if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) { crash_memory_range[memory_ranges-1].end = MAXMEM -1; /* Add segregated region. */ crash_memory_range[memory_ranges].start = MAXMEM; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; memory_ranges++; } } fclose(fp); if (exclude_crash_reserve_region(&memory_ranges) < 0) return -1; *range = crash_memory_range; *ranges = memory_ranges; #if 0 int i; printf("CRASH MEMORY RANGES\n"); for(i = 0; i < memory_ranges; i++) { start = crash_memory_range[i].start; end = crash_memory_range[i].end; printf("%016Lx-%016Lx\n", start, end); } #endif return 0; }