diff options
Diffstat (limited to 'kexec/arch/ppc/kexec-elf-ppc.c')
-rw-r--r-- | kexec/arch/ppc/kexec-elf-ppc.c | 108 |
1 files changed, 81 insertions, 27 deletions
diff --git a/kexec/arch/ppc/kexec-elf-ppc.c b/kexec/arch/ppc/kexec-elf-ppc.c index 530e501..03b8a94 100644 --- a/kexec/arch/ppc/kexec-elf-ppc.c +++ b/kexec/arch/ppc/kexec-elf-ppc.c @@ -91,16 +91,6 @@ int elf_ppc_probe(const char *buf, off_t len) return result; } -void elf_ppc_usage(void) -{ - printf - ( - " --command-line=STRING Set the kernel command line to STRING.\n" - " --append=STRING Set the kernel command line to STRING.\n" - " --gamecube=1|0 Enable/disable support for ELFs with changed\n" - " addresses suitable for the GameCube.\n"); -} - static void gamecube_hack_addresses(struct mem_ehdr *ehdr) { struct mem_phdr *phdr, *phdr_end; @@ -122,39 +112,56 @@ static void gamecube_hack_addresses(struct mem_ehdr *ehdr) } } +#define OPT_APPEND (OPT_ARCH_MAX+0) +#define OPT_GAMECUBE (OPT_ARCH_MAX+1) +#define OPT_DTB (OPT_ARCH_MAX+2) +static const struct option options[] = { + KEXEC_ARCH_OPTIONS + {"command-line", 1, 0, OPT_APPEND}, + {"append", 1, 0, OPT_APPEND}, + {"gamecube", 1, 0, OPT_GAMECUBE}, + {"dtb", 1, 0, OPT_DTB}, + {0, 0, 0, 0}, +}; +static const char short_options[] = KEXEC_ARCH_OPT_STR "d"; + +void elf_ppc_usage(void) +{ + printf( + " --command-line=STRING Set the kernel command line to STRING.\n" + " --append=STRING Set the kernel command line to STRING.\n" + " --gamecube=1|0 Enable/disable support for ELFs with changed\n" + " addresses suitable for the GameCube.\n" + " --dtb=<filename> Specify device tree blob file.\n" + ); +} + int elf_ppc_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; + char *command_line; + int command_line_len; + char *dtb; + int result; +#ifdef WITH_GAMECUBE + int target_is_gamecube = 1; char *arg_buf; size_t arg_bytes; unsigned long arg_base; struct boot_notes *notes; size_t note_bytes; - const char *command_line; - int command_line_len; unsigned char *setup_start; uint32_t setup_size; - int result; -#ifdef WITH_GAMECUBE - int target_is_gamecube = 1; #else int target_is_gamecube = 0; + unsigned int addr; + unsigned long dtb_addr; #endif int opt; -#define OPT_APPEND (OPT_ARCH_MAX+0) -#define OPT_GAMECUBE (OPT_ARCH_MAX+1) - static const struct option options[] = { - KEXEC_ARCH_OPTIONS - {"command-line", 1, 0, OPT_APPEND}, - {"append", 1, 0, OPT_APPEND}, - {"gamecube", 1, 0, OPT_GAMECUBE}, - {0, 0, 0, 0}, - }; - static const char short_options[] = KEXEC_ARCH_OPT_STR "d"; - - command_line = 0; + command_line = NULL; + dtb = NULL; while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch (opt) { default: @@ -171,6 +178,10 @@ int elf_ppc_load(int argc, char **argv, const char *buf, off_t len, case OPT_GAMECUBE: target_is_gamecube = atoi(optarg); break; + + case OPT_DTB: + dtb = optarg; + break; } } command_line_len = 0; @@ -194,6 +205,12 @@ int elf_ppc_load(int argc, char **argv, const char *buf, off_t len, return result; } + /* + * In case of a toy we take the hardcoded things and an easy setup via + * one of the assembly startups. Every thing else should be grown up + * and go through the purgatory. + */ +#ifdef WITH_GAMECUBE if (target_is_gamecube) { setup_start = setup_dol_start; setup_size = setup_dol_size; @@ -220,5 +237,42 @@ int elf_ppc_load(int argc, char **argv, const char *buf, off_t len, notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes); info->entry = (void *)arg_base; +#else + elf_rel_build_load(info, &info->rhdr, (const char *)purgatory, + purgatory_size, 0, elf_max_addr(&ehdr), 1, 0); + + if (dtb) { + char *blob_buf; + off_t blob_size = 0; + + /* Grab device tree from buffer */ + blob_buf = slurp_file(dtb, &blob_size); + dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, 0, + KERNEL_ACCESS_TOP, -1); + if (command_line) + die("Don't consider command line because dtb is supplied\n"); + } else { + die("Missing dtb.\n"); + } + + /* set various variables for the purgatory */ + addr = ehdr.e_entry; + 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 = rmo_top; + elf_rel_set_symbol(&info->rhdr, "mem_size", &addr, sizeof(addr)); + +#define PUL_STACK_SIZE (16 * 1024) + addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, elf_max_addr(&ehdr), 1); + addr += PUL_STACK_SIZE; + elf_rel_set_symbol(&info->rhdr, "pul_stack", &addr, sizeof(addr)); +#undef PUL_STACK_SIZE + + addr = elf_rel_get_addr(&info->rhdr, "purgatory_start"); + info->entry = (void *)addr; +#endif return 0; } |