diff options
Diffstat (limited to 'kexec/arch/ia64/kexec-elf-ia64.c')
-rw-r--r-- | kexec/arch/ia64/kexec-elf-ia64.c | 60 |
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; } |