330-MIPS-kexec-Accept-command-line-parameters-from-users.patch 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. From: Yousong Zhou <yszhou4tech@gmail.com>
  2. Subject: MIPS: kexec: Accept command line parameters from userspace.
  3. Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
  4. ---
  5. arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++-----
  6. arch/mips/kernel/machine_kexec.h | 20 +++++
  7. arch/mips/kernel/relocate_kernel.S | 21 +++--
  8. 3 files changed, 167 insertions(+), 27 deletions(-)
  9. create mode 100644 arch/mips/kernel/machine_kexec.h
  10. --- a/arch/mips/kernel/machine_kexec.c
  11. +++ b/arch/mips/kernel/machine_kexec.c
  12. @@ -10,14 +10,11 @@
  13. #include <linux/mm.h>
  14. #include <linux/delay.h>
  15. +#include <asm/bootinfo.h>
  16. #include <asm/cacheflush.h>
  17. #include <asm/page.h>
  18. -
  19. -extern const unsigned char relocate_new_kernel[];
  20. -extern const size_t relocate_new_kernel_size;
  21. -
  22. -extern unsigned long kexec_start_address;
  23. -extern unsigned long kexec_indirection_page;
  24. +#include <linux/uaccess.h>
  25. +#include "machine_kexec.h"
  26. int (*_machine_kexec_prepare)(struct kimage *) = NULL;
  27. void (*_machine_kexec_shutdown)(void) = NULL;
  28. @@ -28,6 +25,99 @@ atomic_t kexec_ready_to_reboot = ATOMIC_
  29. void (*_crash_smp_send_stop)(void) = NULL;
  30. #endif
  31. +static void machine_kexec_print_args(void)
  32. +{
  33. + unsigned long argc = (int)kexec_args[0];
  34. + int i;
  35. +
  36. + pr_info("kexec_args[0] (argc): %lu\n", argc);
  37. + pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
  38. + pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
  39. + pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
  40. +
  41. + for (i = 0; i < argc; i++) {
  42. + pr_info("kexec_argv[%d] = %p, %s\n",
  43. + i, kexec_argv[i], kexec_argv[i]);
  44. + }
  45. +}
  46. +
  47. +static void machine_kexec_init_argv(struct kimage *image)
  48. +{
  49. + void __user *buf = NULL;
  50. + size_t bufsz;
  51. + size_t size;
  52. + int i;
  53. +
  54. + bufsz = 0;
  55. + for (i = 0; i < image->nr_segments; i++) {
  56. + struct kexec_segment *seg;
  57. +
  58. + seg = &image->segment[i];
  59. + if (seg->bufsz < 6)
  60. + continue;
  61. +
  62. + if (strncmp((char *) seg->buf, "kexec ", 6))
  63. + continue;
  64. +
  65. + buf = seg->buf;
  66. + bufsz = seg->bufsz;
  67. + break;
  68. + }
  69. +
  70. + if (!buf)
  71. + return;
  72. +
  73. + size = KEXEC_COMMAND_LINE_SIZE;
  74. + size = min(size, bufsz);
  75. + if (size < bufsz)
  76. + pr_warn("kexec command line truncated to %zd bytes\n", size);
  77. +
  78. + /* Copy to kernel space */
  79. + copy_from_user(kexec_argv_buf, buf, size);
  80. + kexec_argv_buf[size - 1] = 0;
  81. +}
  82. +
  83. +static void machine_kexec_parse_argv(struct kimage *image)
  84. +{
  85. + char *reboot_code_buffer;
  86. + int reloc_delta;
  87. + char *ptr;
  88. + int argc;
  89. + int i;
  90. +
  91. + ptr = kexec_argv_buf;
  92. + argc = 0;
  93. +
  94. + /*
  95. + * convert command line string to array of parameters
  96. + * (as bootloader does).
  97. + */
  98. + while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
  99. + if (*ptr == ' ') {
  100. + *ptr++ = '\0';
  101. + continue;
  102. + }
  103. +
  104. + kexec_argv[argc++] = ptr;
  105. + ptr = strchr(ptr, ' ');
  106. + }
  107. +
  108. + if (!argc)
  109. + return;
  110. +
  111. + kexec_args[0] = argc;
  112. + kexec_args[1] = (unsigned long)kexec_argv;
  113. + kexec_args[2] = 0;
  114. + kexec_args[3] = 0;
  115. +
  116. + reboot_code_buffer = page_address(image->control_code_page);
  117. + reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
  118. +
  119. + kexec_args[1] += reloc_delta;
  120. + for (i = 0; i < argc; i++)
  121. + kexec_argv[i] += reloc_delta;
  122. +}
  123. +
  124. static void kexec_image_info(const struct kimage *kimage)
  125. {
  126. unsigned long i;
  127. @@ -52,6 +142,18 @@ int
  128. machine_kexec_prepare(struct kimage *kimage)
  129. {
  130. kexec_image_info(kimage);
  131. + /*
  132. + * Whenever arguments passed from kexec-tools, Init the arguments as
  133. + * the original ones to try avoiding booting failure.
  134. + */
  135. +
  136. + kexec_args[0] = fw_arg0;
  137. + kexec_args[1] = fw_arg1;
  138. + kexec_args[2] = fw_arg2;
  139. + kexec_args[3] = fw_arg3;
  140. +
  141. + machine_kexec_init_argv(kimage);
  142. + machine_kexec_parse_argv(kimage);
  143. if (_machine_kexec_prepare)
  144. return _machine_kexec_prepare(kimage);
  145. @@ -89,10 +191,12 @@ machine_kexec(struct kimage *image)
  146. unsigned long *ptr;
  147. reboot_code_buffer =
  148. - (unsigned long)page_address(image->control_code_page);
  149. + (unsigned long)page_address(image->control_code_page);
  150. + pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
  151. kexec_start_address =
  152. (unsigned long) phys_to_virt(image->start);
  153. + pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
  154. if (image->type == KEXEC_TYPE_DEFAULT) {
  155. kexec_indirection_page =
  156. @@ -100,9 +204,19 @@ machine_kexec(struct kimage *image)
  157. } else {
  158. kexec_indirection_page = (unsigned long)&image->head;
  159. }
  160. + pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
  161. - memcpy((void*)reboot_code_buffer, relocate_new_kernel,
  162. - relocate_new_kernel_size);
  163. + pr_info("Where is memcpy: %p\n", memcpy);
  164. + pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
  165. + (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
  166. + pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
  167. + (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
  168. + memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
  169. + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
  170. +
  171. + pr_info("Before _print_args().\n");
  172. + machine_kexec_print_args();
  173. + pr_info("Before eval loop.\n");
  174. /*
  175. * The generic kexec code builds a page list with physical
  176. @@ -121,15 +235,16 @@ machine_kexec(struct kimage *image)
  177. /*
  178. * we do not want to be bothered.
  179. */
  180. + pr_info("Before irq_disable.\n");
  181. local_irq_disable();
  182. - printk("Will call new kernel at %08lx\n", image->start);
  183. - printk("Bye ...\n");
  184. + pr_info("Will call new kernel at %08lx\n", image->start);
  185. + pr_info("Bye ...\n");
  186. __flush_cache_all();
  187. #ifdef CONFIG_SMP
  188. /* All secondary cpus now may jump to kexec_wait cycle */
  189. relocated_kexec_smp_wait = reboot_code_buffer +
  190. - (void *)(kexec_smp_wait - relocate_new_kernel);
  191. + (void *)(kexec_smp_wait - kexec_relocate_new_kernel);
  192. smp_wmb();
  193. atomic_set(&kexec_ready_to_reboot, 1);
  194. #endif
  195. --- /dev/null
  196. +++ b/arch/mips/kernel/machine_kexec.h
  197. @@ -0,0 +1,20 @@
  198. +#ifndef _MACHINE_KEXEC_H
  199. +#define _MACHINE_KEXEC_H
  200. +
  201. +#ifndef __ASSEMBLY__
  202. +extern const unsigned char kexec_relocate_new_kernel[];
  203. +extern unsigned long kexec_relocate_new_kernel_end;
  204. +extern unsigned long kexec_start_address;
  205. +extern unsigned long kexec_indirection_page;
  206. +
  207. +extern char kexec_argv_buf[];
  208. +extern char *kexec_argv[];
  209. +
  210. +#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
  211. +#endif /* !__ASSEMBLY__ */
  212. +
  213. +#define KEXEC_COMMAND_LINE_SIZE 256
  214. +#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16)
  215. +#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long))
  216. +
  217. +#endif
  218. --- a/arch/mips/kernel/relocate_kernel.S
  219. +++ b/arch/mips/kernel/relocate_kernel.S
  220. @@ -12,8 +12,9 @@
  221. #include <asm/mipsregs.h>
  222. #include <asm/stackframe.h>
  223. #include <asm/addrspace.h>
  224. +#include "machine_kexec.h"
  225. -LEAF(relocate_new_kernel)
  226. +LEAF(kexec_relocate_new_kernel)
  227. PTR_L a0, arg0
  228. PTR_L a1, arg1
  229. PTR_L a2, arg2
  230. @@ -98,7 +99,7 @@ done:
  231. #endif
  232. /* jump to kexec_start_address */
  233. j s1
  234. - END(relocate_new_kernel)
  235. + END(kexec_relocate_new_kernel)
  236. #ifdef CONFIG_SMP
  237. /*
  238. @@ -184,9 +185,15 @@ kexec_indirection_page:
  239. PTR 0
  240. .size kexec_indirection_page, PTRSIZE
  241. -relocate_new_kernel_end:
  242. +kexec_argv_buf:
  243. + EXPORT(kexec_argv_buf)
  244. + .skip KEXEC_COMMAND_LINE_SIZE
  245. + .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
  246. +
  247. +kexec_argv:
  248. + EXPORT(kexec_argv)
  249. + .skip KEXEC_ARGV_SIZE
  250. + .size kexec_argv, KEXEC_ARGV_SIZE
  251. -relocate_new_kernel_size:
  252. - EXPORT(relocate_new_kernel_size)
  253. - PTR relocate_new_kernel_end - relocate_new_kernel
  254. - .size relocate_new_kernel_size, PTRSIZE
  255. +kexec_relocate_new_kernel_end:
  256. + EXPORT(kexec_relocate_new_kernel_end)