kernel: add preliminary support for linux 3.3
[openwrt.git] / target / linux / generic / patches-3.3 / 335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch
diff --git a/target/linux/generic/patches-3.3/335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch b/target/linux/generic/patches-3.3/335-mips-kexec-cleanup-kexec-tools-parameter-handling.patch
new file mode 100644 (file)
index 0000000..abc8971
--- /dev/null
@@ -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
This page took 0.024975 seconds and 4 git commands to generate.