/* Patch stub to reference function and correct r2 value. */ static inline int create_stub(Elf64_Shdr *sechdrs, struct ppc64_stub_entry *entry, unsigned long addr, struct module *me) { long reladdr; memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns)); /* Stub uses address relative to r2. */ reladdr = (unsigned long)entry - my_r2(sechdrs, me); if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { pr_err("%s: Address %p of stub out of range of %p.\n", me->name, (void *)reladdr, (void *)my_r2); return 0; } pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr); entry->jump[0] |= PPC_HA(reladdr); entry->jump[1] |= PPC_LO(reladdr); entry->funcdata = func_desc(addr); return 1; }
void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type, void *location, unsigned long address, unsigned long value) { switch(r_type) { case R_PPC64_ADDR32: /* Simply set it */ *(uint32_t *)location = value; break; case R_PPC64_ADDR64: case R_PPC64_REL64: /* Simply set it */ *(uint64_t *)location = value; break; case R_PPC64_REL32: *(uint32_t *)location = value - (uint32_t)(uint64_t)location; break; case R_PPC64_TOC: *(uint64_t *)location = my_r2(ehdr); break; case R_PPC64_TOC16_DS: /* Subtact TOC pointer */ value -= my_r2(ehdr); if ((value & 3) != 0 || value + 0x8000 > 0xffff) { die("bad TOC16_DS relocation (%lu)\n", value); } *((uint16_t *) location) = (*((uint16_t *) location) & ~0xfffc) | (value & 0xfffc); break; case R_PPC64_REL24: /* Convert value to relative */ value -= address; if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){ die("REL24 %li out of range!\n", (long int)value); } /* Only replace bits 2 through 26 */ *(uint32_t *)location = (*(uint32_t *)location & ~0x03fffffc) | (value & 0x03fffffc); break; case R_PPC64_ADDR16_LO: *(uint16_t *)location = value & 0xffff; break; case R_PPC64_ADDR16_HI: *(uint16_t *)location = (value>>16) & 0xffff; break; case R_PPC64_ADDR16_HA: *(uint16_t *)location = (((value+0x8000)>>16) & 0xffff); break; case R_PPC64_ADDR16_HIGHEST: *(uint16_t *)location = (((uint64_t)value>>48) & 0xffff); break; case R_PPC64_ADDR16_HIGHER: *(uint16_t *)location = (((uint64_t)value>>32) & 0xffff); break; default: die("Unknown rela relocation: %lu\n", r_type); break; } return; }
void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *sym, unsigned long r_type, void *location, unsigned long address, unsigned long value) { switch(r_type) { case R_PPC64_ADDR32: /* Simply set it */ *(uint32_t *)location = value; break; case R_PPC64_ADDR64: case R_PPC64_REL64: /* Simply set it */ *(uint64_t *)location = value; break; case R_PPC64_REL32: *(uint32_t *)location = value - (uint32_t)(uint64_t)location; break; case R_PPC64_TOC: *(uint64_t *)location = my_r2(ehdr); break; case R_PPC64_TOC16: do_relative_toc(value - my_r2(ehdr), location, 0xffff, 1); break; case R_PPC64_TOC16_DS: do_relative_toc(value - my_r2(ehdr), location, 0xfffc, 1); break; case R_PPC64_TOC16_LO: do_relative_toc(value - my_r2(ehdr), location, 0xffff, 0); break; case R_PPC64_TOC16_LO_DS: do_relative_toc(value - my_r2(ehdr), location, 0xfffc, 0); break; case R_PPC64_TOC16_HI: do_relative_toc((value - my_r2(ehdr)) >> 16, location, 0xffff, 0); break; case R_PPC64_TOC16_HA: do_relative_toc((value - my_r2(ehdr) + 0x8000) >> 16, location, 0xffff, 0); break; case R_PPC64_REL24: value += local_entry_offset(sym); /* Convert value to relative */ value -= address; if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0) { die("REL24 %li out of range!\n", (long int)value); } /* Only replace bits 2 through 26 */ *(uint32_t *)location = (*(uint32_t *)location & ~0x03fffffc) | (value & 0x03fffffc); break; case R_PPC64_ADDR16_LO: *(uint16_t *)location = value & 0xffff; break; case R_PPC64_ADDR16_HI: *(uint16_t *)location = (value >> 16) & 0xffff; break; case R_PPC64_ADDR16_HA: *(uint16_t *)location = (((value + 0x8000) >> 16) & 0xffff); break; case R_PPC64_ADDR16_HIGHER: *(uint16_t *)location = (((uint64_t)value >> 32) & 0xffff); break; case R_PPC64_ADDR16_HIGHEST: *(uint16_t *)location = (((uint64_t)value >> 48) & 0xffff); break; /* R_PPC64_REL16_HA and R_PPC64_REL16_LO are handled to support * ABIv2 r2 assignment based on r12 for PIC executable. * Here address is know so replace * 0: addis 2,12,.TOC.-0b@ha * addi 2,2,.TOC.-0b@l * by * lis 2,.TOC.@ha * addi 2,2,.TOC.@l */ case R_PPC64_REL16_HA: /* check that we are dealing with the addis 2,12 instruction */ if (((*(uint32_t*)location) & 0xffff0000) != 0x3c4c0000) die("Unexpected instruction for R_PPC64_REL16_HA"); value += my_r2(ehdr); /* replacing by lis 2 */ *(uint32_t *)location = 0x3c400000 + ((value >> 16) & 0xffff); break; case R_PPC64_REL16_LO: /* check that we are dealing with the addi 2,2 instruction */ if (((*(uint32_t*)location) & 0xffff0000) != 0x38420000) die("Unexpected instruction for R_PPC64_REL16_LO"); value += my_r2(ehdr) - 4; *(uint16_t *)location = value & 0xffff; break; default: die("Unknown rela relocation: %lu\n", r_type); break; } }
int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; char *cmdline, *modified_cmdline = NULL; const char *devicetreeblob; int cmdline_len, modified_cmdline_len; uint64_t max_addr, hole_addr; unsigned char *seg_buf = NULL; off_t seg_size = 0; struct mem_phdr *phdr; size_t size; uint64_t *rsvmap_ptr; struct bootblock *bb_ptr; unsigned int nr_segments, i; int result, opt; uint64_t my_kernel, my_dt_offset; unsigned int my_panic_kernel; uint64_t my_stack, my_backup_start; uint64_t toc_addr; unsigned int slave_code[256/sizeof (unsigned int)], master_entry; #define OPT_APPEND (OPT_ARCH_MAX+0) #define OPT_RAMDISK (OPT_ARCH_MAX+1) #define OPT_DEVICETREEBLOB (OPT_ARCH_MAX+2) #define OPT_ARGS_IGNORE (OPT_ARCH_MAX+3) static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, NULL, OPT_APPEND }, { "append", 1, NULL, OPT_APPEND }, { "ramdisk", 1, NULL, OPT_RAMDISK }, { "initrd", 1, NULL, OPT_RAMDISK }, { "devicetreeblob", 1, NULL, OPT_DEVICETREEBLOB }, { "args-linux", 0, NULL, OPT_ARGS_IGNORE }, { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_OPT_STR ""; /* Parse command line arguments */ initrd_base = 0; initrd_size = 0; cmdline = 0; ramdisk = 0; devicetreeblob = 0; max_addr = 0xFFFFFFFFFFFFFFFFUL; hole_addr = 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: cmdline = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_DEVICETREEBLOB: devicetreeblob = optarg; break; case OPT_ARGS_IGNORE: break; } } cmdline_len = 0; if (cmdline) cmdline_len = strlen(cmdline) + 1; else fprintf(stdout, "Warning: append= option is not passed. Using the first kernel root partition\n"); if (ramdisk && reuse_initrd) die("Can't specify --ramdisk or --initrd with --reuseinitrd\n"); setup_memory_ranges(info->kexec_flags); /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & KEXEC_ON_CRASH) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (cmdline) { strncpy(modified_cmdline, cmdline, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } modified_cmdline_len = strlen(modified_cmdline); } /* Parse the Elf file */ result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) { free_elf_info(&ehdr); return result; } /* Load the Elf data. Physical load addresses in elf64 header do not * show up correctly. Use user supplied address for now to patch the * elf header */ phdr = &ehdr.e_phdr[0]; size = phdr->p_filesz; if (size > phdr->p_memsz) size = phdr->p_memsz; hole_addr = (uint64_t)locate_hole(info, size, 0, 0, max_addr, 1); ehdr.e_phdr[0].p_paddr = hole_addr; result = elf_exec_load(&ehdr, info); if (result < 0) { free_elf_info(&ehdr); return result; } /* If panic kernel is being loaded, additional segments need * to be created. */ if (info->kexec_flags & KEXEC_ON_CRASH) { result = load_crashdump_segments(info, modified_cmdline, max_addr, 0); if (result < 0) return -1; /* Use new command line. */ cmdline = modified_cmdline; cmdline_len = strlen(modified_cmdline) + 1; } /* Add v2wrap to the current image */ seg_buf = NULL; seg_size = 0; seg_buf = (unsigned char *) malloc(purgatory_size); if (seg_buf == NULL) { free_elf_info(&ehdr); return -1; } memcpy(seg_buf, purgatory, purgatory_size); seg_size = purgatory_size; elf_rel_build_load(info, &info->rhdr, (const char *)purgatory, purgatory_size, 0, max_addr, 1, 0); /* Add a ram-disk to the current image * Note: Add the ramdisk after elf_rel_build_load */ if (ramdisk) { if (devicetreeblob) { fprintf(stderr, "Can't use ramdisk with device tree blob input\n"); return -1; } seg_buf = (unsigned char *)slurp_file(ramdisk, &seg_size); add_buffer(info, seg_buf, seg_size, seg_size, 0, 0, max_addr, 1); hole_addr = (uint64_t) info->segment[info->nr_segments-1].mem; initrd_base = hole_addr; initrd_size = (uint64_t) info->segment[info->nr_segments-1].memsz; } /* ramdisk */ if (devicetreeblob) { unsigned char *blob_buf = NULL; off_t blob_size = 0; /* Grab device tree from buffer */ blob_buf = (unsigned char *)slurp_file(devicetreeblob, &blob_size); add_buffer(info, blob_buf, blob_size, blob_size, 0, 0, max_addr, -1); } else { /* create from fs2dt */ seg_buf = NULL; seg_size = 0; create_flatten_tree(info, (unsigned char **)&seg_buf, (unsigned long *)&seg_size,cmdline); add_buffer(info, seg_buf, seg_size, seg_size, 0, 0, max_addr, -1); } /* 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 = (uint64_t *)( (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 = (uint64_t)( info->segment[(info->nr_segments)-1].mem); rsvmap_ptr++; *rsvmap_ptr = (uint64_t)bb_ptr->totalsize; nr_segments = info->nr_segments; /* Set kernel */ my_kernel = (uint64_t)info->segment[0].mem; elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel)); /* Set dt_offset */ my_dt_offset = (uint64_t)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)); if (info->kexec_flags & KEXEC_ON_CRASH) { my_panic_kernel = 1; /* Set panic flag */ elf_rel_set_symbol(&info->rhdr, "panic_kernel", &my_panic_kernel, sizeof(my_panic_kernel)); /* Set backup address */ my_backup_start = info->backup_start; elf_rel_set_symbol(&info->rhdr, "backup_start", &my_backup_start, sizeof(my_backup_start)); } /* 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)); /* Set toc */ toc_addr = (unsigned long) my_r2(&info->rhdr); elf_rel_set_symbol(&info->rhdr, "my_toc", &toc_addr, sizeof(toc_addr)); #ifdef DEBUG my_kernel = 0; my_dt_offset = 0; my_panic_kernel = 0; my_backup_start = 0; my_stack = 0; toc_addr = 0; elf_rel_get_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel)); elf_rel_get_symbol(&info->rhdr, "dt_offset", &my_dt_offset, sizeof(my_dt_offset)); elf_rel_get_symbol(&info->rhdr, "panic_kernel", &my_panic_kernel, sizeof(my_panic_kernel)); elf_rel_get_symbol(&info->rhdr, "backup_start", &my_backup_start, sizeof(my_backup_start)); elf_rel_get_symbol(&info->rhdr, "stack", &my_stack, sizeof(my_stack)); elf_rel_get_symbol(&info->rhdr, "my_toc", &toc_addr, sizeof(toc_addr)); fprintf(stderr, "info->entry is %p\n", info->entry); fprintf(stderr, "kernel is %lx\n", my_kernel); fprintf(stderr, "dt_offset is %lx\n", my_dt_offset); fprintf(stderr, "panic_kernel is %x\n", my_panic_kernel); fprintf(stderr, "backup_start is %lx\n", my_backup_start); fprintf(stderr, "stack is %lx\n", my_stack); fprintf(stderr, "toc_addr is %lx\n", toc_addr); fprintf(stderr, "purgatory size is %lu\n", purgatory_size); #endif for (i = 0; i < nr_segments; i++) fprintf(stderr, "segment[%d].mem:%p memsz:%ld\n", i, info->segment[i].mem, info->segment[i].memsz); return 0; }
int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me) { unsigned int i; Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr; Elf64_Sym *sym; unsigned long *location; unsigned long value; pr_debug("Applying ADD relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); /* First time we're called, we can fix up .TOC. */ if (!me->arch.toc_fixed) { sym = find_dot_toc(sechdrs, strtab, symindex); /* It's theoretically possible that a module doesn't want a * .TOC. so don't fail it just for that. */ if (sym) sym->st_value = my_r2(sechdrs, me); me->arch.toc_fixed = true; } for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { /* This is where to make the change */ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rela[i].r_offset; /* This is the symbol it is referring to */ sym = (Elf64_Sym *)sechdrs[symindex].sh_addr + ELF64_R_SYM(rela[i].r_info); pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n", location, (long)ELF64_R_TYPE(rela[i].r_info), strtab + sym->st_name, (unsigned long)sym->st_value, (long)rela[i].r_addend); /* `Everything is relative'. */ value = sym->st_value + rela[i].r_addend; switch (ELF64_R_TYPE(rela[i].r_info)) { case R_PPC64_ADDR32: /* Simply set it */ *(u32 *)location = value; break; case R_PPC64_ADDR64: /* Simply set it */ *(unsigned long *)location = value; break; case R_PPC64_TOC: *(unsigned long *)location = my_r2(sechdrs, me); break; case R_PPC64_TOC16: /* Subtract TOC pointer */ value -= my_r2(sechdrs, me); if (value + 0x8000 > 0xffff) { pr_err("%s: bad TOC16 relocation (0x%lx)\n", me->name, value); return -ENOEXEC; } *((uint16_t *) location) = (*((uint16_t *) location) & ~0xffff) | (value & 0xffff); break; case R_PPC64_TOC16_LO: /* Subtract TOC pointer */ value -= my_r2(sechdrs, me); *((uint16_t *) location) = (*((uint16_t *) location) & ~0xffff) | (value & 0xffff); break; case R_PPC64_TOC16_DS: /* Subtract TOC pointer */ value -= my_r2(sechdrs, me); if ((value & 3) != 0 || value + 0x8000 > 0xffff) { pr_err("%s: bad TOC16_DS relocation (0x%lx)\n", me->name, value); return -ENOEXEC; } *((uint16_t *) location) = (*((uint16_t *) location) & ~0xfffc) | (value & 0xfffc); break; case R_PPC64_TOC16_LO_DS: /* Subtract TOC pointer */ value -= my_r2
int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; char *cmdline, *modified_cmdline = NULL; const char *devicetreeblob; uint64_t max_addr, hole_addr; char *seg_buf = NULL; off_t seg_size = 0; struct mem_phdr *phdr; size_t size; #ifdef NEED_RESERVE_DTB uint64_t *rsvmap_ptr; struct bootblock *bb_ptr; #endif int result, opt; uint64_t my_kernel, my_dt_offset; uint64_t my_opal_base = 0, my_opal_entry = 0; unsigned int my_panic_kernel; uint64_t my_stack, my_backup_start; uint64_t toc_addr; uint32_t my_run_at_load; unsigned int slave_code[256/sizeof (unsigned int)], master_entry; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, NULL, OPT_APPEND }, { "append", 1, NULL, OPT_APPEND }, { "ramdisk", 1, NULL, OPT_RAMDISK }, { "initrd", 1, NULL, OPT_RAMDISK }, { "devicetreeblob", 1, NULL, OPT_DEVICETREEBLOB }, { "dtb", 1, NULL, OPT_DEVICETREEBLOB }, { "args-linux", 0, NULL, OPT_ARGS_IGNORE }, { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_OPT_STR ""; if (info->file_mode) return elf_ppc64_load_file(argc, argv, info); /* Parse command line arguments */ initrd_base = 0; initrd_size = 0; cmdline = 0; ramdisk = 0; devicetreeblob = 0; max_addr = 0xFFFFFFFFFFFFFFFFULL; hole_addr = 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 OPT_APPEND: cmdline = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_DEVICETREEBLOB: devicetreeblob = optarg; break; case OPT_ARGS_IGNORE: break; } } if (!cmdline) fprintf(stdout, "Warning: append= option is not passed. Using the first kernel root partition\n"); if (ramdisk && reuse_initrd) die("Can't specify --ramdisk or --initrd with --reuseinitrd\n"); /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & KEXEC_ON_CRASH) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (cmdline) { strncpy(modified_cmdline, cmdline, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } } /* Parse the Elf file */ result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) { free_elf_info(&ehdr); return result; } /* Load the Elf data. Physical load addresses in elf64 header do not * show up correctly. Use user supplied address for now to patch the * elf header */ phdr = &ehdr.e_phdr[0]; size = phdr->p_filesz; if (size > phdr->p_memsz) size = phdr->p_memsz; my_kernel = hole_addr = locate_hole(info, size, 0, 0, max_addr, 1); ehdr.e_phdr[0].p_paddr = hole_addr; result = elf_exec_load(&ehdr, info); if (result < 0) { free_elf_info(&ehdr); return result; } /* If panic kernel is being loaded, additional segments need * to be created. */ if (info->kexec_flags & KEXEC_ON_CRASH) { result = load_crashdump_segments(info, modified_cmdline, max_addr, 0); if (result < 0) return -1; /* Use new command line. */ cmdline = modified_cmdline; } /* Add v2wrap to the current image */ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0, max_addr, 1, 0); /* Add a ram-disk to the current image * Note: Add the ramdisk after elf_rel_build_load */ if (ramdisk) { if (devicetreeblob) { fprintf(stderr, "Can't use ramdisk with device tree blob input\n"); return -1; } seg_buf = slurp_file(ramdisk, &seg_size); hole_addr = add_buffer(info, seg_buf, seg_size, seg_size, 0, 0, max_addr, 1); initrd_base = hole_addr; initrd_size = seg_size; } /* ramdisk */ if (devicetreeblob) { /* Grab device tree from buffer */ seg_buf = slurp_file(devicetreeblob, &seg_size); } else { /* create from fs2dt */ create_flatten_tree(&seg_buf, &seg_size, cmdline); } result = fixup_dt(&seg_buf, &seg_size); if (result < 0) return result; my_dt_offset = add_buffer(info, seg_buf, seg_size, seg_size, 0, 0, max_addr, -1); #ifdef NEED_RESERVE_DTB /* 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 *)(seg_buf); rsvmap_ptr = (uint64_t *)(seg_buf + be32_to_cpu(bb_ptr->off_mem_rsvmap)); while (*rsvmap_ptr || *(rsvmap_ptr+1)) rsvmap_ptr += 2; rsvmap_ptr -= 2; *rsvmap_ptr = cpu_to_be64(my_dt_offset); rsvmap_ptr++; *rsvmap_ptr = cpu_to_be64((uint64_t)be32_to_cpu(bb_ptr->totalsize)); #endif if (read_prop("/proc/device-tree/ibm,opal/opal-base-address", &my_opal_base, sizeof(my_opal_base)) == 0) { my_opal_base = be64_to_cpu(my_opal_base); elf_rel_set_symbol(&info->rhdr, "opal_base", &my_opal_base, sizeof(my_opal_base)); } if (read_prop("/proc/device-tree/ibm,opal/opal-entry-address", &my_opal_entry, sizeof(my_opal_entry)) == 0) { my_opal_entry = be64_to_cpu(my_opal_entry); elf_rel_set_symbol(&info->rhdr, "opal_entry", &my_opal_entry, sizeof(my_opal_entry)); } /* Set kernel */ elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel)); /* Set dt_offset */ 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, phdr->p_data, sizeof(slave_code)); slave_code[0] = master_entry; elf_rel_set_symbol(&info->rhdr, "purgatory_start", slave_code, sizeof(slave_code)); if (info->kexec_flags & KEXEC_ON_CRASH) { my_panic_kernel = 1; /* Set panic flag */ elf_rel_set_symbol(&info->rhdr, "panic_kernel", &my_panic_kernel, sizeof(my_panic_kernel)); /* Set backup address */ my_backup_start = info->backup_start; elf_rel_set_symbol(&info->rhdr, "backup_start", &my_backup_start, sizeof(my_backup_start)); /* Tell relocatable kernel to run at load address * via word before slave code in purgatory */ elf_rel_get_symbol(&info->rhdr, "run_at_load", &my_run_at_load, sizeof(my_run_at_load)); if (my_run_at_load == KERNEL_RUN_AT_ZERO_MAGIC) my_run_at_load = 1; /* else it should be a fixed offset image */ elf_rel_set_symbol(&info->rhdr, "run_at_load", &my_run_at_load, sizeof(my_run_at_load)); } /* 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)); /* Set toc */ toc_addr = my_r2(&info->rhdr); elf_rel_set_symbol(&info->rhdr, "my_toc", &toc_addr, sizeof(toc_addr)); /* Set debug */ elf_rel_set_symbol(&info->rhdr, "debug", &my_debug, sizeof(my_debug)); my_kernel = 0; my_dt_offset = 0; my_panic_kernel = 0; my_backup_start = 0; my_stack = 0; toc_addr = 0; my_run_at_load = 0; my_debug = 0; my_opal_base = 0; my_opal_entry = 0; elf_rel_get_symbol(&info->rhdr, "opal_base", &my_opal_base, sizeof(my_opal_base)); elf_rel_get_symbol(&info->rhdr, "opal_entry", &my_opal_entry, sizeof(my_opal_entry)); elf_rel_get_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel)); elf_rel_get_symbol(&info->rhdr, "dt_offset", &my_dt_offset, sizeof(my_dt_offset)); elf_rel_get_symbol(&info->rhdr, "run_at_load", &my_run_at_load, sizeof(my_run_at_load)); elf_rel_get_symbol(&info->rhdr, "panic_kernel", &my_panic_kernel, sizeof(my_panic_kernel)); elf_rel_get_symbol(&info->rhdr, "backup_start", &my_backup_start, sizeof(my_backup_start)); elf_rel_get_symbol(&info->rhdr, "stack", &my_stack, sizeof(my_stack)); elf_rel_get_symbol(&info->rhdr, "my_toc", &toc_addr, sizeof(toc_addr)); elf_rel_get_symbol(&info->rhdr, "debug", &my_debug, sizeof(my_debug)); dbgprintf("info->entry is %p\n", info->entry); dbgprintf("kernel is %llx\n", (unsigned long long)my_kernel); dbgprintf("dt_offset is %llx\n", (unsigned long long)my_dt_offset); dbgprintf("run_at_load flag is %x\n", my_run_at_load); dbgprintf("panic_kernel is %x\n", my_panic_kernel); dbgprintf("backup_start is %llx\n", (unsigned long long)my_backup_start); dbgprintf("stack is %llx\n", (unsigned long long)my_stack); dbgprintf("toc_addr is %llx\n", (unsigned long long)toc_addr); dbgprintf("purgatory size is %zu\n", purgatory_size); dbgprintf("debug is %d\n", my_debug); dbgprintf("opal_base is %llx\n", (unsigned long long) my_opal_base); dbgprintf("opal_entry is %llx\n", (unsigned long long) my_opal_entry); return 0; }