summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Horman <horms@verge.net.au>2007-02-01 17:09:16 +0900
committerSimon Horman <horms@verge.net.au>2007-02-01 17:16:53 +0900
commit35917b5e76e8aef49920cc9693c94863f4ae507b (patch)
tree79aac9b8ea813e3809e44b940d10b4f4d6ef257b
parent17aef86b03edc9867f990434bc30be0ac498376d (diff)
kexec-tools: Add sh support
Patch found on http://eggplant.ddo.jp/www/download/debian26/source/kexec-tools/kexec-tools_1.101-2sh.diff.gz According to Paul Mundt <lethal@linux-sh.org> it was originally by kogiidena <kogiidena@eggplant.ddo.jp> Signed-off-by: Simon Horman <horms@verge.net.au> Acked-by: Magnus Damm <magnus.damm@gmail.com>
-rw-r--r--kexec/arch/sh/Makefile8
-rw-r--r--kexec/arch/sh/include/arch/options.h22
-rw-r--r--kexec/arch/sh/kexec-elf-rel-sh.c18
-rw-r--r--kexec/arch/sh/kexec-netbsd-sh.c153
-rw-r--r--kexec/arch/sh/kexec-sh.c166
-rw-r--r--kexec/arch/sh/kexec-sh.h17
-rw-r--r--kexec/arch/sh/kexec-zImage-sh.c107
-rw-r--r--kexec/arch/sh/netbsd_booter.S47
-rw-r--r--kexec/kexec-syscall.h3
-rw-r--r--purgatory/arch/sh/Makefile7
-rw-r--r--purgatory/arch/sh/include/limits.h58
-rw-r--r--purgatory/arch/sh/include/stdint.h16
12 files changed, 622 insertions, 0 deletions
diff --git a/kexec/arch/sh/Makefile b/kexec/arch/sh/Makefile
new file mode 100644
index 0000000..8cf52e3
--- /dev/null
+++ b/kexec/arch/sh/Makefile
@@ -0,0 +1,8 @@
+#
+# kexec sh (linux booting linux)
+#
+KEXEC_C_SRCS+= kexec/arch/sh/kexec-sh.c
+KEXEC_C_SRCS+= kexec/arch/sh/kexec-zImage-sh.c
+KEXEC_C_SRCS+= kexec/arch/sh/kexec-netbsd-sh.c
+KEXEC_C_SRCS+= kexec/arch/sh/kexec-elf-rel-sh.c
+KEXEC_S_SRCS+= kexec/arch/sh/netbsd_booter.S
diff --git a/kexec/arch/sh/include/arch/options.h b/kexec/arch/sh/include/arch/options.h
new file mode 100644
index 0000000..e02960d
--- /dev/null
+++ b/kexec/arch/sh/include/arch/options.h
@@ -0,0 +1,22 @@
+#ifndef KEXEC_ARCH_SH_OPTIONS_H
+#define KEXEC_ARCH_SH_OPTIONS_H
+
+#define OPT_ARCH_MAX (OPT_MAX+0)
+#define OPT_APPEND (OPT_ARCH_MAX+1)
+#define OPT_EMPTYZERO (OPT_ARCH_MAX+2)
+#define OPT_NBSD_HOWTO (OPT_ARCH_MAX+3)
+#define OPT_NBSD_MROOT (OPT_ARCH_MAX+4)
+
+
+#define KEXEC_ARCH_OPTIONS \
+ KEXEC_OPTIONS \
+ {"command-line", 1, 0, OPT_APPEND}, \
+ {"append", 1, 0, OPT_APPEND}, \
+ {"empty-zero", 1, 0, OPT_APPEND}, \
+ {"howto", 1, 0, OPT_NBSD_HOWTO}, \
+ {"miniroot", 1, 0, OPT_NBSD_MROOT}, \
+
+
+#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
+
+#endif /* KEXEC_ARCH_SH_OPTIONS_H */
diff --git a/kexec/arch/sh/kexec-elf-rel-sh.c b/kexec/arch/sh/kexec-elf-rel-sh.c
new file mode 100644
index 0000000..3e16b28
--- /dev/null
+++ b/kexec/arch/sh/kexec-elf-rel-sh.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <elf.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+
+int machine_verify_elf_rel(struct mem_ehdr *ehdr)
+{
+
+ die("machine_verify_elf_rel is not implemented\n");
+ return 0;
+}
+
+void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
+ void *location, unsigned long address, unsigned long value)
+{
+ die("Unknown rela relocation: %lu\n", r_type);
+ return;
+}
diff --git a/kexec/arch/sh/kexec-netbsd-sh.c b/kexec/arch/sh/kexec-netbsd-sh.c
new file mode 100644
index 0000000..935338e
--- /dev/null
+++ b/kexec/arch/sh/kexec-netbsd-sh.c
@@ -0,0 +1,153 @@
+/*
+ * kexec-netbsd-sh.c - kexec netbsd loader for the SH
+ * Copyright (C) 2005 kogiidena@eggplant.ddo.jp
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <elf.h>
+#include <boot/elf_boot.h>
+#include <ip_checksum.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include <arch/options.h>
+#include <asm/page.h>
+
+static const int probe_debug = 0;
+const extern unsigned char netbsd_booter[];
+
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+/*
+ * netbsd_sh_probe - sanity check the elf image
+ *
+ * Make sure that the file image has a reasonable chance of working.
+ */
+int netbsd_sh_probe(const char *buf, off_t len)
+{
+ Elf32_Ehdr *ehdr;
+
+ ehdr = (Elf32_Ehdr *)buf;
+ if(memcmp(buf, ELFMAG, SELFMAG) != 0){
+ return -1;
+ }
+ if (ehdr->e_machine != EM_SH) {
+ return -1;
+ }
+ return 0;
+}
+
+void netbsd_sh_usage(void)
+{
+ printf(
+ " --howto=VALUE NetBSD kernel boot option.\n"
+ " --miniroot=FILE NetBSD miniroot ramdisk.\n\n");
+}
+
+int netbsd_sh_load(int argc, char **argv, const char *buf, off_t len,
+ struct kexec_info *info)
+{
+ const char *howto, *miniroot;
+ unsigned long entry, start, size;
+ char *miniroot_buf;
+ off_t miniroot_length;
+ unsigned int howto_value;
+ unsigned char *param;
+ unsigned long *paraml;
+ unsigned char *img;
+
+ int opt;
+
+ static const struct option options[] = {
+ KEXEC_ARCH_OPTIONS
+ {0, 0, 0, 0},
+ };
+
+ static const char short_options[] = KEXEC_ARCH_OPT_STR "";
+
+ howto = miniroot = 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_NBSD_HOWTO:
+ howto = optarg;
+ break;
+ case OPT_NBSD_MROOT:
+ miniroot = optarg;
+ break;
+ }
+ }
+
+ /* howto */
+ howto_value = 0;
+ if(howto){
+ howto_value = strtol(howto, NULL, 0);
+ }
+
+ /* Parse the Elf file */
+ {
+ Elf32_Ehdr *ehdr;
+ Elf32_Phdr *phdr;
+ unsigned long bbs;
+ ehdr = (Elf32_Ehdr *)buf;
+ phdr = (Elf32_Phdr *)&buf[ehdr->e_phoff];
+
+ entry = ehdr->e_entry;
+ img = (unsigned char *)&buf[phdr->p_offset];
+ start = (phdr->p_paddr) & 0x1fffffff;
+ bbs = phdr->p_filesz;
+ size = phdr->p_memsz;
+
+ if(size < bbs){
+ size = bbs;
+ }
+ size = PAGE_ALIGN(size);
+ memset(&img[bbs], 0, size-bbs);
+ add_segment(info, img, size, start, size);
+ start += size;
+ }
+
+ /* miniroot file */
+ miniroot_buf = 0;
+ if (miniroot) {
+ miniroot_buf = slurp_file(miniroot, &miniroot_length);
+ howto_value |= 0x200;
+ size = PAGE_ALIGN(miniroot_length);
+ add_segment(info, miniroot_buf, size, start, size);
+ start += size;
+ }
+
+ /* howto & bootinfo */
+ param = xmalloc(4096);
+ memset(param, 0, 4096);
+ paraml = (unsigned long *) &param[256];
+ memcpy(param, netbsd_booter, 256);
+ paraml[0] = entry;
+ paraml[1] = howto_value;
+ add_segment(info, param, 4096, start, 4096);
+
+ /* For now we don't have arguments to pass :( */
+ info->entry = (void *) (start | 0xa0000000);
+ return 0;
+}
diff --git a/kexec/arch/sh/kexec-sh.c b/kexec/arch/sh/kexec-sh.c
new file mode 100644
index 0000000..6b485d1
--- /dev/null
+++ b/kexec/arch/sh/kexec-sh.c
@@ -0,0 +1,166 @@
+/*
+ * kexec-sh.c - kexec for the SH
+ * Copyright (C) 2004 kogiidena@eggplant.ddo.jp
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/utsname.h>
+#include "../../kexec.h"
+#include "../../kexec-syscall.h"
+#include "kexec-sh.h"
+#include <arch/options.h>
+
+#define MAX_MEMORY_RANGES 64
+#define MAX_LINE 160
+static struct memory_range memory_range[MAX_MEMORY_RANGES];
+
+/* Return a sorted list of available memory ranges. */
+int get_memory_ranges(struct memory_range **range, int *ranges)
+{
+ int memory_ranges;
+
+ memory_ranges = 0;
+ memory_range[memory_ranges].start = 0x08000000;
+ memory_range[memory_ranges].end = 0x10000000;
+ memory_range[memory_ranges].type = RANGE_RAM;
+ memory_ranges++;
+ *range = memory_range;
+ *ranges = memory_ranges;
+ return 0;
+}
+
+/* Supported file types and callbacks */
+struct file_type file_type[] = {
+ {"zImage-sh", zImage_sh_probe, zImage_sh_load, zImage_sh_usage},
+ {"netbsd-sh", netbsd_sh_probe, netbsd_sh_load, netbsd_sh_usage},
+};
+int file_types = sizeof(file_type) / sizeof(file_type[0]);
+
+
+void arch_usage(void)
+{
+
+ printf(
+ " none\n\n"
+ "Default options:\n"
+ " --append=\"%s\"\n"
+ " --empty-zero=0x%08x\n\n"
+ " STRING of --appned is set form /proc/cmdline as default.\n"
+ " ADDRESS of --empty-zero can be set SHELL environment variable\n"
+ " KEXEC_EMPTY_ZERO as default.\n\n"
+ " ADDRESS can be get in the following method in your system. \n"
+ " 1) \"grep empty_zero /proc/kallsyms\". \n"
+ " 2) \"grep empty_zero System.map\". \n"
+ " 3) CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET in your kernel\n"
+ " config file.\n"
+ ,get_append(), (unsigned int) get_empty_zero(NULL));
+
+}
+
+static struct {
+} arch_options = {
+};
+int arch_process_options(int argc, char **argv)
+{
+ static const struct option options[] = {
+ KEXEC_ARCH_OPTIONS
+ { 0, 0, NULL, 0 },
+ };
+ static const char short_options[] = KEXEC_ARCH_OPT_STR;
+ int opt;
+
+ opterr = 0; /* Don't complain about unrecognized options here */
+ while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
+ switch(opt) {
+ default:
+ /* Ignore core options */
+ if (opt < OPT_MAX) {
+ break;
+ }
+ case '?':
+ usage();
+ return -1;
+ case OPT_APPEND:
+ case OPT_NBSD_HOWTO:
+ case OPT_NBSD_MROOT:
+ ;
+ }
+ }
+ /* Reset getopt for the next pass; called in other source modules */
+ opterr = 1;
+ optind = 1;
+ return 0;
+}
+
+int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
+{
+ int result;
+ struct utsname utsname;
+ result = uname(&utsname);
+ if (result < 0) {
+ fprintf(stderr, "uname failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ if ( (strcmp(utsname.machine, "sh3") == 0) ||
+ (strcmp(utsname.machine, "sh4") == 0))
+
+ {
+ /* For compatibility with older patches
+ * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_IA64 here.
+ */
+ *flags |= KEXEC_ARCH_DEFAULT;
+ }
+ else {
+ fprintf(stderr, "Unsupported machine type: %s\n",
+ utsname.machine);
+ return -1;
+ }
+ return 0;
+}
+
+void arch_update_purgatory(struct kexec_info *info)
+{
+}
+
+
+unsigned long get_empty_zero(char *s)
+{
+ char *env;
+
+ env = getenv("KEXEC_EMPTY_ZERO");
+
+ if(s){
+ env = s;
+ }else if(!env){
+ env = "0x0c001000";
+ }
+ return 0x1fffffff & strtoul(env,(char **)NULL,0);
+}
+
+char append_buf[256];
+
+char *get_append(void)
+{
+ FILE *fp;
+ int len;
+ if((fp = fopen("/proc/cmdline", "r")) == NULL){
+ printf("/proc/cmdline file open error !!\n");
+ exit(1);
+ }
+ fgets(append_buf, 256, fp);
+ len = strlen(append_buf);
+ append_buf[len-1] = 0;
+ fclose(fp);
+ return append_buf;
+}
diff --git a/kexec/arch/sh/kexec-sh.h b/kexec/arch/sh/kexec-sh.h
new file mode 100644
index 0000000..ee73d8c
--- /dev/null
+++ b/kexec/arch/sh/kexec-sh.h
@@ -0,0 +1,17 @@
+#ifndef KEXEC_SH_H
+#define KEXEC_SH_H
+
+int zImage_sh_probe(const char *buf, off_t len);
+int zImage_sh_load(int argc, char **argv, const char *buf, off_t len,
+ struct kexec_info *info);
+void zImage_sh_usage(void);
+
+int netbsd_sh_probe(const char *buf, off_t len);
+int netbsd_sh_load(int argc, char **argv, const char *buf, off_t len,
+ struct kexec_info *info);
+void netbsd_sh_usage(void);
+
+char *get_append(void);
+unsigned long get_empty_zero(char *s);
+
+#endif /* KEXEC_SH_H */
diff --git a/kexec/arch/sh/kexec-zImage-sh.c b/kexec/arch/sh/kexec-zImage-sh.c
new file mode 100644
index 0000000..9527fb6
--- /dev/null
+++ b/kexec/arch/sh/kexec-zImage-sh.c
@@ -0,0 +1,107 @@
+/*
+ * kexec-zImage-sh.c - kexec zImage loader for the SH
+ * Copyright (C) 2005 kogiidena@eggplant.ddo.jp
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <elf.h>
+#include <boot/elf_boot.h>
+#include <ip_checksum.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include <arch/options.h>
+#include "kexec-sh.h"
+
+static const int probe_debug = 0;
+
+/*
+ * zImage_sh_probe - sanity check the elf image
+ *
+ * Make sure that the file image has a reasonable chance of working.
+ */
+int zImage_sh_probe(const char *buf, off_t len)
+{
+ if (memcmp(&buf[0x202], "HdrS", 4) != 0) {
+ fprintf(stderr, "Not a zImage\n");
+ return -1;
+ }
+ return 0;
+}
+
+void zImage_sh_usage(void)
+{
+ printf(
+
+ " --append=STRING Set the kernel command line to STRING.\n"
+ " --empty-zero=ADDRESS Set the kernel top ADDRESS. \n\n");
+
+}
+
+int zImage_sh_load(int argc, char **argv, const char *buf, off_t len,
+ struct kexec_info *info)
+{
+ char *command_line;
+ int opt;
+ unsigned long empty_zero, area;
+ unsigned char *param;
+ unsigned long *paraml;
+
+ static const struct option options[] = {
+ KEXEC_ARCH_OPTIONS
+ {0, 0, 0, 0},
+ };
+
+ static const char short_options[] = KEXEC_ARCH_OPT_STR "";
+
+ command_line = 0;
+ empty_zero = get_empty_zero(NULL);
+ 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:
+ command_line = optarg;
+ break;
+ case OPT_EMPTYZERO:
+ empty_zero = get_empty_zero(optarg);
+ break;
+ }
+ }
+ param = xmalloc(4096);
+ memset(param, 0, 4096);
+ area = empty_zero & 0x1c000000;
+ if (!command_line) {
+ command_line = get_append();
+ }
+ strncpy(&param[256], command_line, strlen(command_line));
+ paraml = (unsigned long *)param;
+ // paraml[0] = 1; // readonly flag is set as default
+
+ add_segment(info, param, 4096, empty_zero, 4096);
+ add_segment(info, buf, len, (area | 0x00210000), len);
+
+ /* For now we don't have arguments to pass :( */
+ info->entry = (void *)(0x80210000 | area);
+ return 0;
+}
diff --git a/kexec/arch/sh/netbsd_booter.S b/kexec/arch/sh/netbsd_booter.S
new file mode 100644
index 0000000..e660b3d
--- /dev/null
+++ b/kexec/arch/sh/netbsd_booter.S
@@ -0,0 +1,47 @@
+ .globl netbsd_booter
+netbsd_booter:
+ mov.l ccr,r0
+ mov #0,r1
+ mov.l r1,@r0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ mova netbsd_start,r0
+ mov.l @r0,r1
+ add #4,r0
+ mov.l @r0,r4 ! howto
+ add #4,r0
+ mov r0,r5 ! bootinfo
+ jmp @r1
+ nop
+ nop
+ nop
+ .align 4
+ccr: .long 0xff00001c
+
+ .align 8
+netbsd_start:
+ .long 0x8c001000
+ .long 0x200 ! howto
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+ .long 0 ! bootinfo
+
diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h
index 37e2bb1..0ca3984 100644
--- a/kexec/kexec-syscall.h
+++ b/kexec/kexec-syscall.h
@@ -25,6 +25,9 @@
#ifdef __i386__
#define __NR_kexec_load 283
#endif
+#ifdef __sh__
+#define __NR_kexec_load 283
+#endif
#ifdef __ia64__
#define __NR_kexec_load 1268
#endif
diff --git a/purgatory/arch/sh/Makefile b/purgatory/arch/sh/Makefile
new file mode 100644
index 0000000..a626bbd
--- /dev/null
+++ b/purgatory/arch/sh/Makefile
@@ -0,0 +1,7 @@
+#
+# Purgatory alpha
+#
+
+PURGATORY_C_SRCS+=
+PURGATORY_S_SRCS+=
+
diff --git a/purgatory/arch/sh/include/limits.h b/purgatory/arch/sh/include/limits.h
new file mode 100644
index 0000000..d5a5a02
--- /dev/null
+++ b/purgatory/arch/sh/include/limits.h
@@ -0,0 +1,58 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 2147483647L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 4294967295UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/purgatory/arch/sh/include/stdint.h b/purgatory/arch/sh/include/stdint.h
new file mode 100644
index 0000000..79262c2
--- /dev/null
+++ b/purgatory/arch/sh/include/stdint.h
@@ -0,0 +1,16 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+typedef unsigned long size_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+
+#endif /* STDINT_H */