summaryrefslogtreecommitdiff
path: root/kexec/arch/ppc/kexec-elf-ppc.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/arch/ppc/kexec-elf-ppc.c')
-rw-r--r--kexec/arch/ppc/kexec-elf-ppc.c108
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;
}