unsigned long virt_to_phys(unsigned long addr) { unsigned long seg = addr & 0xe0000000; unsigned long long start = 0; int have_32bit = is_32bit(); if (seg != 0x80000000 && (have_32bit || seg != 0xc0000000)) die("Virtual address %p is not in P1%s\n", (void *)addr, have_32bit ? "" : " or P2"); /* If 32bit addressing is used then the base of system RAM * is an offset into physical memory. */ if (have_32bit) { unsigned long long end; int ret; /* Assume there is only one "System RAM" region */ ret = parse_iomem_single("System RAM\n", &start, &end); if (ret) die("Could not parse System RAM region " "in /proc/iomem\n"); } return addr - seg + start; }
int is_crashkernel_mem_reserved(void) { uint64_t start, end; return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ? (start != end) : 0; }
/* Return a sorted list of available memory ranges. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { int nr, ret; nr = kexec_iomem_for_each_line("System RAM\n", kexec_sh_memory_range_callback, NULL); *range = memory_range; *ranges = nr; /* * Redefine the memory region boundaries if kernel * exports the limits and if it is panic kernel. * Override user values only if kernel exported values are * subset of user defined values. */ if (kexec_flags & KEXEC_ON_CRASH) { unsigned long long start, end; ret = parse_iomem_single("Crash kernel\n", &start, &end); if (ret != 0) { fprintf(stderr, "parse_iomem_single failed.\n"); return -1; } if (start > mem_min) mem_min = start; if (end < mem_max) mem_max = end; } return 0; }
int image_arm64_load(int argc, char **argv, const char *kernel_buf, off_t kernel_size, struct kexec_info *info) { int result; uint64_t start; const struct arm64_image_header *h; char *header_option = NULL; h = (const struct arm64_image_header *)(kernel_buf); arm64_mem.text_offset = le64_to_cpu(h->text_offset); arm64_mem.image_size = le64_to_cpu(h->image_size); arm64_mem.page_offset = get_kernel_page_offset(); if (info->kexec_flags & KEXEC_ON_CRASH) { result = load_crashdump_segments(info, &header_option); if (result) { fprintf(stderr, "kexec: load crashdump segments failed.\n"); return -1; } start = crash_reserved_mem.start; } else { result = parse_iomem_single("Kernel code\n", &start, NULL); if (result) { fprintf(stderr, "kexec: Could not get kernel code address.\n"); return -1; } start -= arm64_mem.text_offset; } /* Add kernel */ add_segment_phys_virt(info, kernel_buf, kernel_size, start + arm64_mem.text_offset, kernel_size, 0); info->entry = (void *)start + arm64_mem.text_offset; result = arm64_load_other_segments(info, (unsigned long)info->entry, header_option); if (header_option) free(header_option); return result; }
/* Read kernel physical load addr from the file returned by proc_iomem() * (Kernel Code) and store in kexec_info */ static int get_kernel_paddr(struct crash_elf_info *elf_info) { uint64_t start; if (xen_present()) /* Kernel not entity mapped under Xen */ return 0; if (parse_iomem_single("Kernel code\n", &start, NULL) == 0) { elf_info->kern_paddr_start = start; dbgprintf("kernel load physical addr start = 0x%lx\n", start); return 0; } fprintf(stderr, "Cannot determine kernel physical load addr\n"); return -1; }
/* Read kernel physical load addr from the file returned by proc_iomem() * (Kernel Code) and store in kexec_info */ static int get_kernel_paddr(struct kexec_info *info) { uint64_t start; if (xen_present()) /* Kernel not entity mapped under Xen */ return 0; if (parse_iomem_single("Kernel code\n", &start, NULL) == 0) { info->kern_paddr_start = start; #ifdef DEBUG printf("kernel load physical addr start = 0x%016Lx\n", start); #endif return 0; } fprintf(stderr, "Cannot determine kernel physical load addr\n"); return -1; }
static int get_kernel_vaddr_and_size(struct crash_elf_info *elf_info, unsigned long start_offset) { uint64_t end; if (!elf_info->kern_paddr_start) return -1; elf_info->kern_vaddr_start = elf_info->kern_paddr_start | start_offset; if (parse_iomem_single("Kernel data\n", NULL, &end) == 0) { elf_info->kern_size = end - elf_info->kern_paddr_start; dbgprintf("kernel_vaddr= 0x%llx paddr %llx\n", elf_info->kern_vaddr_start, elf_info->kern_paddr_start); dbgprintf("kernel size = 0x%lx\n", elf_info->kern_size); return 0; } fprintf(stderr, "Cannot determine kernel virtual load addr and size\n"); return -1; }
int zImage_arm_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { unsigned long base; unsigned int atag_offset = 0x1000; /* 4k offset from memory start */ unsigned int offset = 0x8000; /* 32k offset from memory start */ unsigned int opt_ramdisk_addr; unsigned int opt_atags_addr; const char *command_line; char *modified_cmdline = NULL; off_t command_line_len; const char *ramdisk; char *ramdisk_buf; int opt; char *endptr; int use_dtb; const char *dtb_file; char *dtb_buf; off_t dtb_length; off_t dtb_offset; struct arm_mach *mach; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_APPEND }, { "append", 1, 0, OPT_APPEND }, { "initrd", 1, 0, OPT_RAMDISK }, { "ramdisk", 1, 0, OPT_RAMDISK }, { "dtb", 2, 0, OPT_DTB }, { "rd-addr", 1, 0, OPT_RD_ADDR }, { "atags-addr", 1, 0, OPT_ATAGS_ADDR }, { "boardname", 1, 0, OPT_BOARDNAME }, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR "a:r:d::i:g:b:"; /* * Parse the command line arguments */ command_line = 0; command_line_len = 0; ramdisk = 0; ramdisk_buf = 0; use_dtb = 0; dtb_file = NULL; opt_ramdisk_addr = 0; opt_atags_addr = 0; mach = NULL; while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case '?': usage(); return -1; case OPT_APPEND: command_line = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_DTB: use_dtb = 1; if(optarg) dtb_file = optarg; break; case OPT_RD_ADDR: opt_ramdisk_addr = strtoul(optarg, &endptr, 0); if (*endptr) { fprintf(stderr, "Bad option value in --rd-addr=%s\n", optarg); usage(); return -1; } break; case OPT_ATAGS_ADDR: opt_atags_addr = strtoul(optarg, &endptr, 0); if (*endptr) { fprintf(stderr, "Bad option value in --atag-addr=%s\n", optarg); usage(); return -1; } break; case OPT_BOARDNAME: mach = arm_mach_choose(optarg); if(!mach) { fprintf(stderr, "Unknown boardname '%s'!\n", optarg); return -1; } break; } } if (command_line) { command_line_len = strlen(command_line) + 1; if (command_line_len > COMMAND_LINE_SIZE) command_line_len = COMMAND_LINE_SIZE; } if (ramdisk) { ramdisk_buf = slurp_file(ramdisk, &initrd_size); } /* * If we are loading a dump capture kernel, we need to update kernel * command line and also add some additional segments. */ if (info->kexec_flags & KEXEC_ON_CRASH) { uint64_t start, end; modified_cmdline = xmalloc(COMMAND_LINE_SIZE); if (!modified_cmdline) return -1; if (command_line) { (void) strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } if (load_crashdump_segments(info, modified_cmdline) < 0) { free(modified_cmdline); return -1; } command_line = modified_cmdline; command_line_len = strlen(command_line) + 1; /* * We put the dump capture kernel at the start of crashkernel * reserved memory. */ if (parse_iomem_single("Crash kernel\n", &start, &end)) { /* * No crash kernel memory reserved. We cannot do more * but just bail out. */ return -1; } base = start; } else { base = locate_hole(info,len+offset,0,0,ULONG_MAX,INT_MAX); } if (base == ULONG_MAX) return -1; /* assume the maximum kernel compression ratio is 4, * and just to be safe, place ramdisk after that */ if(opt_ramdisk_addr == 0) initrd_base = _ALIGN(base + len * 4, getpagesize()); else initrd_base = opt_ramdisk_addr; if(!use_dtb) { if (atag_arm_load(info, base + atag_offset, command_line, command_line_len, ramdisk_buf, initrd_size, initrd_base) == -1) return -1; } else { char *dtb_img = NULL; off_t dtb_img_len = 0; int free_dtb_img = 0; int choose_res = 0; if(!mach) { fprintf(stderr, "DTB: --boardname was not specified.\n"); return -1; } if(dtb_file) { if(!load_dtb_image(dtb_file, &dtb_img, &dtb_img_len)) return -1; printf("DTB: Using DTB from file %s\n", dtb_file); free_dtb_img = 1; } else { if(!get_appended_dtb(buf, len, &dtb_img, &dtb_img_len)) return -1; printf("DTB: Using DTB appended to zImage\n"); } choose_res = (mach->choose_dtb)(dtb_img, dtb_img_len, &dtb_buf, &dtb_length); if(free_dtb_img) free(dtb_img); if(choose_res) { int ret, off; dtb_length = fdt_totalsize(dtb_buf) + DTB_PAD_SIZE; dtb_buf = xrealloc(dtb_buf, dtb_length); ret = fdt_open_into(dtb_buf, dtb_buf, dtb_length); if(ret) die("DTB: fdt_open_into failed"); ret = (mach->add_extra_regs)(dtb_buf); if (ret < 0) { fprintf(stderr, "DTB: error while adding mach-specific extra regs\n"); return -1; } if (command_line) { const char *node_name = "/chosen"; const char *prop_name = "bootargs"; /* check if a /choosen subnode already exists */ off = fdt_path_offset(dtb_buf, node_name); if (off == -FDT_ERR_NOTFOUND) off = fdt_add_subnode(dtb_buf, off, node_name); if (off < 0) { fprintf(stderr, "DTB: Error adding %s node.\n", node_name); return -1; } if (fdt_setprop(dtb_buf, off, prop_name, command_line, strlen(command_line) + 1) != 0) { fprintf(stderr, "DTB: Error setting %s/%s property.\n", node_name, prop_name); return -1; } } if(ramdisk) { const char *node_name = "/chosen"; uint32_t initrd_start, initrd_end; /* check if a /choosen subnode already exists */ off = fdt_path_offset(dtb_buf, node_name); if (off == -FDT_ERR_NOTFOUND) off = fdt_add_subnode(dtb_buf, off, node_name); if (off < 0) { fprintf(stderr, "DTB: Error adding %s node.\n", node_name); return -1; } initrd_start = cpu_to_fdt32(initrd_base); initrd_end = cpu_to_fdt32(initrd_base + initrd_size); ret = fdt_setprop(dtb_buf, off, "linux,initrd-start", &initrd_start, sizeof(initrd_start)); if (ret) die("DTB: Error setting %s/linux,initrd-start property.\n", node_name); ret = fdt_setprop(dtb_buf, off, "linux,initrd-end", &initrd_end, sizeof(initrd_end)); if (ret) die("DTB: Error setting %s/linux,initrd-end property.\n", node_name); } fdt_pack(dtb_buf); } else { /* * Extract the DTB from /proc/device-tree. */ printf("DTB: Failed to load dtb from zImage or dtb.img, using /proc/device-tree. This is unlikely to work.\n"); create_flatten_tree(&dtb_buf, &dtb_length, command_line); } if(ramdisk) { add_segment(info, ramdisk_buf, initrd_size, initrd_base, initrd_size); } if(opt_atags_addr != 0) dtb_offset = opt_atags_addr; else { dtb_offset = initrd_base + initrd_size + getpagesize(); dtb_offset = _ALIGN_DOWN(dtb_offset, getpagesize()); } printf("DTB: add dtb segment 0x%x\n", (unsigned int)dtb_offset); add_segment(info, dtb_buf, dtb_length, dtb_offset, dtb_length); } add_segment(info, buf, len, base + offset, len); info->entry = (void*)base + offset; return 0; }
/** * Return a sorted list of memory ranges. * * If we have the /sys/firmware/memmap interface, then use that. If not, * or if parsing of that fails, use /proc/iomem as fallback. * * @param[out] range pointer that will be set to an array that holds the * memory ranges * @param[out] ranges number of ranges valid in @p range * @param[in] kexec_flags the kexec_flags to determine if we load a normal * or a crashdump kernel * * @return 0 on success, any other value on failure. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { int ret, i; if (!efi_map_added() && !xen_present() && have_sys_firmware_memmap()) { ret = get_memory_ranges_sysfs(range, ranges); if (!ret) ret = fixup_memory_ranges(range, ranges); } else if (xen_present()) { ret = get_memory_ranges_xen(range, ranges); if (!ret) ret = fixup_memory_ranges(range, ranges); } else ret = get_memory_ranges_proc_iomem(range, ranges); /* * get_memory_ranges_sysfs(), get_memory_ranges_proc_iomem() and * get_memory_ranges_xen() have already printed an error message, * so fail silently here. */ if (ret != 0) return ret; /* Don't report the interrupt table as ram */ for (i = 0; i < *ranges; i++) { if ((*range)[i].type == RANGE_RAM && ((*range)[i].start < 0x100)) { (*range)[i].start = 0x100; break; } } /* * Redefine the memory region boundaries if kernel * exports the limits and if it is panic kernel. * Override user values only if kernel exported values are * subset of user defined values. */ if ((kexec_flags & KEXEC_ON_CRASH) && !(kexec_flags & KEXEC_PRESERVE_CONTEXT)) { uint64_t start, end; ret = parse_iomem_single("Crash kernel\n", &start, &end); if (ret != 0) { fprintf(stderr, "parse_iomem_single failed.\n"); return -1; } if (start > mem_min) mem_min = start; if (end < mem_max) mem_max = end; } /* just set 0 to 1 to enable printing for debugging */ #if 0 { int i; printf("MEMORY RANGES\n"); for (i = 0; i < *ranges; i++) { printf("%016Lx-%016Lx (%d)\n", (*range)[i].start, (*range)[i].end, (*range)[i].type); } } #endif return ret; }
/** * Return a sorted list of memory ranges. * * If we have the /sys/firmware/memmap interface, then use that. If not, * or if parsing of that fails, use /proc/iomem as fallback. * * @param[out] range pointer that will be set to an array that holds the * memory ranges * @param[out] ranges number of ranges valid in @p range * @param[in] kexec_flags the kexec_flags to determine if we load a normal * or a crashdump kernel * * @return 0 on success, any other value on failure. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { int ret, i; /* * When using Xen, /sys/firmware/memmap (i.e., the E820 map) is * wrong, it just provides one large memory are and that cannot * be used for Kdump. Use always the /proc/iomem interface there * even if we have /sys/firmware/memmap. Without that, /proc/vmcore * is empty in the kdump kernel. */ if (!xen_present() && have_sys_firmware_memmap()) { ret = get_memory_ranges_sysfs(range, ranges); if (!ret) ret = fixup_memory_ranges_sysfs(range, ranges); } else ret = get_memory_ranges_proc_iomem(range, ranges); /* * both get_memory_ranges_sysfs() and get_memory_ranges_proc_iomem() * have already printed an error message, so fail silently here */ if (ret != 0) return ret; /* Don't report the interrupt table as ram */ for (i = 0; i < *ranges; i++) { if ((*range)[i].type == RANGE_RAM && ((*range)[i].start < 0x100)) { (*range)[i].start = 0x100; break; } } /* * Redefine the memory region boundaries if kernel * exports the limits and if it is panic kernel. * Override user values only if kernel exported values are * subset of user defined values. */ if ((kexec_flags & KEXEC_ON_CRASH) && !(kexec_flags & KEXEC_PRESERVE_CONTEXT)) { uint64_t start, end; ret = parse_iomem_single("Crash kernel\n", &start, &end); if (ret != 0) { fprintf(stderr, "parse_iomem_single failed.\n"); return -1; } if (start > mem_min) mem_min = start; if (end < mem_max) mem_max = end; } /* just set 0 to 1 to enable printing for debugging */ #if 0 { int i; printf("MEMORY RANGES\n"); for (i = 0; i < *ranges; i++) { printf("%016Lx-%016Lx (%d)\n", (*range)[i].start, (*range)[i].end, (*range)[i].type); } } #endif return ret; }
int zImage_arm_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { unsigned long base; unsigned int atag_offset = 0x1000; /* 4k offset from memory start */ unsigned int offset = 0x8000; /* 32k offset from memory start */ const char *command_line; char *modified_cmdline = NULL; off_t command_line_len; const char *ramdisk; char *ramdisk_buf; off_t ramdisk_length; off_t ramdisk_offset; int opt; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_APPEND }, { "append", 1, 0, OPT_APPEND }, { "initrd", 1, 0, OPT_RAMDISK }, { "ramdisk", 1, 0, OPT_RAMDISK }, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR "a:r:"; /* * Parse the command line arguments */ command_line = 0; command_line_len = 0; ramdisk = 0; ramdisk_buf = 0; ramdisk_length = 0; while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case '?': usage(); return -1; case OPT_APPEND: command_line = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; } } if (command_line) { command_line_len = strlen(command_line) + 1; if (command_line_len > COMMAND_LINE_SIZE) command_line_len = COMMAND_LINE_SIZE; } if (ramdisk) { ramdisk_buf = slurp_file(ramdisk, &ramdisk_length); } /* * If we are loading a dump capture kernel, we need to update kernel * command line and also add some additional segments. */ if (info->kexec_flags & KEXEC_ON_CRASH) { uint64_t start, end; modified_cmdline = xmalloc(COMMAND_LINE_SIZE); if (!modified_cmdline) return -1; if (command_line) { (void) strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } if (load_crashdump_segments(info, modified_cmdline) < 0) { free(modified_cmdline); return -1; } command_line = modified_cmdline; command_line_len = strlen(command_line) + 1; /* * We put the dump capture kernel at the start of crashkernel * reserved memory. */ if (parse_iomem_single("Crash kernel\n", &start, &end)) { /* * No crash kernel memory reserved. We cannot do more * but just bail out. */ return -1; } base = start; } else { base = locate_hole(info,len+offset,0,0,ULONG_MAX,INT_MAX); } if (base == ULONG_MAX) return -1; /* assume the maximum kernel compression ratio is 4, * and just to be safe, place ramdisk after that */ ramdisk_offset = base + len * 4; if (atag_arm_load(info, base + atag_offset, command_line, command_line_len, ramdisk_buf, ramdisk_length, ramdisk_offset) == -1) return -1; add_segment(info, buf, len, base + offset, len); info->entry = (void*)base + offset; return 0; }
int zImage_arm_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { unsigned long base; unsigned int atag_offset = 0x1000; /* 4k offset from memory start */ unsigned int offset = 0x8000; /* 32k offset from memory start */ const char *command_line; char *modified_cmdline = NULL; off_t command_line_len; const char *ramdisk; char *ramdisk_buf; int opt; int use_atags; char *dtb_buf; off_t dtb_length; char *dtb_file; off_t dtb_offset; char *end; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_APPEND }, { "append", 1, 0, OPT_APPEND }, { "initrd", 1, 0, OPT_RAMDISK }, { "ramdisk", 1, 0, OPT_RAMDISK }, { "dtb", 1, 0, OPT_DTB }, { "atags", 0, 0, OPT_ATAGS }, { "image-size", 1, 0, OPT_IMAGE_SIZE }, { "atags-file", 1, 0, OPT_ATAGS }, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR "a:r:"; /* * Parse the command line arguments */ command_line = 0; command_line_len = 0; ramdisk = 0; ramdisk_buf = 0; initrd_size = 0; use_atags = 0; dtb_file = NULL; while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case OPT_APPEND: command_line = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_DTB: dtb_file = optarg; break; case OPT_ATAGS: use_atags = 1; break; case OPT_IMAGE_SIZE: kexec_arm_image_size = strtoul(optarg, &end, 0); break; case OPT_ATAGS_FILE: atags_file = optarg; break; } } if (use_atags && dtb_file) { fprintf(stderr, "You can only use ATAGs if you don't specify a " "dtb file.\n"); return -1; } if (command_line) { command_line_len = strlen(command_line) + 1; if (command_line_len > COMMAND_LINE_SIZE) command_line_len = COMMAND_LINE_SIZE; } if (ramdisk) { ramdisk_buf = slurp_file(ramdisk, &initrd_size); } /* * If we are loading a dump capture kernel, we need to update kernel * command line and also add some additional segments. */ if (info->kexec_flags & KEXEC_ON_CRASH) { uint64_t start, end; modified_cmdline = xmalloc(COMMAND_LINE_SIZE); if (!modified_cmdline) return -1; if (command_line) { (void) strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } if (load_crashdump_segments(info, modified_cmdline) < 0) { free(modified_cmdline); return -1; } command_line = modified_cmdline; command_line_len = strlen(command_line) + 1; /* * We put the dump capture kernel at the start of crashkernel * reserved memory. */ if (parse_iomem_single("Crash kernel\n", &start, &end)) { /* * No crash kernel memory reserved. We cannot do more * but just bail out. */ return -1; } base = start; } else { base = locate_hole(info,len+offset,0,0,ULONG_MAX,INT_MAX); } if (base == ULONG_MAX) return -1; printf("Kernel segment stats: %lx (%ld)\n", base, len); if (kexec_arm_image_size) { /* If the image size was passed as command line argument, * use that value for determining the address for initrd, * atags and dtb images. page-align the given length.*/ initrd_base = base + _ALIGN(kexec_arm_image_size, getpagesize()); } else { /* Otherwise, assume the maximum kernel compression ratio * is 4, and just to be safe, place ramdisk after that */ initrd_base = base + _ALIGN(len * 4, getpagesize()); } if (use_atags) { /* * use ATAGs from /proc/atags */ if (atag_arm_load(info, base + atag_offset, command_line, command_line_len, ramdisk_buf, initrd_size, initrd_base) == -1) return -1; } else { /* * Read a user-specified DTB file. */ if (dtb_file) { dtb_buf = slurp_file(dtb_file, &dtb_length); if (fdt_check_header(dtb_buf) != 0) { fprintf(stderr, "Invalid FDT buffer.\n"); return -1; } if (command_line) { /* * Error should have been reported so * directly return -1 */ if (setup_dtb_prop(&dtb_buf, &dtb_length, "/chosen", "bootargs", command_line, strlen(command_line) + 1)) return -1; } } else { /* * Extract the DTB from /proc/device-tree. */ create_flatten_tree(&dtb_buf, &dtb_length, command_line); } if (base + atag_offset + dtb_length > base + offset) { fprintf(stderr, "DTB too large!\n"); return -1; } if (ramdisk) { add_segment(info, ramdisk_buf, initrd_size, initrd_base, initrd_size); unsigned long start, end; start = cpu_to_be32((unsigned long)(initrd_base)); end = cpu_to_be32((unsigned long)(initrd_base + initrd_size)); if (setup_dtb_prop(&dtb_buf, &dtb_length, "/chosen", "linux,initrd-start", &start, sizeof(start))) return -1; if (setup_dtb_prop(&dtb_buf, &dtb_length, "/chosen", "linux,initrd-end", &end, sizeof(end))) return -1; } /* Stick the dtb at the end of the initrd and page * align it. */ dtb_offset = initrd_base + initrd_size + getpagesize(); dtb_offset = _ALIGN_DOWN(dtb_offset, getpagesize()); add_segment(info, dtb_buf, dtb_length, dtb_offset, dtb_length); } printf("Kernel segment info: %lx (%d)\n", base+offset, len); add_segment(info, buf, len, base + offset, len); info->entry = (void*)base + offset; return 0; }