summaryrefslogtreecommitdiff
path: root/kexec/arch/ia64/kexec-elf-ia64.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/arch/ia64/kexec-elf-ia64.c')
-rw-r--r--kexec/arch/ia64/kexec-elf-ia64.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/kexec/arch/ia64/kexec-elf-ia64.c b/kexec/arch/ia64/kexec-elf-ia64.c
index 4a91b95..06fe59b 100644
--- a/kexec/arch/ia64/kexec-elf-ia64.c
+++ b/kexec/arch/ia64/kexec-elf-ia64.c
@@ -6,6 +6,7 @@
* Copyright (C) 2004 Silicon Graphics, Inc.
* Jesse Barnes <jbarnes@sgi.com>
* Copyright (C) 2004 Khalid Aziz <khalid.aziz@hp.com> Hewlett Packard Co
+ * Copyright (C) 2005 Zou Nan hai <nanhai.zou@intel.com> Intel Corp
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,6 +35,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
+#include <limits.h>
#include <elf.h>
#include <boot/elf_boot.h>
#include <ip_checksum.h>
@@ -74,23 +76,29 @@ void elf_ia64_usage(void)
{
printf(
" --command-line=STRING Set the kernel command line to STRING.\n"
- " --append=STRING Set the kernel command line to STRING.\n");
+ " --append=STRING Set the kernel command line to STRING.\n"
+ " --initrd=FILE Use FILE as the kernel's initial ramdisk.\n");
}
int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
struct mem_ehdr ehdr;
- const char *command_line;
- int command_line_len;
- unsigned long entry, max_addr;
+ const char *command_line, *ramdisk=0;
+ char *ramdisk_buf = NULL;
+ off_t ramdisk_size = 0;
+ unsigned long command_line_len;
+ unsigned long entry, max_addr, gp_value;
+ unsigned command_line_base, ramdisk_base;
int result;
int opt;
#define OPT_APPEND (OPT_ARCH_MAX+0)
+#define OPT_RAMDISK (OPT_ARCH_MAX+1)
static const struct option options[] = {
KEXEC_ARCH_OPTIONS
{"command-line", 1, 0, OPT_APPEND},
{"append", 1, 0, OPT_APPEND},
+ {"initrd", 1, 0, OPT_RAMDISK},
{0, 0, 0, 0},
};
@@ -110,11 +118,14 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
case OPT_APPEND:
command_line = optarg;
break;
+ case OPT_RAMDISK:
+ ramdisk = optarg;
+ break;
}
}
command_line_len = 0;
if (command_line) {
- command_line_len = strlen(command_line) + 1;
+ command_line_len = strlen(command_line) + 16;
}
/* Parse the Elf file */
@@ -129,13 +140,46 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
/* Load the Elf data */
result = elf_exec_load(&ehdr, info);
- free_elf_info(&ehdr);
if (result < 0) {
fprintf(stderr, "ELF load failed\n");
+ free_elf_info(&ehdr);
return result;
}
+
+
+ /* Load the setup code */
+ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
+ 0x80000, ULONG_MAX, 1);
+
+ if (command_line_len) {
+ char *cmdline = xmalloc(command_line_len);
+ strcpy(cmdline, command_line);
+ command_line_len = (command_line_len + 15)&(~15);
+ elf_rel_set_symbol(&info->rhdr, "__command_line_len",
+ &command_line_len, sizeof(long));
+ command_line_base = add_buffer(info, cmdline,
+ command_line_len, command_line_len,
+ 16, 0, max_addr, 1);
+ elf_rel_set_symbol(&info->rhdr, "__command_line",
+ &command_line_base, sizeof(long));
+ }
- /* For now we don't have arguments to pass :( */
- info->entry = (void *)entry;
+ if (ramdisk) {
+ ramdisk_buf = slurp_file(ramdisk, &ramdisk_size);
+ ramdisk_base = add_buffer(info, ramdisk_buf, ramdisk_size,
+ ramdisk_size,
+ getpagesize(), 0, max_addr, 1);
+ elf_rel_set_symbol(&info->rhdr, "__ramdisk_base",
+ &ramdisk_base, sizeof(long));
+ elf_rel_set_symbol(&info->rhdr, "__ramdisk_size",
+ &ramdisk_size, sizeof(long));
+ }
+
+ gp_value = info->rhdr.rel_addr + 0x200000;
+ elf_rel_set_symbol(&info->rhdr, "__gp_value", &gp_value,
+ sizeof(gp_value));
+
+ elf_rel_set_symbol(&info->rhdr, "__kernel_entry", &entry, sizeof(entry));
+ free_elf_info(&ehdr);
return 0;
}