mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 03cd81fbca6b91317ec1a7b3b3c09fb8d08f83a6 Mon Sep 17 00:00:00 2001
 | |
| From: Wu Zhangjin <wuzhangjin@gmail.com>
 | |
| Date: Tue, 11 Jan 2011 18:42:08 +0000
 | |
| Subject: MIPS: Kexec: Enhance the support
 | |
| 
 | |
| Changes:
 | |
|   o Print more information in machine_kexec() for debugging
 | |
|     E.g. with this information, the kexec_start_address has been found
 | |
|     it was wrong with 64bit kernel / o32 kexec-tools. Which must be
 | |
|     fixed later.
 | |
|   o Link relocate_kernel.S to a section for future extension
 | |
|     This allows more functions can be added for the kexec relocation
 | |
|     part even written in C. to add code into that section, you just need
 | |
|     to mark your function or data with __kexec or
 | |
|     __attribute__((__section__(".__kexec.relocate")))
 | |
| 
 | |
| TODO:
 | |
| 
 | |
| 1. Make 64bit kernel / o32|n32|64 kexec-tools works
 | |
| 
 | |
| Fix the user-space kexec-tools, seems the tool only work for 32bit
 | |
| machine. So, we need to add 64bit support for it. The address of the
 | |
| entry point(kexec_start_address) is wrong and make the "kexec -e" fail.
 | |
| the real entry point must be read from the new kernel image by the
 | |
| user-space kexec-tools, otherwise, it will not work.  The above 64bit
 | |
| support tested is 64bit kernel with o32 user-space kexec-tools. The root
 | |
| cause may be the different definition of virt_to_phys() and
 | |
| phys_to_virt() in the kexec-tools and kernel space for 64bit system /
 | |
| o32 kernel.
 | |
| 
 | |
| Ref: http://www.linux-mips.org/archives/linux-mips/2009-08/msg00149.html
 | |
| 
 | |
| 2. Pass the arguments from kexec-tools to the new kernel image
 | |
| 
 | |
| Please refer to: "MIPS: Loongson: Kexec: Pass parameters to new kernel"
 | |
| 
 | |
| Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
 | |
| ---
 | |
| --- a/arch/mips/include/asm/kexec.h
 | |
| +++ b/arch/mips/include/asm/kexec.h
 | |
| @@ -36,6 +36,16 @@ static inline void crash_setup_regs(stru
 | |
|  }
 | |
|  
 | |
|  #ifdef CONFIG_KEXEC
 | |
| +
 | |
| +#define __kexec __attribute__((__section__(".__kexec.relocate")))
 | |
| +
 | |
| +/* The linker tells us where the relocate_new_kernel part is. */
 | |
| +extern const unsigned char __start___kexec_relocate;
 | |
| +extern const unsigned char __end___kexec_relocate;
 | |
| +
 | |
| +extern unsigned long kexec_start_address;
 | |
| +extern unsigned long kexec_indirection_page;
 | |
| +
 | |
|  struct kimage;
 | |
|  extern unsigned long kexec_args[4];
 | |
|  extern int (*_machine_kexec_prepare)(struct kimage *);
 | |
| --- a/arch/mips/kernel/machine_kexec.c
 | |
| +++ b/arch/mips/kernel/machine_kexec.c
 | |
| @@ -14,10 +14,6 @@
 | |
|  #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;
 | |
|  
 | |
|  int (*_machine_kexec_prepare)(struct kimage *) = NULL;
 | |
|  void (*_machine_kexec_shutdown)(void) = NULL;
 | |
| @@ -61,21 +57,34 @@ typedef void (*noretfun_t)(void) __attri
 | |
|  void
 | |
|  machine_kexec(struct kimage *image)
 | |
|  {
 | |
| +	unsigned long kexec_relocate_size;
 | |
|  	unsigned long reboot_code_buffer;
 | |
|  	unsigned long entry;
 | |
|  	unsigned long *ptr;
 | |
|  
 | |
| +	kexec_relocate_size = (unsigned long)(&__end___kexec_relocate) -
 | |
| +		(unsigned long)(&__start___kexec_relocate);
 | |
| +	pr_info("kexec_relocate_size = %lu\n", kexec_relocate_size);
 | |
| +
 | |
|  	reboot_code_buffer =
 | |
|  	  (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(entry point of new kernel) = %p\n",
 | |
| +			(void *)kexec_start_address);
 | |
|  
 | |
|  	kexec_indirection_page =
 | |
|  		(unsigned long) phys_to_virt(image->head & PAGE_MASK);
 | |
| +	pr_info("kexec_indirection_page = %p\n",
 | |
| +			(void *)kexec_indirection_page);
 | |
|  
 | |
| -	memcpy((void*)reboot_code_buffer, relocate_new_kernel,
 | |
| -	       relocate_new_kernel_size);
 | |
| +	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);
 | |
|  
 | |
|  	/*
 | |
|  	 * The generic kexec code builds a page list with physical
 | |
| @@ -96,8 +105,8 @@ machine_kexec(struct kimage *image)
 | |
|  	 */
 | |
|  	local_irq_disable();
 | |
|  
 | |
| -	printk("Will call new kernel at %08lx\n", image->start);
 | |
| -	printk("Bye ...\n");
 | |
| +	pr_info("Will call new kernel at %p\n", (void *)kexec_start_address);
 | |
| +	pr_info("Bye ...\n");
 | |
|  	__flush_cache_all();
 | |
|  #ifdef CONFIG_SMP
 | |
|  	/* All secondary cpus now may jump to kexec_wait cycle */
 | |
| @@ -108,4 +117,3 @@ machine_kexec(struct kimage *image)
 | |
|  #endif
 | |
|  	((noretfun_t) reboot_code_buffer)();
 | |
|  }
 | |
| -
 | |
| --- a/arch/mips/kernel/relocate_kernel.S
 | |
| +++ b/arch/mips/kernel/relocate_kernel.S
 | |
| @@ -14,6 +14,8 @@
 | |
|  #include <asm/stackframe.h>
 | |
|  #include <asm/addrspace.h>
 | |
|  
 | |
| +	.section	.kexec.relocate, "ax"
 | |
| +
 | |
|  LEAF(relocate_new_kernel)
 | |
|  	PTR_L a0,	arg0
 | |
|  	PTR_L a1,	arg1
 | |
| @@ -155,9 +157,3 @@ EXPORT(kexec_start_address)
 | |
|  EXPORT(kexec_indirection_page)
 | |
|  	PTR		0
 | |
|  	.size		kexec_indirection_page, PTRSIZE
 | |
| -
 | |
| -relocate_new_kernel_end:
 | |
| -
 | |
| -EXPORT(relocate_new_kernel_size)
 | |
| -	PTR		relocate_new_kernel_end - relocate_new_kernel
 | |
| -	.size		relocate_new_kernel_size, PTRSIZE
 | |
| --- a/arch/mips/kernel/vmlinux.lds.S
 | |
| +++ b/arch/mips/kernel/vmlinux.lds.S
 | |
| @@ -58,6 +58,10 @@ SECTIONS
 | |
|  		*(.text.*)
 | |
|  		*(.fixup)
 | |
|  		*(.gnu.warning)
 | |
| +		__start___kexec_relocate = .;
 | |
| +		KEEP(*(.kexec.relocate))
 | |
| +		KEEP(*(.__kexec.relocate))
 | |
| +		__end___kexec_relocate = .;
 | |
|  	} :text = 0
 | |
|  	_etext = .;	/* End of text section */
 | |
|  
 |