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;
}