| 1 | From 03cd81fbca6b91317ec1a7b3b3c09fb8d08f83a6 Mon Sep 17 00:00:00 2001 |
| 2 | From: Wu Zhangjin <wuzhangjin@gmail.com> |
| 3 | Date: Tue, 11 Jan 2011 18:42:08 +0000 |
| 4 | Subject: MIPS: Kexec: Enhance the support |
| 5 | |
| 6 | Changes: |
| 7 | o Print more information in machine_kexec() for debugging |
| 8 | E.g. with this information, the kexec_start_address has been found |
| 9 | it was wrong with 64bit kernel / o32 kexec-tools. Which must be |
| 10 | fixed later. |
| 11 | o Link relocate_kernel.S to a section for future extension |
| 12 | This allows more functions can be added for the kexec relocation |
| 13 | part even written in C. to add code into that section, you just need |
| 14 | to mark your function or data with __kexec or |
| 15 | __attribute__((__section__(".__kexec.relocate"))) |
| 16 | |
| 17 | TODO: |
| 18 | |
| 19 | 1. Make 64bit kernel / o32|n32|64 kexec-tools works |
| 20 | |
| 21 | Fix the user-space kexec-tools, seems the tool only work for 32bit |
| 22 | machine. So, we need to add 64bit support for it. The address of the |
| 23 | entry point(kexec_start_address) is wrong and make the "kexec -e" fail. |
| 24 | the real entry point must be read from the new kernel image by the |
| 25 | user-space kexec-tools, otherwise, it will not work. The above 64bit |
| 26 | support tested is 64bit kernel with o32 user-space kexec-tools. The root |
| 27 | cause may be the different definition of virt_to_phys() and |
| 28 | phys_to_virt() in the kexec-tools and kernel space for 64bit system / |
| 29 | o32 kernel. |
| 30 | |
| 31 | Ref: http://www.linux-mips.org/archives/linux-mips/2009-08/msg00149.html |
| 32 | |
| 33 | 2. Pass the arguments from kexec-tools to the new kernel image |
| 34 | |
| 35 | Please refer to: "MIPS: Loongson: Kexec: Pass parameters to new kernel" |
| 36 | |
| 37 | Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> |
| 38 | --- |
| 39 | --- a/arch/mips/include/asm/kexec.h |
| 40 | +++ b/arch/mips/include/asm/kexec.h |
| 41 | @@ -36,6 +36,16 @@ static inline void crash_setup_regs(stru |
| 42 | } |
| 43 | |
| 44 | #ifdef CONFIG_KEXEC |
| 45 | + |
| 46 | +#define __kexec __attribute__((__section__(".__kexec.relocate"))) |
| 47 | + |
| 48 | +/* The linker tells us where the relocate_new_kernel part is. */ |
| 49 | +extern const unsigned char __start___kexec_relocate; |
| 50 | +extern const unsigned char __end___kexec_relocate; |
| 51 | + |
| 52 | +extern unsigned long kexec_start_address; |
| 53 | +extern unsigned long kexec_indirection_page; |
| 54 | + |
| 55 | struct kimage; |
| 56 | extern unsigned long kexec_args[4]; |
| 57 | extern int (*_machine_kexec_prepare)(struct kimage *); |
| 58 | --- a/arch/mips/kernel/machine_kexec.c |
| 59 | +++ b/arch/mips/kernel/machine_kexec.c |
| 60 | @@ -13,12 +13,6 @@ |
| 61 | #include <asm/cacheflush.h> |
| 62 | #include <asm/page.h> |
| 63 | |
| 64 | -extern const unsigned char relocate_new_kernel[]; |
| 65 | -extern const size_t relocate_new_kernel_size; |
| 66 | - |
| 67 | -extern unsigned long kexec_start_address; |
| 68 | -extern unsigned long kexec_indirection_page; |
| 69 | - |
| 70 | int (*_machine_kexec_prepare)(struct kimage *) = NULL; |
| 71 | void (*_machine_kexec_shutdown)(void) = NULL; |
| 72 | void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; |
| 73 | @@ -61,21 +55,34 @@ typedef void (*noretfun_t)(void) __attri |
| 74 | void |
| 75 | machine_kexec(struct kimage *image) |
| 76 | { |
| 77 | + unsigned long kexec_relocate_size; |
| 78 | unsigned long reboot_code_buffer; |
| 79 | unsigned long entry; |
| 80 | unsigned long *ptr; |
| 81 | |
| 82 | + kexec_relocate_size = (unsigned long)(&__end___kexec_relocate) - |
| 83 | + (unsigned long)(&__start___kexec_relocate); |
| 84 | + pr_info("kexec_relocate_size = %lu\n", kexec_relocate_size); |
| 85 | + |
| 86 | reboot_code_buffer = |
| 87 | (unsigned long)page_address(image->control_code_page); |
| 88 | + pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer); |
| 89 | |
| 90 | kexec_start_address = |
| 91 | (unsigned long) phys_to_virt(image->start); |
| 92 | + pr_info("kexec_start_address(entry point of new kernel) = %p\n", |
| 93 | + (void *)kexec_start_address); |
| 94 | |
| 95 | kexec_indirection_page = |
| 96 | (unsigned long) phys_to_virt(image->head & PAGE_MASK); |
| 97 | + pr_info("kexec_indirection_page = %p\n", |
| 98 | + (void *)kexec_indirection_page); |
| 99 | |
| 100 | - memcpy((void*)reboot_code_buffer, relocate_new_kernel, |
| 101 | - relocate_new_kernel_size); |
| 102 | + memcpy((void *)reboot_code_buffer, &__start___kexec_relocate, |
| 103 | + kexec_relocate_size); |
| 104 | + |
| 105 | + pr_info("Copy kexec_relocate section from %p to reboot_code_buffer: %p\n", |
| 106 | + &__start___kexec_relocate, (void *)reboot_code_buffer); |
| 107 | |
| 108 | /* |
| 109 | * The generic kexec code builds a page list with physical |
| 110 | @@ -96,8 +103,8 @@ machine_kexec(struct kimage *image) |
| 111 | */ |
| 112 | local_irq_disable(); |
| 113 | |
| 114 | - printk("Will call new kernel at %08lx\n", image->start); |
| 115 | - printk("Bye ...\n"); |
| 116 | + pr_info("Will call new kernel at %p\n", (void *)kexec_start_address); |
| 117 | + pr_info("Bye ...\n"); |
| 118 | __flush_cache_all(); |
| 119 | #ifdef CONFIG_SMP |
| 120 | /* All secondary cpus now may jump to kexec_wait cycle */ |
| 121 | @@ -108,4 +115,3 @@ machine_kexec(struct kimage *image) |
| 122 | #endif |
| 123 | ((noretfun_t) reboot_code_buffer)(); |
| 124 | } |
| 125 | - |
| 126 | --- a/arch/mips/kernel/relocate_kernel.S |
| 127 | +++ b/arch/mips/kernel/relocate_kernel.S |
| 128 | @@ -14,6 +14,8 @@ |
| 129 | #include <asm/stackframe.h> |
| 130 | #include <asm/addrspace.h> |
| 131 | |
| 132 | + .section .kexec.relocate, "ax" |
| 133 | + |
| 134 | LEAF(relocate_new_kernel) |
| 135 | PTR_L a0, arg0 |
| 136 | PTR_L a1, arg1 |
| 137 | @@ -155,9 +157,3 @@ EXPORT(kexec_start_address) |
| 138 | EXPORT(kexec_indirection_page) |
| 139 | PTR 0 |
| 140 | .size kexec_indirection_page, PTRSIZE |
| 141 | - |
| 142 | -relocate_new_kernel_end: |
| 143 | - |
| 144 | -EXPORT(relocate_new_kernel_size) |
| 145 | - PTR relocate_new_kernel_end - relocate_new_kernel |
| 146 | - .size relocate_new_kernel_size, PTRSIZE |
| 147 | --- a/arch/mips/kernel/vmlinux.lds.S |
| 148 | +++ b/arch/mips/kernel/vmlinux.lds.S |
| 149 | @@ -58,6 +58,10 @@ SECTIONS |
| 150 | *(.text.*) |
| 151 | *(.fixup) |
| 152 | *(.gnu.warning) |
| 153 | + __start___kexec_relocate = .; |
| 154 | + KEEP(*(.kexec.relocate)) |
| 155 | + KEEP(*(.__kexec.relocate)) |
| 156 | + __end___kexec_relocate = .; |
| 157 | } :text = 0 |
| 158 | _etext = .; /* End of text section */ |
| 159 | |
| 160 | |