[PATCH 04/06] sh: Autodetect zImage zero page address
Magnus Damm
magnus.damm at gmail.com
Tue Aug 26 07:12:18 EDT 2008
From: Magnus Damm <damm at igel.co.jp>
Autodetect the zero page base address for zImages on SuperH.
Signed-off-by: Magnus Damm <damm at igel.co.jp>
---
kexec/arch/sh/kexec-sh.c | 40 +++++++------------
kexec/arch/sh/kexec-sh.h | 3 -
kexec/arch/sh/kexec-zImage-sh.c | 79 ++++++++++++++++++++++++++++-----------
3 files changed, 75 insertions(+), 47 deletions(-)
--- 0004/kexec/arch/sh/kexec-sh.c
+++ work/kexec/arch/sh/kexec-sh.c 2008-08-22 12:05:08.000000000 +0900
@@ -65,16 +65,8 @@ void arch_usage(void)
" 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));
+ ,get_append());
}
@@ -130,21 +122,6 @@ void arch_update_purgatory(struct kexec_
{
}
-
-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)
@@ -162,6 +139,21 @@ char *get_append(void)
return append_buf;
}
+void kexec_sh_setup_zero_page(char *zero_page_buf, int zero_page_size,
+ char *cmd_line)
+{
+ int n = zero_page_size - 0x100;
+
+ memset(zero_page_buf, 0, zero_page_size);
+
+ if (cmd_line) {
+ if (n > strlen(cmd_line))
+ n = strlen(cmd_line);
+
+ memcpy(zero_page_buf + 0x100, cmd_line, n);
+ zero_page_buf[0x100 + n] = '\0';
+ }
+}
int is_crashkernel_mem_reserved(void)
{
--- 0001/kexec/arch/sh/kexec-sh.h
+++ work/kexec/arch/sh/kexec-sh.h 2008-08-22 12:05:08.000000000 +0900
@@ -12,6 +12,7 @@ int netbsd_sh_load(int argc, char **argv
void netbsd_sh_usage(void);
char *get_append(void);
-unsigned long get_empty_zero(char *s);
+void kexec_sh_setup_zero_page(char *zero_page_buf, int zero_page_size,
+ char *cmd_line);
#endif /* KEXEC_SH_H */
--- 0004/kexec/arch/sh/kexec-zImage-sh.c
+++ work/kexec/arch/sh/kexec-zImage-sh.c 2008-08-22 14:28:29.000000000 +0900
@@ -28,6 +28,24 @@
static const int probe_debug = 0;
+#define HEAD32_KERNEL_START_ADDR 0
+#define HEAD32_DECOMPRESS_KERNEL_ADDR 1
+#define HEAD32_INIT_STACK_ADDR 2
+#define HEAD32_INIT_SR 3
+#define HEAD32_INIT_SR_VALUE 0x400000F0
+
+unsigned long zImage_head32(const char *buf, off_t len, int offs)
+{
+ unsigned long *values = (void *)buf;
+ int k;
+
+ for (k = (0x200 / 4) - 1; k > 0; k--)
+ if (values[k] != 0x00090009) /* not nop + nop padding*/
+ return values[k - offs];
+
+ return 0;
+}
+
/*
* zImage_sh_probe - sanity check the elf image
*
@@ -35,10 +53,12 @@ static const int probe_debug = 0;
*/
int zImage_sh_probe(const char *buf, off_t len)
{
- if (memcmp(&buf[0x202], "HdrS", 4) != 0) {
- fprintf(stderr, "Not a zImage\n");
+ if (memcmp(&buf[0x202], "HdrS", 4) != 0)
return -1;
- }
+
+ if (zImage_head32(buf, len, HEAD32_INIT_SR) != HEAD32_INIT_SR_VALUE)
+ return -1;
+
return 0;
}
@@ -54,10 +74,9 @@ int zImage_sh_load(int argc, char **argv
struct kexec_info *info)
{
char *command_line;
- int opt;
- unsigned long empty_zero, area;
- unsigned char *param;
- unsigned long *paraml;
+ int opt, k;
+ unsigned long empty_zero, area, zero_page_base, zero_page_size;
+ char *param;
static const struct option options[] = {
KEXEC_ARCH_OPTIONS
@@ -67,7 +86,6 @@ int zImage_sh_load(int argc, char **argv
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:
@@ -81,25 +99,42 @@ int zImage_sh_load(int argc, char **argv
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) {
+
+ if (!command_line)
command_line = get_append();
- }
- strncpy(¶m[256], command_line, strlen(command_line));
- paraml = (unsigned long *)param;
- // paraml[0] = 1; // readonly flag is set as default
- add_segment(info, param, 4096, 0x80000000 | empty_zero, 4096);
- add_segment(info, buf, len, (area | 0x80210000), len);
+ /* assume the zero page is the page before the vmlinux entry point.
+ * we don't know the page size though, but 64k seems to be max.
+ * put several 4k zero page copies before the entry point to cover
+ * all combinations.
+ */
+
+ empty_zero = zImage_head32(buf, len, HEAD32_KERNEL_START_ADDR);
+
+ zero_page_size = 0x10000;
+ zero_page_base = virt_to_phys(empty_zero - zero_page_size);
+
+ while (!valid_memory_range(info, zero_page_base,
+ zero_page_base + zero_page_size - 1)) {
+ zero_page_base += 0x1000;
+ zero_page_size -= 0x1000;
+ if (zero_page_size == 0)
+ die("Unable to determine zero page size from %p \n",
+ (void *)empty_zero);
+ }
+
+ param = xmalloc(zero_page_size);
+ for (k = 0; k < (zero_page_size / 0x1000); k++)
+ kexec_sh_setup_zero_page(param + (k * 0x1000), 0x1000,
+ command_line);
- /* For now we don't have arguments to pass :( */
+ add_segment(info, param, zero_page_size,
+ 0x80000000 | zero_page_base, zero_page_size);
+
+ area = empty_zero & 0x1c000000;
+ add_segment(info, buf, len, (area | 0x80210000), len);
info->entry = (void *)(0x80210000 | area);
return 0;
}
More information about the kexec
mailing list