diff options
-rw-r--r-- | kexec/arch/ppc/fixup_dtb.c | 298 | ||||
-rw-r--r-- | kexec/arch/ppc/fixup_dtb.h | 6 | ||||
-rw-r--r-- | kexec/arch/ppc/kexec-elf-ppc.c | 159 | ||||
-rw-r--r-- | kexec/arch/ppc/kexec-ppc.h | 1 | ||||
-rw-r--r-- | kexec/arch/ppc/kexec-uImage-ppc.c | 65 | ||||
-rw-r--r-- | kexec/arch/ppc/ops.h | 1 |
6 files changed, 390 insertions, 140 deletions
diff --git a/kexec/arch/ppc/fixup_dtb.c b/kexec/arch/ppc/fixup_dtb.c index 40e9350..26c23a3 100644 --- a/kexec/arch/ppc/fixup_dtb.c +++ b/kexec/arch/ppc/fixup_dtb.c @@ -8,13 +8,35 @@ #include <sys/stat.h> #include "../../kexec.h" +#include "../../kexec-syscall.h" #include <libfdt.h> #include "ops.h" #include "page.h" #include "fixup_dtb.h" +#include "kexec-ppc.h" const char proc_dts[] = "/proc/device-tree"; +#ifdef DEBUG +static void print_fdt_reserve_regions(char *blob_buf) +{ + int i, num; + + /* Print out a summary of the final reserve regions */ + num = fdt_num_mem_rsv(blob_buf); + printf ("reserve regions: %d\n", num); + for (i = 0; i < num; i++) { + uint64_t offset, size; + + if (fdt_get_mem_rsv(blob_buf, i, &offset, &size) == 0) { + printf("%d: offset: %llx, size: %llx\n", i, offset, size); + } else { + printf("Error retreiving reserved region\n"); + } + } +} +#endif + static void fixup_nodes(char *nodes[]) { int index = 0; @@ -92,14 +114,288 @@ static void fixup_cmdline(const char *cmdline) return; } -char *fixup_dtb_nodes(char *blob_buf, off_t *blob_size, char *nodes[], char *cmdline) +#define EXPAND_GRANULARITY 1024 + +static char *expand_buf(int minexpand, char *blob_buf, off_t *blob_size) +{ + int size = fdt_totalsize(blob_buf); + int rc; + + size = _ALIGN(size + minexpand, EXPAND_GRANULARITY); + blob_buf = realloc(blob_buf, size); + if (!blob_buf) + fatal("Couldn't find %d bytes to expand device tree\n\r", size); + rc = fdt_open_into(blob_buf, blob_buf, size); + if (rc != 0) + fatal("Couldn't expand fdt into new buffer: %s\n\r", + fdt_strerror(rc)); + + *blob_size = fdt_totalsize(blob_buf); + + return blob_buf; +} + +static void fixup_reserve_regions(struct kexec_info *info, char *blob_buf, off_t *blob_size) { + int ret, i; + int nodeoffset; + + /* If this is a KEXEC kernel we add all regions since they will + * all need to be saved */ + if (info->kexec_flags & KEXEC_ON_CRASH) { + for (i = 0; i < info->nr_segments; i++) { + uint64_t address = (unsigned long)info->segment[i].mem; + uint64_t size = info->segment[i].memsz; + + while ((i+1) < info->nr_segments && + (address + size == (unsigned long)info->segment[i+1].mem)) { + size += info->segment[++i].memsz; + } + + ret = fdt_add_mem_rsv(blob_buf, address, size); + if (ret) { + printf("%s: Error adding memory range to memreserve!\n", + fdt_strerror(ret)); + goto out; + } + } + } else { + /* Otherwise we just add back the ramdisk and the device tree + * is already in the list */ + ret = fdt_add_mem_rsv(blob_buf, ramdisk_base, ramdisk_size); + if (ret) { + printf("%s: Unable to add new reserved memory for initrd flat device tree\n", + fdt_strerror(ret)); + goto out; + } + } + + /* Add reserve regions for cpu-release-addr */ + nodeoffset = fdt_node_offset_by_prop_value(blob_buf, -1, "device_type", "cpu", 4); + while (nodeoffset != -FDT_ERR_NOTFOUND) { + const void *buf; + int sz, ret; + u64 val = 0; + + buf = fdt_getprop(blob_buf, nodeoffset, "cpu-release-addr", &sz); + if (sz == 4) { + val = *(u32 *)buf; + } else if (sz == 8) { + val = *(u64 *)buf; + } + + if (val) { + ret = fdt_add_mem_rsv(blob_buf, PAGE_ALIGN(val-PAGE_SIZE), PAGE_SIZE); + if (ret) + printf("%s: Unable to add reserve for cpu-release-addr!\n", + fdt_strerror(ret)); + } + + nodeoffset = fdt_node_offset_by_prop_value(blob_buf, nodeoffset, + "device_type", "cpu", 4); + } + +out: ; + +#ifdef DEBUG + print_fdt_reserve_regions(blob_buf); +#endif +} + +static void fixup_memory(struct kexec_info *info, char *blob_buf) +{ + if (info->kexec_flags & KEXEC_ON_CRASH) { + int nodeoffset, len = 0; + u8 tmp[16]; + const unsigned long *addrcell, *sizecell; + + nodeoffset = fdt_path_offset(blob_buf, "/memory"); + + if (nodeoffset < 0) { + printf("Error searching for memory node!\n"); + return; + } + + addrcell = fdt_getprop(blob_buf, 0, "#address-cells", NULL); + /* use shifts and mask to ensure endianness */ + if ((addrcell) && (*addrcell == 2)) { + tmp[0] = (crash_base >> 56) & 0xff; + tmp[1] = (crash_base >> 48) & 0xff; + tmp[2] = (crash_base >> 40) & 0xff; + tmp[3] = (crash_base >> 32) & 0xff; + tmp[4] = (crash_base >> 24) & 0xff; + tmp[5] = (crash_base >> 16) & 0xff; + tmp[6] = (crash_base >> 8) & 0xff; + tmp[7] = (crash_base ) & 0xff; + len = 8; + } else { + tmp[0] = (crash_base >> 24) & 0xff; + tmp[1] = (crash_base >> 16) & 0xff; + tmp[2] = (crash_base >> 8) & 0xff; + tmp[3] = (crash_base ) & 0xff; + len = 4; + } + + sizecell = fdt_getprop(blob_buf, 0, "#size-cells", NULL); + /* use shifts and mask to ensure endianness */ + if ((sizecell) && (*sizecell == 2)) { + tmp[0+len] = (crash_size >> 56) & 0xff; + tmp[1+len] = (crash_size >> 48) & 0xff; + tmp[2+len] = (crash_size >> 40) & 0xff; + tmp[3+len] = (crash_size >> 32) & 0xff; + tmp[4+len] = (crash_size >> 24) & 0xff; + tmp[5+len] = (crash_size >> 16) & 0xff; + tmp[6+len] = (crash_size >> 8) & 0xff; + tmp[7+len] = (crash_size ) & 0xff; + len += 8; + } else { + tmp[0+len] = (crash_size >> 24) & 0xff; + tmp[1+len] = (crash_size >> 16) & 0xff; + tmp[2+len] = (crash_size >> 8) & 0xff; + tmp[3+len] = (crash_size ) & 0xff; + len += 4; + } + + if (fdt_setprop(blob_buf, nodeoffset, "reg", tmp, len) != 0) { + printf ("Error setting memory node!\n"); + } + + fdt_delprop(blob_buf, nodeoffset, "linux,usable-memory"); + } +} + +/* removes crashkernel nodes if they exist and we are *rebooting* + * into a crashkernel. These nodes should not exist after we + * crash and reboot into a new kernel + */ +static void fixup_crashkernel(struct kexec_info *info, char *blob_buf) +{ + int nodeoffset; + + nodeoffset = fdt_path_offset(blob_buf, "/chosen"); + + if (info->kexec_flags & KEXEC_ON_CRASH) { + if (nodeoffset < 0) { + printf("fdt_crashkernel: %s\n", fdt_strerror(nodeoffset)); + return; + } + + fdt_delprop(blob_buf, nodeoffset, "linux,crashkernel-base"); + fdt_delprop(blob_buf, nodeoffset, "linux,crashkernel-size"); + } +} +/* remove the old chosen nodes if they exist and add correct chosen + * nodes if we have an initd + */ +static void fixup_initrd(char *blob_buf) +{ + int err, nodeoffset; + unsigned long tmp; + + nodeoffset = fdt_path_offset(blob_buf, "/chosen"); + + if ((reuse_initrd || ramdisk) && + ((ramdisk_base != 0) && (ramdisk_size != 0))) { + if (nodeoffset < 0) { + printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset)); + return; + } + + tmp = ramdisk_base; + err = fdt_setprop(blob_buf, nodeoffset, + "linux,initrd-start", &tmp, sizeof(tmp)); + if (err < 0) { + printf("WARNING: " + "could not set linux,initrd-start %s.\n", + fdt_strerror(err)); + return; + } + + tmp = ramdisk_base + ramdisk_size + 1; + err = fdt_setprop(blob_buf, nodeoffset, + "linux,initrd-end", &tmp, sizeof(tmp)); + if (err < 0) { + printf("WARNING: could not set linux,initrd-end %s.\n", + fdt_strerror(err)); + return; + } + } else { + fdt_delprop(blob_buf, nodeoffset, "linux,initrd-start"); + fdt_delprop(blob_buf, nodeoffset, "linux,initrd-end"); + } +} + +char *fixup_dtb_init(struct kexec_info *info, char *blob_buf, off_t *blob_size, + unsigned long hole_addr, unsigned long *dtb_addr) +{ + int ret, i, num = fdt_num_mem_rsv(blob_buf); + fdt_init(blob_buf); + /* Remove the existing reserve regions as they will no longer + * be valid after we reboot */ + for (i = num - 1; i >= 0; i--) { + ret = fdt_del_mem_rsv(blob_buf, i); + if (ret) { + printf("%s: Error deleting memory reserve region %d from device tree!\n", + fdt_strerror(ret), i); + } + } + + /* Pack the FDT first, so we don't grow excessively if there is already free space */ + ret = fdt_pack(blob_buf); + if (ret) + printf("%s: Unable to pack flat device tree\n", fdt_strerror(ret)); + + /* info->nr_segments just a guide, will grow by at least EXPAND_GRANULARITY */ + blob_buf = expand_buf(info->nr_segments, blob_buf, blob_size); + + /* add reserve region for *THIS* fdt */ + *dtb_addr = locate_hole(info, *blob_size, 0, + hole_addr, hole_addr+KERNEL_ACCESS_TOP, -1); + ret = fdt_add_mem_rsv(blob_buf, *dtb_addr, PAGE_ALIGN(*blob_size)); + if (ret) { + printf("%s: Unable to add new reserved memory for the flat device tree\n", + fdt_strerror(ret)); + } + + return blob_buf; +} + +#ifdef DEBUG +static void save_fixed_up_dtb(char *blob_buf, off_t blob_size) +{ + FILE *fp; + + fp = fopen("debug.dtb", "w"); + if (fp) { + if ( blob_size == fwrite(blob_buf, sizeof(char), blob_size, fp)) { + printf("debug.dtb written\n"); + } else { + printf("Unable to write debug.dtb\n"); + } + } else { + printf("Unable to dump flat device tree to debug.dtb\n"); + } +} +#endif + +char *fixup_dtb_finalize(struct kexec_info *info, char *blob_buf, off_t *blob_size, + char *nodes[], char *cmdline) +{ fixup_nodes(nodes); fixup_cmdline(cmdline); + fixup_reserve_regions(info, blob_buf, blob_size); + fixup_memory(info, blob_buf); + fixup_initrd(blob_buf); + fixup_crashkernel(info, blob_buf); blob_buf = (char *)dt_ops.finalize(); *blob_size = fdt_totalsize(blob_buf); + +#ifdef DEBUG + save_fixed_up_dtb(blob_buf, *blob_size); +#endif + return blob_buf; } diff --git a/kexec/arch/ppc/fixup_dtb.h b/kexec/arch/ppc/fixup_dtb.h index 0ff981e..b706a5a 100644 --- a/kexec/arch/ppc/fixup_dtb.h +++ b/kexec/arch/ppc/fixup_dtb.h @@ -1,6 +1,10 @@ #ifndef __FIXUP_DTB_H #define __FIXUP_DTB_H -char *fixup_dtb_nodes(char *blob_buf, off_t *blob_size, char *nodes[], char *cmdline); +char *fixup_dtb_init(struct kexec_info *info, char *blob_buf, off_t *blob_size, + unsigned long hole_addr, unsigned long *dtb_addr); + +char *fixup_dtb_finalize(struct kexec_info *info, char *blob_buf, off_t *blob_size, + char *nodes[], char *cmdline); #endif diff --git a/kexec/arch/ppc/kexec-elf-ppc.c b/kexec/arch/ppc/kexec-elf-ppc.c index daf7a34..f4443b4 100644 --- a/kexec/arch/ppc/kexec-elf-ppc.c +++ b/kexec/arch/ppc/kexec-elf-ppc.c @@ -175,23 +175,20 @@ int elf_ppc_load(int argc, char **argv, const char *buf, off_t len, unsigned char *setup_start; uint32_t setup_size; #else - unsigned long long *rsvmap_ptr; - struct bootblock *bb_ptr; - unsigned int nr_segments; - unsigned long my_kernel, my_dt_offset; - unsigned long my_stack, my_backup_start; - unsigned int slave_code[256 / sizeof(unsigned int)], master_entry; char *seg_buf = NULL; off_t seg_size = 0; int target_is_gamecube = 0; unsigned int addr; unsigned long dtb_addr; + unsigned long dtb_addr_actual; #endif unsigned long kernel_addr; #define FIXUP_ENTRYS (20) char *fixup_nodes[FIXUP_ENTRYS + 1]; int cur_fixup = 0; int opt; + char *blob_buf = NULL; + off_t blob_size = 0; command_line = NULL; dtb = NULL; @@ -351,137 +348,75 @@ int elf_ppc_load(int argc, char **argv, const char *buf, off_t len, elf_rel_build_load(info, &info->rhdr, (const char *)purgatory, purgatory_size, 0, elf_max_addr(&ehdr), 1, 0); - if (ramdisk) - { + /* Here we need to initialize the device tree, and find out where + * it is going to live so we can place it directly after the + * kernel image */ + if (dtb) { + /* Grab device tree from buffer */ + blob_buf = slurp_file(dtb, &blob_size); + } else { + create_flatten_tree(info, (unsigned char **)&blob_buf, + (unsigned long *)&blob_size, cmdline_buf); + } + if (!blob_buf || !blob_size) + die("Device tree seems to be an empty file.\n"); + + /* initial fixup for device tree */ + blob_buf = fixup_dtb_init(info, blob_buf, &blob_size, kernel_addr, &dtb_addr); + + if (ramdisk) { seg_buf = slurp_file(ramdisk, &seg_size); + /* load the ramdisk *above* the device tree */ hole_addr = add_buffer(info, seg_buf, seg_size, seg_size, - 0, 0, max_addr, 1); + 0, dtb_addr + blob_size + 1, max_addr, -1); ramdisk_base = hole_addr; ramdisk_size = seg_size; } - if (reuse_initrd) - { + if (reuse_initrd) { ramdisk_base = initrd_base; ramdisk_size = initrd_size; } if (info->kexec_flags & KEXEC_ON_CRASH && ramdisk_base != 0) { if ( (ramdisk_base < crash_base) || - (ramdisk_base > crash_base + crash_size) ) - { + (ramdisk_base > crash_base + crash_size) ) { printf("WARNING: ramdisk is above crashkernel region!\n"); } - else if (ramdisk_base + initrd_size > crash_base + crash_size) - { + else if (ramdisk_base + initrd_size > crash_base + crash_size) { printf("WARNING: ramdisk overflows crashkernel region!\n"); } } - if (dtb) { - char *blob_buf; - off_t blob_size = 0; - - /* Grab device tree from buffer */ - blob_buf = slurp_file(dtb, &blob_size); - if (!blob_buf || !blob_size) - die("Device tree seems to be an empty file.\n"); - - blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes, - cmdline_buf); - dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, kernel_addr, - kernel_addr + KERNEL_ACCESS_TOP, -1); - } else { - /* create from fs2dt */ - seg_buf = NULL; - seg_size = 0; - create_flatten_tree(info, (unsigned char **)&seg_buf, - (unsigned long *)&seg_size, cmdline_buf); - add_buffer(info, seg_buf, seg_size, seg_size, -#ifdef CONFIG_PPC64 - 0, 0, max_addr, -1); -#else - /* load dev tree at 16 Mb offset from kernel load address */ - 0, 0, ehdr.e_phdr[0].p_paddr + SIZE_16M, -1); -#endif + /* Perform final fixup on devie tree, i.e. everything beside what + * was done above */ + fixup_dtb_finalize(info, blob_buf, &blob_size, fixup_nodes, + cmdline_buf); + dtb_addr_actual = add_buffer(info, blob_buf, blob_size, blob_size, 0, dtb_addr, + kernel_addr + KERNEL_ACCESS_TOP, 1); + if (dtb_addr_actual != dtb_addr) { + die("Error device tree not loadded to address it was expecting to be loaded too!\n"); } + /* set various variables for the purgatory ehdr.e_entry is a + * virtual address, we can use kernel_addr which + * should be the physical start address of the kernel */ + addr = kernel_addr; + elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr)); - if (dtb) { - /* set various variables for the purgatory ehdr.e_entry is a - * virtual address, we can use kernel_addr which - * should be the physical start address of the kernel */ - addr = kernel_addr; - elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr)); - - addr = dtb_addr; - elf_rel_set_symbol(&info->rhdr, "dt_offset", - &addr, sizeof(addr)); + addr = dtb_addr; + elf_rel_set_symbol(&info->rhdr, "dt_offset", + &addr, sizeof(addr)); #define PUL_STACK_SIZE (16 * 1024) - addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, + addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, elf_max_addr(&ehdr), 1); - addr += PUL_STACK_SIZE; - elf_rel_set_symbol(&info->rhdr, "stack", &addr, sizeof(addr)); + addr += PUL_STACK_SIZE; + elf_rel_set_symbol(&info->rhdr, "stack", &addr, sizeof(addr)); #undef PUL_STACK_SIZE - addr = elf_rel_get_addr(&info->rhdr, "purgatory_start"); - info->entry = (void *)addr; - - } else { /*from fs2dt*/ - - /* patch reserve map address for flattened device-tree - * find last entry (both 0) in the reserve mem list. Assume DT - * entry is before this one - */ - bb_ptr = (struct bootblock *)( - (unsigned char *)info->segment[(info->nr_segments) - - 1].buf); - rsvmap_ptr = (unsigned long long *)( - (unsigned char *)info->segment[(info->nr_segments) - - 1].buf + bb_ptr->off_mem_rsvmap); - while (*rsvmap_ptr || *(rsvmap_ptr + 1)) - rsvmap_ptr += 2; - rsvmap_ptr -= 2; - *rsvmap_ptr = (unsigned long)( - info->segment[(info->nr_segments)-1].mem); - rsvmap_ptr++; - *rsvmap_ptr = (unsigned long long)bb_ptr->totalsize; - - nr_segments = info->nr_segments; - - /* Set kernel */ - my_kernel = (unsigned long)info->segment[0].mem; - elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel, - sizeof(my_kernel)); - - /* Set dt_offset */ - my_dt_offset = (unsigned long)info->segment[nr_segments - - 1].mem; - elf_rel_set_symbol(&info->rhdr, "dt_offset", &my_dt_offset, - sizeof(my_dt_offset)); - - /* get slave code from new kernel, put in purgatory */ - elf_rel_get_symbol(&info->rhdr, "purgatory_start", slave_code, - sizeof(slave_code)); - master_entry = slave_code[0]; - memcpy(slave_code, info->segment[0].buf, sizeof(slave_code)); - slave_code[0] = master_entry; - elf_rel_set_symbol(&info->rhdr, "purgatory_start", slave_code, - sizeof(slave_code)); - - /* Set stack address */ - my_stack = locate_hole(info, 16*1024, 0, 0, max_addr, 1); - my_stack += 16*1024; - elf_rel_set_symbol(&info->rhdr, "stack", &my_stack, - sizeof(my_stack)); - } - - if (info->kexec_flags & KEXEC_ON_CRASH) { - /* Set backup address */ - my_backup_start = info->backup_start; - elf_rel_set_symbol(&info->rhdr, "backup_start", - &my_backup_start, sizeof(my_backup_start)); - } + addr = elf_rel_get_addr(&info->rhdr, "purgatory_start"); + info->entry = (void *)addr; #endif + return 0; } diff --git a/kexec/arch/ppc/kexec-ppc.h b/kexec/arch/ppc/kexec-ppc.h index d25138a..7f96be8 100644 --- a/kexec/arch/ppc/kexec-ppc.h +++ b/kexec/arch/ppc/kexec-ppc.h @@ -64,6 +64,7 @@ typedef struct mem_rgns { } mem_rgns_t; extern mem_rgns_t usablemem_rgns; extern int max_memory_ranges; +extern unsigned long long crash_base, crash_size; extern unsigned long long initrd_base, initrd_size; extern unsigned long long ramdisk_base, ramdisk_size; extern unsigned char reuse_initrd; diff --git a/kexec/arch/ppc/kexec-uImage-ppc.c b/kexec/arch/ppc/kexec-uImage-ppc.c index 310d6c3..1d71374 100644 --- a/kexec/arch/ppc/kexec-uImage-ppc.c +++ b/kexec/arch/ppc/kexec-uImage-ppc.c @@ -17,6 +17,9 @@ #include "crashdump-powerpc.h" #include <limits.h> +int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *, + char *); + /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS @@ -57,6 +60,7 @@ static int ppc_load_bare_bits(int argc, char **argv, const char *buf, char *dtb; unsigned int addr; unsigned long dtb_addr; + unsigned long dtb_addr_actual; #define FIXUP_ENTRYS (20) char *fixup_nodes[FIXUP_ENTRYS + 1]; int cur_fixup = 0; @@ -66,6 +70,8 @@ static int ppc_load_bare_bits(int argc, char **argv, const char *buf, off_t seg_size = 0; unsigned long long hole_addr; unsigned long max_addr; + char *blob_buf = NULL; + off_t blob_size = 0; cmdline_buf = NULL; command_line = NULL; @@ -155,50 +161,59 @@ static int ppc_load_bare_bits(int argc, char **argv, const char *buf, sizeof(crash_cmdline) - strlen(crash_cmdline) - 1); - if (ramdisk) - { + elf_rel_build_load(info, &info->rhdr, (const char *)purgatory, + purgatory_size, 0, -1, -1, 0); + + /* Here we need to initialize the device tree, and find out where + * it is going to live so we can place it directly after the + * kernel image */ + if (dtb) { + /* Grab device tree from buffer */ + blob_buf = slurp_file(dtb, &blob_size); + } else { + create_flatten_tree(info, (unsigned char **)&blob_buf, + (unsigned long *)&blob_size, cmdline_buf); + } + if (!blob_buf || !blob_size) + die("Device tree seems to be an empty file.\n"); + + /* initial fixup for device tree */ + blob_buf = fixup_dtb_init(info, blob_buf, &blob_size, load_addr, &dtb_addr); + + if (ramdisk) { seg_buf = slurp_file(ramdisk, &seg_size); + /* Load ramdisk at top of memory */ hole_addr = add_buffer(info, seg_buf, seg_size, seg_size, - 0, 0, max_addr, 1); + 0, dtb_addr + blob_size, max_addr, -1); ramdisk_base = hole_addr; ramdisk_size = seg_size; } - if (reuse_initrd) - { + if (reuse_initrd) { ramdisk_base = initrd_base; ramdisk_size = initrd_size; } if (info->kexec_flags & KEXEC_ON_CRASH && ramdisk_base != 0) { if ( (ramdisk_base < crash_base) || - (ramdisk_base > crash_base + crash_size) ) - { + (ramdisk_base > crash_base + crash_size) ) { printf("WARNING: ramdisk is above crashkernel region!\n"); } - else if (ramdisk_base + ramdisk_size > crash_base + crash_size) - { + else if (ramdisk_base + ramdisk_size > crash_base + crash_size) { printf("WARNING: ramdisk overflows crashkernel region!\n"); } } - if (dtb) { - char *blob_buf; - off_t blob_size = 0; - - /* Grab device tree from buffer */ - blob_buf = slurp_file(dtb, &blob_size); - if (!blob_buf || !blob_size) - die("Device tree seems to be an empty file.\n"); - blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes, cmdline_buf); - dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, load_addr, - load_addr + KERNEL_ACCESS_TOP, -1); - } else { - dtb_addr = 0; + /* Perform final fixup on devie tree, i.e. everything beside what + * was done above */ + fixup_dtb_finalize(info, blob_buf, &blob_size, fixup_nodes, + cmdline_buf); + dtb_addr_actual = add_buffer(info, blob_buf, blob_size, blob_size, 0, dtb_addr, + load_addr + KERNEL_ACCESS_TOP, 1); + if (dtb_addr_actual != dtb_addr) { + printf("dtb_addr_actual: %lx, dtb_addr: %lx\n", dtb_addr_actual, dtb_addr); + die("Error device tree not loadded to address it was expecting to be loaded too!\n"); } - elf_rel_build_load(info, &info->rhdr, (const char *)purgatory, - purgatory_size, 0, -1, -1, 0); - /* set various variables for the purgatory */ addr = ep; elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr)); diff --git a/kexec/arch/ppc/ops.h b/kexec/arch/ppc/ops.h index f33e941..a2eb140 100644 --- a/kexec/arch/ppc/ops.h +++ b/kexec/arch/ppc/ops.h @@ -147,5 +147,4 @@ static inline char *get_path(const void *phandle, char *buf, int len) #define fatal(args...) { printf(args); exit(1); } -char *fixup_dtb_nodes(char *blob_buf, off_t *blob_size, char *nodes[], char *cmdline); #endif /* _PPC_BOOT_OPS_H_ */ |