diff options
author | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-01-07 16:29:16 +0000 |
---|---|---|
committer | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-01-07 16:29:16 +0000 |
commit | c2243d1fb9e44f9f4dbf83f8e85b4d52b30aea82 (patch) | |
tree | fea5a7ecead9e3e4bb44cb019e8caad46453fd00 /target/linux/generic/patches-3.0/335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch | |
parent | 66663e28094813f57d1d1124bd7397d2189f5ee5 (diff) |
generic: improve MIPS kexec support
It is based on patches from the linux-longsoon-community git tree:
http://dev.lemote.com/cgit/linux-loongson-community.git/
Now the kernel can use the command line parameter from kexec-tools.
Runtime tested on ar71xx with 2.6.39.4 (the wathdog must be stopped
before executing the new kernel). Compile tested with lantiq (3.1.4)
and brcm47xx (3.0.12).
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@29674 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic/patches-3.0/335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch')
-rw-r--r-- | target/linux/generic/patches-3.0/335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.0/335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch b/target/linux/generic/patches-3.0/335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch new file mode 100644 index 000000000..abc89712b --- /dev/null +++ b/target/linux/generic/patches-3.0/335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch @@ -0,0 +1,186 @@ +--- a/arch/mips/kernel/machine_kexec.c ++++ b/arch/mips/kernel/machine_kexec.c +@@ -23,67 +23,104 @@ void (*relocated_kexec_smp_wait) (void * + atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); + #endif + +-static void machine_kexec_init_args(void) ++#define KEXEC_MIPS_ARGV_BUF_SIZE COMMAND_LINE_SIZE ++#define KEXEC_MIPS_ARGV_MAX_ARGS (COMMAND_LINE_SIZE / 15) ++ ++char kexec_argv_buf[KEXEC_MIPS_ARGV_BUF_SIZE] __kexec; ++int kexec_argv[KEXEC_MIPS_ARGV_MAX_ARGS] __kexec; ++ ++static void ++machine_kexec_print_args(void) + { +- kexec_args[0] = fw_arg0; +- kexec_args[1] = fw_arg1; +- kexec_args[2] = fw_arg2; +- kexec_args[3] = fw_arg3; ++ int i; + + pr_info("kexec_args[0] (argc): %lu\n", kexec_args[0]); + pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]); + pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]); + pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]); +-} + +-#define ARGV_MAX_ARGS (COMMAND_LINE_SIZE / 15) ++ for (i = 0; i < kexec_args[0]; i++) ++ pr_info("kexec_argv[%d] = %p, %s\n", i, ++ (char *)kexec_argv[i], (char *)kexec_argv[i]); ++} + +-int machine_kexec_pass_args(struct kimage *image) ++static void ++machine_kexec_init_argv(struct kimage *image) + { +- int i, argc = 0; +- char *bootloader = "kexec"; +- int *kexec_argv = (int *)kexec_args[1]; ++ void __user *buf; ++ size_t bufsz; ++ size_t size; ++ int i; + ++ bufsz = 0; + for (i = 0; i < image->nr_segments; i++) { +- if (!strncmp(bootloader, (char *)image->segment[i].buf, +- strlen(bootloader))) { +- /* +- * convert command line string to array +- * of parameters (as bootloader does). +- */ +- /* +- * Note: we do treat the 1st string "kexec" as an +- * argument ;-) so, argc here is 1. +- */ +- char *str = (char *)image->segment[i].buf; +- char *ptr = strchr(str, ' '); +- char *kbuf = (char *)kexec_argv[0]; +- /* Whenever --command-line or --append used, "kexec" is copied */ +- argc = 1; +- /* Parse the offset */ +- while (ptr && (ARGV_MAX_ARGS > argc)) { +- *ptr = '\0'; +- if (ptr[1] != ' ' && ptr[1] != '\0') { +- int offt = (int)(ptr - str + 1); +- kexec_argv[argc] = (int)kbuf + offt; +- argc++; +- } +- ptr = strchr(ptr + 1, ' '); +- } +- if (argc > 1) { +- /* Copy to kernel space */ +- copy_from_user(kbuf, (char *)image->segment[i].buf, image->segment[i].bufsz); +- fw_arg0 = kexec_args[0] = argc; +- } +- break; ++ struct kexec_segment *seg; ++ ++ seg = &image->segment[i]; ++ if (seg->bufsz < 6) ++ continue; ++ ++ if (strncmp((char *) seg->buf, "kexec", 5)) ++ continue; ++ ++ /* don't copy "kexec" */ ++ buf = seg->buf + 5; ++ bufsz = seg->bufsz - 5; ++ break; ++ } ++ ++ if (i >= image->nr_segments) ++ return; ++ ++ size = KEXEC_MIPS_ARGV_BUF_SIZE - 1; ++ size = min(size, bufsz); ++ if (size < bufsz) ++ pr_warn("kexec command line truncated to %d bytes\n", size); ++ ++ /* Copy to kernel space */ ++ copy_from_user(kexec_argv_buf, buf, size); ++} ++ ++static void ++machine_kexec_parse_argv(struct kimage *image) ++{ ++ char *reboot_code_buffer; ++ int reloc_delta; ++ char *ptr; ++ int argc; ++ int i; ++ ++ ptr = kexec_argv_buf; ++ argc = 0; ++ ++ /* ++ * convert command line string to array of parameters ++ * (as bootloader does). ++ */ ++ while (ptr && *ptr && (KEXEC_MIPS_ARGV_MAX_ARGS > argc)) { ++ if (*ptr == ' ') { ++ *ptr++ = '\0'; ++ continue; + } ++ ++ kexec_argv[argc++] = (int) ptr; ++ ptr = strchr(ptr, ' '); + } + +- pr_info("argc = %lu\n", kexec_args[0]); +- for (i = 0; i < kexec_args[0]; i++) +- pr_info("argv[%d] = %p, %s\n", i, (char *)kexec_argv[i], (char *)kexec_argv[i]); ++ if (!argc) ++ return; + +- return 0; ++ kexec_args[0] = argc; ++ kexec_args[1] = (int) kexec_argv; ++ kexec_args[2] = 0; ++ kexec_args[3] = 0; ++ ++ reboot_code_buffer = page_address(image->control_code_page); ++ reloc_delta = reboot_code_buffer - (char *) &__start___kexec_relocate; ++ ++ kexec_args[1] += reloc_delta; ++ for (i = 0; i < argc; i++) ++ kexec_argv[i] += reloc_delta; + } + + int +@@ -95,8 +132,14 @@ machine_kexec_prepare(struct kimage *kim + * + * This can be overrided by _machine_kexec_prepare(). + */ +- machine_kexec_init_args(); +- machine_kexec_pass_args(kimage); ++ ++ kexec_args[0] = fw_arg0; ++ kexec_args[1] = fw_arg1; ++ kexec_args[2] = fw_arg2; ++ kexec_args[3] = fw_arg3; ++ ++ machine_kexec_init_argv(kimage); ++ machine_kexec_parse_argv(kimage); + + if (_machine_kexec_prepare) + return _machine_kexec_prepare(kimage); +@@ -152,11 +195,13 @@ machine_kexec(struct kimage *image) + pr_info("kexec_indirection_page = %p\n", + (void *)kexec_indirection_page); + ++ pr_info("Copy kexec_relocate section from %p to reboot_code_buffer: %p\n", ++ &__start___kexec_relocate, (void *)reboot_code_buffer); ++ + memcpy((void *)reboot_code_buffer, &__start___kexec_relocate, + kexec_relocate_size); + +- pr_info("Copy kexec_relocate section from %p to reboot_code_buffer: %p\n", +- &__start___kexec_relocate, (void *)reboot_code_buffer); ++ machine_kexec_print_args(); + + /* + * The generic kexec code builds a page list with physical |