Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c587e4a6 authored by Richard Purdie's avatar Richard Purdie Committed by Russell King
Browse files

[ARM] 4137/1: Add kexec support



Add kexec support to ARM.

Improvements like commandline handling could be made but this patch gives
basic functional support. It uses the next available syscall number, 347.

Once the syscall number is known, userspace support will be
finalised/submitted to kexec-tools, various patches already exist.

Originally based on a patch by Maxim Syrchin but updated and forward
ported by various people.

Signed-off-by: default avatarRichard Purdie <rpurdie@rpsys.net>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 3b581f54
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -738,6 +738,20 @@ config XIP_PHYS_ADDR
	  be linked for and stored to.  This address is dependent on your
	  be linked for and stored to.  This address is dependent on your
	  own flash usage.
	  own flash usage.


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.

	  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.

endmenu
endmenu


if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
+1 −0
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
obj-$(CONFIG_PCI)		+= bios32.o isa.o
obj-$(CONFIG_PCI)		+= bios32.o isa.o
obj-$(CONFIG_SMP)		+= smp.o
obj-$(CONFIG_SMP)		+= smp.o
obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o


obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
+1 −0
Original line number Original line Diff line number Diff line
@@ -356,6 +356,7 @@
		CALL(sys_move_pages)
		CALL(sys_move_pages)
/* 345 */	CALL(sys_getcpu)
/* 345 */	CALL(sys_getcpu)
		CALL(sys_ni_syscall)		/* eventually epoll_pwait */
		CALL(sys_ni_syscall)		/* eventually epoll_pwait */
		CALL(sys_kexec_load)
#ifndef syscalls_counted
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
#define syscalls_counted
+78 −0
Original line number Original line Diff line number Diff line
/*
 * machine_kexec.c - handle transition of Linux booting another kernel
 */

#include <linux/mm.h>
#include <linux/kexec.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
#include <asm/cacheflush.h>
#include <asm/mach-types.h>

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

extern void setup_mm_for_reboot(char mode);

extern unsigned long kexec_start_address;
extern unsigned long kexec_indirection_page;
extern unsigned long kexec_mach_type;

/*
 * Provide a dummy crash_notes definition while crash dump arrives to arm.
 * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
 */

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

void machine_kexec_cleanup(struct kimage *image)
{
}

void machine_shutdown(void)
{
}

void machine_crash_shutdown(struct pt_regs *regs)
{
}

void machine_kexec(struct kimage *image)
{
	unsigned long page_list;
	unsigned long reboot_code_buffer_phys;
	void *reboot_code_buffer;


	page_list = image->head & PAGE_MASK;

	/* we need both effective and real address here */
	reboot_code_buffer_phys =
	    page_to_pfn(image->control_code_page) << PAGE_SHIFT;
	reboot_code_buffer = page_address(image->control_code_page);

	/* Prepare parameters for reboot_code_buffer*/
	kexec_start_address = image->start;
	kexec_indirection_page = page_list;
	kexec_mach_type = machine_arch_type;

	/* copy our kernel relocation code to the control code page */
	memcpy(reboot_code_buffer,
	       relocate_new_kernel, relocate_new_kernel_size);


	flush_icache_range((unsigned long) reboot_code_buffer,
			   (unsigned long) reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
	printk(KERN_INFO "Bye!\n");

	cpu_proc_fin();
	setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
	cpu_reset(reboot_code_buffer_phys);
}
+74 −0
Original line number Original line Diff line number Diff line
/*
 * relocate_kernel.S - put the kernel image in place to boot
 */

#include <asm/kexec.h>

	.globl relocate_new_kernel
relocate_new_kernel:

	ldr	r0,kexec_indirection_page
	ldr	r1,kexec_start_address


0:	/* top, read another word for the indirection page */
	ldr	r3, [r0],#4

	/* Is it a destination page. Put destination address to r4 */
	tst	r3,#1,0
	beq	1f
	bic	r4,r3,#1
	b	0b
1:
	/* Is it an indirection page */
	tst	r3,#2,0
	beq	1f
	bic	r0,r3,#2
	b	0b
1:

	/* are we done ? */
	tst	r3,#4,0
	beq	1f
	b	2f

1:
	/* is it source ? */
	tst	r3,#8,0
	beq	0b
	bic r3,r3,#8
	mov r6,#1024
9:
	ldr r5,[r3],#4
	str r5,[r4],#4
	subs r6,r6,#1
	bne 9b
	b 0b

2:
	/* Jump to relocated kernel */
	mov lr,r1
	mov r0,#0
	ldr r1,kexec_mach_type
	mov r2,#0
	mov pc,lr

	.globl kexec_start_address
kexec_start_address:
	.long	0x0

	.globl kexec_indirection_page
kexec_indirection_page:
	.long	0x0

	.globl kexec_mach_type
kexec_mach_type:
	.long	0x0

relocate_new_kernel_end:

	.globl relocate_new_kernel_size
relocate_new_kernel_size:
	.long relocate_new_kernel_end - relocate_new_kernel

Loading