Commit 583bb86f authored by Nicolas Schichan's avatar Nicolas Schichan Committed by Ralf Baechle
Browse files

[MIPS] Add support for kexec

A tiny userland application loading the kernel and invoking kexec_load for 
mips is available here:

http://chac.le-poulpe.net/~nico/kexec/kexec-2006-10-18.tar.gz



Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent c2379230
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -766,6 +766,23 @@ config TOSHIBA_RBTX4938

endchoice

config KEXEC
 	bool "Kexec system call (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
 	help
 	  kexec is a system call that implements the ability to shutdown your
 	  current kernel, and to start another kernel.  It is like a reboot
 	  but it is indepedent of the system firmware.   And like a reboot
 	  you can start any kernel with it, not just Linux.

 	  The name comes from the similiarity to the exec system call.

 	  It is an ongoing process to be certain the hardware in a machine
 	  is properly shutdown, so do not be surprised if this code does not
 	  initially work for you.  It may help to enable device hotplugging
 	  support.  As of this writing the exact hardware interface is
 	  strongly in flux, so no good recommendation can be made.

source "arch/mips/ddb5xxx/Kconfig"
source "arch/mips/gt64120/ev64120/Kconfig"
source "arch/mips/jazz/Kconfig"
+2 −0
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@ obj-$(CONFIG_64BIT) += cpu-bugs64.o

obj-$(CONFIG_I8253)		+= i8253.o

obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o

CFLAGS_cpu-bugs64.o	= $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)

EXTRA_AFLAGS := $(CFLAGS)
+85 −0
Original line number Diff line number Diff line
/*
 * machine_kexec.c for kexec
 * Created by <nschichan@corp.free.fr> on Thu Oct 12 15:15:06 2006
 *
 * This source code is licensed under the GNU General Public License,
 * Version 2.  See the file COPYING for more details.
 */

#include <linux/kexec.h>
#include <linux/mm.h>
#include <linux/delay.h>

#include <asm/cacheflush.h>
#include <asm/page.h>

const extern unsigned char relocate_new_kernel[];
const extern unsigned int relocate_new_kernel_size;

extern unsigned long kexec_start_address;
extern unsigned long kexec_indirection_page;

int
machine_kexec_prepare(struct kimage *kimage)
{
	return 0;
}

void
machine_kexec_cleanup(struct kimage *kimage)
{
}

void
machine_shutdown(void)
{
}

void
machine_crash_shutdown(struct pt_regs *regs)
{
}

void
machine_kexec(struct kimage *image)
{
	unsigned long reboot_code_buffer;
	unsigned long entry;
	unsigned long *ptr;

	reboot_code_buffer =
	  (unsigned long)page_address(image->control_code_page);

	kexec_start_address = image->start;
	kexec_indirection_page = phys_to_virt(image->head & PAGE_MASK);

	memcpy((void*)reboot_code_buffer, relocate_new_kernel,
	       relocate_new_kernel_size);

	/*
	 * The generic kexec code builds a page list with physical
	 * addresses. they are directly accessible through KSEG0 (or
	 * CKSEG0 or XPHYS if on 64bit system), hence the
	 * pys_to_virt() call.
	 */
	for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE);
	     ptr = (entry & IND_INDIRECTION) ?
	       phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
		if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
		    *ptr & IND_DESTINATION)
			*ptr = phys_to_virt(*ptr);
	}

	/*
	 * we do not want to be bothered.
	 */
	local_irq_disable();

	flush_icache_range(reboot_code_buffer,
			   reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);

	printk("Will call new kernel at %08x\n", image->start);
	printk("Bye ...\n");
	flush_cache_all();
	((void (*)(void))reboot_code_buffer)();
}
+80 −0
Original line number Diff line number Diff line
/*
 * relocate_kernel.S for kexec
 * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
 *
 * This source code is licensed under the GNU General Public License,
 * Version 2.  See the file COPYING for more details.
 */

#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/regdef.h>
#include <asm/page.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>

	.globl relocate_new_kernel
relocate_new_kernel:

	PTR_L	s0, kexec_indirection_page
	PTR_L	s1, kexec_start_address

process_entry:
	PTR_L	s2, (s0)
	PTR_ADD	s0, s0, SZREG

	/* destination page */
	and	s3, s2, 0x1
	beq	s3, zero, 1f
	and	s4, s2, ~0x1	/* store destination addr in s4 */
	move	a0, s4
	b	process_entry

1:
	/* indirection page, update s0  */
	and	s3, s2, 0x2
	beq	s3, zero, 1f
	and	s0, s2, ~0x2
	b	process_entry

1:
	/* done page */
	and	s3, s2, 0x4
	beq	s3, zero, 1f
	b	done
1:
	/* source page */
	and	s3, s2, 0x8
	beq	s3, zero, process_entry
	and	s2, s2, ~0x8
	li	s6, (1 << PAGE_SHIFT) / SZREG

copy_word:
	/* copy page word by word */
	REG_L	s5, (s2)
	REG_S	s5, (s4)
	INT_ADD	s4, s4, SZREG
	INT_ADD	s2, s2, SZREG
	INT_SUB	s6, s6, 1
	beq	s6, zero, process_entry
	b	copy_word
	b	process_entry

done:
	/* jump to kexec_start_address */
	j	s1

	.globl kexec_start_address
kexec_start_address:
	.long	0x0

	.globl kexec_indirection_page
kexec_indirection_page:
	.long	0x0

relocate_new_kernel_end:

	.globl relocate_new_kernel_size
relocate_new_kernel_size:
	.long relocate_new_kernel_end - relocate_new_kernel
+1 −1
Original line number Diff line number Diff line
@@ -653,7 +653,7 @@ einval: li v0, -EINVAL
	sys	sys_move_pages		6
	sys	sys_set_robust_list	2
	sys	sys_get_robust_list	3	/* 4310 */
	sys	sys_ni_syscall		0
	sys	sys_kexec_load		4
	sys	sys_getcpu		3
	sys	sys_epoll_pwait		6
	.endm
Loading