123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- From: Yousong Zhou <yszhou4tech@gmail.com>
- Subject: MIPS: kexec: Accept command line parameters from userspace.
- Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
- ---
- arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++-----
- arch/mips/kernel/machine_kexec.h | 20 +++++
- arch/mips/kernel/relocate_kernel.S | 21 +++--
- 3 files changed, 167 insertions(+), 27 deletions(-)
- create mode 100644 arch/mips/kernel/machine_kexec.h
- --- a/arch/mips/kernel/machine_kexec.c
- +++ b/arch/mips/kernel/machine_kexec.c
- @@ -10,14 +10,11 @@
- #include <linux/mm.h>
- #include <linux/delay.h>
-
- +#include <asm/bootinfo.h>
- #include <asm/cacheflush.h>
- #include <asm/page.h>
- -
- -extern const unsigned char relocate_new_kernel[];
- -extern const size_t relocate_new_kernel_size;
- -
- -extern unsigned long kexec_start_address;
- -extern unsigned long kexec_indirection_page;
- +#include <linux/uaccess.h>
- +#include "machine_kexec.h"
-
- int (*_machine_kexec_prepare)(struct kimage *) = NULL;
- void (*_machine_kexec_shutdown)(void) = NULL;
- @@ -28,6 +25,99 @@ atomic_t kexec_ready_to_reboot = ATOMIC_
- void (*_crash_smp_send_stop)(void) = NULL;
- #endif
-
- +static void machine_kexec_print_args(void)
- +{
- + unsigned long argc = (int)kexec_args[0];
- + int i;
- +
- + pr_info("kexec_args[0] (argc): %lu\n", argc);
- + 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]);
- +
- + for (i = 0; i < argc; i++) {
- + pr_info("kexec_argv[%d] = %p, %s\n",
- + i, kexec_argv[i], kexec_argv[i]);
- + }
- +}
- +
- +static void machine_kexec_init_argv(struct kimage *image)
- +{
- + void __user *buf = NULL;
- + size_t bufsz;
- + size_t size;
- + int i;
- +
- + bufsz = 0;
- + for (i = 0; i < image->nr_segments; i++) {
- + struct kexec_segment *seg;
- +
- + seg = &image->segment[i];
- + if (seg->bufsz < 6)
- + continue;
- +
- + if (strncmp((char *) seg->buf, "kexec ", 6))
- + continue;
- +
- + buf = seg->buf;
- + bufsz = seg->bufsz;
- + break;
- + }
- +
- + if (!buf)
- + return;
- +
- + size = KEXEC_COMMAND_LINE_SIZE;
- + size = min(size, bufsz);
- + if (size < bufsz)
- + pr_warn("kexec command line truncated to %zd bytes\n", size);
- +
- + /* Copy to kernel space */
- + copy_from_user(kexec_argv_buf, buf, size);
- + kexec_argv_buf[size - 1] = 0;
- +}
- +
- +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_MAX_ARGC > argc)) {
- + if (*ptr == ' ') {
- + *ptr++ = '\0';
- + continue;
- + }
- +
- + kexec_argv[argc++] = ptr;
- + ptr = strchr(ptr, ' ');
- + }
- +
- + if (!argc)
- + return;
- +
- + kexec_args[0] = argc;
- + kexec_args[1] = (unsigned long)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 *)kexec_relocate_new_kernel;
- +
- + kexec_args[1] += reloc_delta;
- + for (i = 0; i < argc; i++)
- + kexec_argv[i] += reloc_delta;
- +}
- +
- static void kexec_image_info(const struct kimage *kimage)
- {
- unsigned long i;
- @@ -52,6 +142,18 @@ int
- machine_kexec_prepare(struct kimage *kimage)
- {
- kexec_image_info(kimage);
- + /*
- + * Whenever arguments passed from kexec-tools, Init the arguments as
- + * the original ones to try avoiding booting failure.
- + */
- +
- + 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);
- @@ -89,10 +191,12 @@ machine_kexec(struct kimage *image)
- unsigned long *ptr;
-
- reboot_code_buffer =
- - (unsigned long)page_address(image->control_code_page);
- + (unsigned long)page_address(image->control_code_page);
- + pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
-
- kexec_start_address =
- (unsigned long) phys_to_virt(image->start);
- + pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
-
- if (image->type == KEXEC_TYPE_DEFAULT) {
- kexec_indirection_page =
- @@ -100,9 +204,19 @@ machine_kexec(struct kimage *image)
- } else {
- kexec_indirection_page = (unsigned long)&image->head;
- }
- + pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
-
- - memcpy((void*)reboot_code_buffer, relocate_new_kernel,
- - relocate_new_kernel_size);
- + pr_info("Where is memcpy: %p\n", memcpy);
- + pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
- + (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
- + pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
- + (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
- + memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
- + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
- +
- + pr_info("Before _print_args().\n");
- + machine_kexec_print_args();
- + pr_info("Before eval loop.\n");
-
- /*
- * The generic kexec code builds a page list with physical
- @@ -121,15 +235,16 @@ machine_kexec(struct kimage *image)
- /*
- * we do not want to be bothered.
- */
- + pr_info("Before irq_disable.\n");
- local_irq_disable();
-
- - printk("Will call new kernel at %08lx\n", image->start);
- - printk("Bye ...\n");
- + pr_info("Will call new kernel at %08lx\n", image->start);
- + pr_info("Bye ...\n");
- __flush_cache_all();
- #ifdef CONFIG_SMP
- /* All secondary cpus now may jump to kexec_wait cycle */
- relocated_kexec_smp_wait = reboot_code_buffer +
- - (void *)(kexec_smp_wait - relocate_new_kernel);
- + (void *)(kexec_smp_wait - kexec_relocate_new_kernel);
- smp_wmb();
- atomic_set(&kexec_ready_to_reboot, 1);
- #endif
- --- /dev/null
- +++ b/arch/mips/kernel/machine_kexec.h
- @@ -0,0 +1,20 @@
- +#ifndef _MACHINE_KEXEC_H
- +#define _MACHINE_KEXEC_H
- +
- +#ifndef __ASSEMBLY__
- +extern const unsigned char kexec_relocate_new_kernel[];
- +extern unsigned long kexec_relocate_new_kernel_end;
- +extern unsigned long kexec_start_address;
- +extern unsigned long kexec_indirection_page;
- +
- +extern char kexec_argv_buf[];
- +extern char *kexec_argv[];
- +
- +#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
- +#endif /* !__ASSEMBLY__ */
- +
- +#define KEXEC_COMMAND_LINE_SIZE 256
- +#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16)
- +#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long))
- +
- +#endif
- --- a/arch/mips/kernel/relocate_kernel.S
- +++ b/arch/mips/kernel/relocate_kernel.S
- @@ -12,8 +12,9 @@
- #include <asm/mipsregs.h>
- #include <asm/stackframe.h>
- #include <asm/addrspace.h>
- +#include "machine_kexec.h"
-
- -LEAF(relocate_new_kernel)
- +LEAF(kexec_relocate_new_kernel)
- PTR_L a0, arg0
- PTR_L a1, arg1
- PTR_L a2, arg2
- @@ -98,7 +99,7 @@ done:
- #endif
- /* jump to kexec_start_address */
- j s1
- - END(relocate_new_kernel)
- + END(kexec_relocate_new_kernel)
-
- #ifdef CONFIG_SMP
- /*
- @@ -184,9 +185,15 @@ kexec_indirection_page:
- PTR 0
- .size kexec_indirection_page, PTRSIZE
-
- -relocate_new_kernel_end:
- +kexec_argv_buf:
- + EXPORT(kexec_argv_buf)
- + .skip KEXEC_COMMAND_LINE_SIZE
- + .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
- +
- +kexec_argv:
- + EXPORT(kexec_argv)
- + .skip KEXEC_ARGV_SIZE
- + .size kexec_argv, KEXEC_ARGV_SIZE
-
- -relocate_new_kernel_size:
- - EXPORT(relocate_new_kernel_size)
- - PTR relocate_new_kernel_end - relocate_new_kernel
- - .size relocate_new_kernel_size, PTRSIZE
- +kexec_relocate_new_kernel_end:
- + EXPORT(kexec_relocate_new_kernel_end)
|