[PATCH 4/4] basic kexec tools for ppc64
R Sharada
sharada at in.ibm.com
Wed Sep 14 22:48:34 EST 2005
This provides the basic functionality in kexec-elf-ppc64.c to load the various
segments required for kexec-tools on ppc64. It also adds ppc64 arch support
in build scripts and cleans up some misc error in member deferencing to allow
the build to succeed.
Signed-off-by: R Sharada <sharada at in.ibm.com>
---
kexec-tools-1.101-sharada/configure | 7
kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-elf-ppc64.c | 240 ++++++++--
kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-elf-rel-ppc64.c | 2
kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-ppc64.h | 2
4 files changed, 214 insertions(+), 37 deletions(-)
diff -puN configure~basic_kexec_tools_for_ppc64 configure
--- kexec-tools-1.101/configure~basic_kexec_tools_for_ppc64 2005-09-14 13:10:39.000000000 +0530
+++ kexec-tools-1.101-sharada/configure 2005-09-14 13:11:05.000000000 +0530
@@ -1384,6 +1384,9 @@ case $host_cpu in
powerpc )
host_cpu="ppc"
;;
+ powerpc64 )
+ host_cpu="ppc64"
+ ;;
* )
host_cpu="$host_cpu"
;;
@@ -1421,6 +1424,10 @@ if test "${with_gamecube+set}" = set; th
EXTRA_CFLAGS="$EXTRA_CFLAGS -DCONFIG_GAMECUBE=1"
fi;
+# Check whether ppc64. Add -m64 for building 64-bit binary
+if test "$ARCH"=ppc64; then
+ EXTRA_CFLAGS="$EXTRA_CFLAGS -m64"
+fi;
# Check whether --with-zlib or --without-zlib was given.
if test "${with_zlib+set}" = set; then
diff -puN kexec/arch/ppc64/kexec-elf-ppc64.c~basic_kexec_tools_for_ppc64 kexec/arch/ppc64/kexec-elf-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-ppc64.c~basic_kexec_tools_for_ppc64 2005-09-14 13:10:39.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-elf-ppc64.c 2005-09-14 13:11:05.000000000 +0530
@@ -3,6 +3,7 @@
*
* Copyright (C) 2004 Adam Litke (agl at us.ibm.com)
* Copyright (C) 2004 IBM Corp.
+ * Copyright (C) 2005 R Sharada (sharada at in.ibm.com)
*
* 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
@@ -33,45 +34,15 @@
#include "../../kexec.h"
#include "../../kexec-elf.h"
#include "kexec-ppc64.h"
+#include <arch/options.h>
#define BOOTLOADER "kexec"
#define BOOTLOADER_VERSION VERSION
#define MAX_COMMAND_LINE 256
-#define UPSZ(X) ((sizeof(X) + 3) & ~3)
-static struct boot_notes {
- Elf_Bhdr hdr;
- Elf_Nhdr bl_hdr;
- unsigned char bl_desc[UPSZ(BOOTLOADER)];
- Elf_Nhdr blv_hdr;
- unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
- Elf_Nhdr cmd_hdr;
- unsigned char command_line[0];
-} elf_boot_notes = {
- .hdr = {
- .b_signature = 0x0E1FB007,
- .b_size = sizeof(elf_boot_notes),
- .b_checksum = 0,
- .b_records = 3,
- },
- .bl_hdr = {
- .n_namesz = 0,
- .n_descsz = sizeof(BOOTLOADER),
- .n_type = EBN_BOOTLOADER_NAME,
- },
- .bl_desc = BOOTLOADER,
- .blv_hdr = {
- .n_namesz = 0,
- .n_descsz = sizeof(BOOTLOADER_VERSION),
- .n_type = EBN_BOOTLOADER_VERSION,
- },
- .blv_desc = BOOTLOADER_VERSION,
- .cmd_hdr = {
- .n_namesz = 0,
- .n_descsz = 0,
- .n_type = EBN_COMMAND_LINE,
- },
-};
+int create_flatten_tree(struct kexec_info *, unsigned char*, unsigned long *);
+int parse_options(char *);
+int setup_memory_ranges(void);
int elf_ppc64_probe(const char *buf, off_t len)
{
@@ -94,12 +65,62 @@ int elf_ppc64_probe(const char *buf, off
return result;
}
-int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
+int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
struct mem_ehdr ehdr;
+ const char *command_line;
+ const char *input_options;
+ int command_line_len;
+ const char *ramdisk;
+ unsigned long *lp;
+ 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
+ { "append", 1, NULL, OPT_APPEND },
+ { "ramdisk", 1, NULL, OPT_RAMDISK },
+ { 0, 0, NULL, 0 },
+ };
+
+ static const char short_options[] = KEXEC_OPT_STR "";
/* Parse command line arguments */
+ initrd_base = 0;
+ initrd_size = 0;
+ command_line = 0;
+ input_options = 0;
+ ramdisk = 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:
+ input_options = optarg;
+ break;
+ case OPT_RAMDISK:
+ ramdisk = optarg;
+ break;
+ }
+ }
+
+ command_line_len = 0;
+ if (command_line) {
+ command_line_len = strlen(command_line) + 1;
+ }
+
+ if (input_options)
+ parse_options(input_options);
/* Parse the Elf file */
result = build_elf_exec_info(buf, len, &ehdr);
@@ -109,15 +130,162 @@ int elf_ppc64_load(int argc, char **argv
}
/* Load the Elf data */
+ setup_memory_ranges();
+ /* 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
+ */
+ unsigned long long base_addr;
+ struct mem_phdr *phdr;
+ size_t size;
+
+ phdr = &ehdr.e_phdr[0];
+ size = phdr->p_filesz;
+ if (size > phdr->p_memsz) {
+ size = phdr->p_memsz;
+ }
+
+ base_addr = (unsigned long)locate_hole(info, size, 0, 0,
+ 0xFFFFFFFFFFFFFFFFUL, 1);
+ ehdr.e_phdr[0].p_paddr = base_addr;
result = elf_exec_load(&ehdr, info);
if (result < 0) {
free_elf_info(&ehdr);
return result;
}
- return 1;
+
+ /* Add a ram-disk to the current image */
+ if (ramdisk) {
+ unsigned char *ramdisk_buf = NULL;
+ off_t ramdisk_size = 0;
+ unsigned long long ramdisk_addr;
+
+ ramdisk_buf = slurp_file(ramdisk, &ramdisk_size);
+ add_buffer(info, ramdisk_buf, ramdisk_size, ramdisk_size, 0, 0,
+ 0xFFFFFFFFFFFFFFFFUL, 1);
+ ramdisk_addr = info->segment[info->nr_segments-1].mem;
+ initrd_base = ramdisk_addr;
+ initrd_size = ramdisk_size;
+ }
+
+ /* Add v2wrap to the current image */
+ unsigned char *v2wrap_buf = NULL;
+ off_t v2wrap_size = 0;
+ unsigned int len;
+ unsigned char *buf;
+ unsigned int rsvmap_len;
+ unsigned long long *ptr;
+ struct bootblock *bb_ptr;
+ unsigned int devtree_size;
+
+ v2wrap_buf = (char *) malloc(purgatory_size);
+ if (v2wrap_buf == NULL) {
+ free_elf_info(&ehdr);
+ return -1;
+ }
+ memcpy(v2wrap_buf, purgatory, purgatory_size);
+ v2wrap_size = purgatory_size;
+ create_flatten_tree(info, &v2wrap_buf, &v2wrap_size);
+ add_buffer(info, v2wrap_buf, v2wrap_size, v2wrap_size, 0, 0,
+ 0xFFFFFFFFFFFFFFFFUL, -1);
+
+ /* patch reserve map address for flattened device-tree */
+ base_addr = info->segment[(info->nr_segments)-1].mem;
+ buf = (unsigned char *)info->segment[(info->nr_segments)-1].buf;
+ buf = buf + 0x100; /* offset to end of v2wrap */
+ bb_ptr = (struct bootblock *)buf;
+ rsvmap_len = bb_ptr->off_dt_struct - bb_ptr->off_mem_rsvmap;
+ devtree_size = bb_ptr->totalsize;
+ len = sizeof(struct bootblock);
+ len += 7; len &= ~7;
+ buf = buf + len;
+ len = rsvmap_len / (2 * sizeof(unsigned long long));
+
+ ptr = (unsigned long long *)buf;
+ ptr = ptr + 2*(len-2);
+ *ptr = base_addr + 0x100;
+ ptr++;
+ *ptr = (unsigned long long)devtree_size;
+
+ unsigned int nr_segments;
+ nr_segments = info->nr_segments;
+ lp = info->segment[nr_segments-1].buf + 0x100;
+ lp--;
+ *lp = info->segment[0].mem;
+ info->entry = info->segment[nr_segments-1].mem;
+
+ unsigned int i;
+ for (i = 0; i < nr_segments; i++)
+ printf("segment[i].mem:%lx\n", info->segment[i].mem);
+
+ return 0;
}
void elf_ppc64_usage(void)
{
fprintf(stderr, "elf support is still broken\n");
}
+
+struct param_struct {
+ const char *name;
+ void *val;
+};
+struct param_struct params;
+
+static char *next_arg(char *args, char **param, char **val)
+{
+ unsigned int i, equals = 0;
+ char *next;
+
+ /* Chew any extra spaces */
+ while (*args == ' ') args++;
+ for (i = 0; args[i]; i++) {
+ if (args[i] == ' ')
+ break;
+ if (equals == 0) {
+ if (args[i] == '=')
+ equals = i;
+ }
+ }
+ *param = args;
+ if (!equals)
+ *val = NULL;
+ else {
+ args[equals] = '\0';
+ *val = args + equals + 1;
+ }
+
+ if (args[i]) {
+ args[i] = '\0';
+ next = args + i + 1;
+ } else
+ next = args + i;
+ return next;
+}
+
+static int add_arg(char *param, char*val)
+{
+ int ret = 0;
+ if (strcmp(param, "initrd-base")==0)
+ initrd_base=strtoul(val, NULL, 0);
+ else if (strcmp(param, "initrd-size")==0)
+ initrd_size=strtoul(val, NULL, 0);
+ else {
+ printf("invalid option\n");
+ ret = 1;
+ }
+ return ret;
+}
+
+int parse_options(char *options)
+{
+ char *param, *val;
+ /* initrd-addr , initrd-size */
+ while (*options) {
+ int ret;
+ options = next_arg(options, ¶m, &val);
+ ret = add_arg(param, val);
+ }
+ /* All parsed OK */
+ return 0;
+}
diff -puN kexec/arch/ppc64/kexec-elf-rel-ppc64.c~basic_kexec_tools_for_ppc64 kexec/arch/ppc64/kexec-elf-rel-ppc64.c
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-elf-rel-ppc64.c~basic_kexec_tools_for_ppc64 2005-09-14 13:10:39.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-elf-rel-ppc64.c 2005-09-14 13:11:05.000000000 +0530
@@ -22,7 +22,7 @@ static struct mem_shdr *toc_section(cons
struct mem_shdr *shdr, *shdr_end;
unsigned char *strtab;
strtab = ehdr->e_shdr[ehdr->e_shstrndx].sh_data;
- shdr_end = &ehdr->e_shdr[ehdr->shnum];
+ shdr_end = &ehdr->e_shdr[ehdr->e_shnum];
for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
if (strcmp(shdr->sh_name, ".toc") == 0) {
return shdr;
diff -puN kexec/arch/ppc64/kexec-ppc64.h~basic_kexec_tools_for_ppc64 kexec/arch/ppc64/kexec-ppc64.h
--- kexec-tools-1.101/kexec/arch/ppc64/kexec-ppc64.h~basic_kexec_tools_for_ppc64 2005-09-14 13:10:39.000000000 +0530
+++ kexec-tools-1.101-sharada/kexec/arch/ppc64/kexec-ppc64.h 2005-09-14 13:11:05.000000000 +0530
@@ -6,6 +6,8 @@ int elf_ppc64_load(int argc, char **argv
struct kexec_info *info);
void elf_ppc64_usage(void);
+unsigned long initrd_base;
+unsigned long initrd_size;
/* boot block version 2 as defined by the linux kernel */
struct bootblock {
unsigned magic,
_
More information about the Linuxppc64-dev
mailing list