/* Loads additional segments in case of a panic kernel is being loaded.
 * One segment for backup region, another segment for storing elf headers
 * for crash memory image.
 */
int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
				unsigned long max_addr, unsigned long min_base)
{
	void *tmp;
	unsigned long sz, elfcorehdr;
	int nr_ranges, align = 1024, i;
	struct memory_range *mem_range, *memmap_p;

	struct crash_elf_info elf_info =
	{
		class: ELFCLASS64,
		data: ELFDATA2LSB,
		machine: EM_X86_64,
		backup_src_start: BACKUP_SRC_START,
		backup_src_end: BACKUP_SRC_END,
		page_offset: page_offset,
	};

	if (get_kernel_paddr(info))
		return -1;

	if (get_kernel_vaddr_and_size(info))
		return -1;

	if (get_crash_memory_ranges(&mem_range, &nr_ranges,
				    info->kexec_flags) < 0)
		return -1;

	/* Memory regions which panic kernel can safely use to boot into */
	sz = (sizeof(struct memory_range) * (KEXEC_MAX_SEGMENTS + 1));
	memmap_p = xmalloc(sz);
	memset(memmap_p, 0, sz);
	add_memmap(memmap_p, BACKUP_SRC_START, BACKUP_SRC_SIZE);
	sz = crash_reserved_mem.end - crash_reserved_mem.start +1;
	add_memmap(memmap_p, crash_reserved_mem.start, sz);

	/* Create a backup region segment to store backup data*/
	if (!(info->kexec_flags & KEXEC_PRESERVE_CONTEXT)) {
		sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
		tmp = xmalloc(sz);
		memset(tmp, 0, sz);
		info->backup_start = add_buffer(info, tmp, sz, sz, align,
						0, max_addr, 1);
		if (delete_memmap(memmap_p, info->backup_start, sz) < 0)
			return -1;
	}

	/* Create elf header segment and store crash image data. */
	if (crash_create_elf64_headers(info, &elf_info,
				       crash_memory_range, nr_ranges,
				       &tmp, &sz,
				       ELF_CORE_HEADER_ALIGN) < 0)
		return -1;

	/* Hack: With some ld versions (GNU ld version 2.14.90.0.4 20030523),
	 * vmlinux program headers show a gap of two pages between bss segment
	 * and data segment but effectively kernel considers it as bss segment
	 * and overwrites the any data placed there. Hence bloat the memsz of
	 * elf core header segment to 16K to avoid being placed in such gaps.
	 * This is a makeshift solution until it is fixed in kernel.
	 */
	elfcorehdr = add_buffer(info, tmp, sz, 16*1024, align, min_base,
							max_addr, -1);
	if (delete_memmap(memmap_p, elfcorehdr, sz) < 0)
		return -1;
	cmdline_add_memmap(mod_cmdline, memmap_p);
	cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);

	/* Inform second kernel about the presence of ACPI tables. */
	for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) {
		unsigned long start, end;
		if ( !( mem_range[i].type == RANGE_ACPI
			|| mem_range[i].type == RANGE_ACPI_NVS) )
			continue;
		start = mem_range[i].start;
		end = mem_range[i].end;
		cmdline_add_memmap_acpi(mod_cmdline, start, end);
	}
	return 0;
}
/* Loads additional segments in case of a panic kernel is being loaded.
 * One segment for backup region, another segment for storing elf headers
 * for crash memory image.
 */
int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
                            unsigned long max_addr, unsigned long min_base)
{
    void *tmp;
    unsigned long sz, elfcorehdr;
    int nr_ranges, align = 1024;
    struct memory_range *mem_range, *memmap_p;

    if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
        return -1;

    /*
     * if the core type has not been set on command line, set it here
     * automatically
     */
    if (arch_options.core_header_type == CORE_TYPE_UNDEF) {
        arch_options.core_header_type =
            get_core_type(info, mem_range, nr_ranges);
    }

    /* Memory regions which panic kernel can safely use to boot into */
    sz = (sizeof(struct memory_range) * (KEXEC_MAX_SEGMENTS + 1));
    memmap_p = xmalloc(sz);
    memset(memmap_p, 0, sz);
    add_memmap(memmap_p, BACKUP_SRC_START, BACKUP_SRC_SIZE);
    sz = crash_reserved_mem.end - crash_reserved_mem.start +1;
    add_memmap(memmap_p, crash_reserved_mem.start, sz);

    /* Create a backup region segment to store backup data*/
    sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
    tmp = xmalloc(sz);
    memset(tmp, 0, sz);
    info->backup_start = add_buffer(info, tmp, sz, sz, align,
                                    0, max_addr, -1);
    dbgprintf("Created backup segment at 0x%lx\n", info->backup_start);
    if (delete_memmap(memmap_p, info->backup_start, sz) < 0)
        return -1;

    /* Create elf header segment and store crash image data. */
    if (arch_options.core_header_type == CORE_TYPE_ELF64) {
        if (crash_create_elf64_headers(info, &elf_info64,
                                       crash_memory_range, nr_ranges,
                                       &tmp, &sz,
                                       ELF_CORE_HEADER_ALIGN) < 0)
            return -1;
    }
    else {
        if (crash_create_elf32_headers(info, &elf_info32,
                                       crash_memory_range, nr_ranges,
                                       &tmp, &sz,
                                       ELF_CORE_HEADER_ALIGN) < 0)
            return -1;
    }

    /* Hack: With some ld versions (GNU ld version 2.14.90.0.4 20030523),
     * vmlinux program headers show a gap of two pages between bss segment
     * and data segment but effectively kernel considers it as bss segment
     * and overwrites the any data placed there. Hence bloat the memsz of
     * elf core header segment to 16K to avoid being placed in such gaps.
     * This is a makeshift solution until it is fixed in kernel.
     */
    elfcorehdr = add_buffer(info, tmp, sz, 16*1024, align, min_base,
                            max_addr, -1);
    dbgprintf("Created elf header segment at 0x%lx\n", elfcorehdr);
    if (delete_memmap(memmap_p, elfcorehdr, sz) < 0)
        return -1;
    cmdline_add_memmap(mod_cmdline, memmap_p);
    cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
    return 0;
}