aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig14
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/calls.S1
-rw-r--r--arch/arm/kernel/machine_kexec.c78
-rw-r--r--arch/arm/kernel/relocate_kernel.S74
-rw-r--r--include/asm-arm/kexec.h30
-rw-r--r--include/asm-arm/unistd.h1
-rw-r--r--include/linux/kexec.h1
8 files changed, 200 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6783c2e5512d..a8298949d166 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -738,6 +738,20 @@ config XIP_PHYS_ADDR
738 be linked for and stored to. This address is dependent on your 738 be linked for and stored to. This address is dependent on your
739 own flash usage. 739 own flash usage.
740 740
741config KEXEC
742 bool "Kexec system call (EXPERIMENTAL)"
743 depends on EXPERIMENTAL
744 help
745 kexec is a system call that implements the ability to shutdown your
746 current kernel, and to start another kernel. It is like a reboot
747 but it is indepedent of the system firmware. And like a reboot
748 you can start any kernel with it, not just Linux.
749
750 It is an ongoing process to be certain the hardware in a machine
751 is properly shutdown, so do not be surprised if this code does not
752 initially work for you. It may help to enable device hotplugging
753 support.
754
741endmenu 755endmenu
742 756
743if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX ) 757if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index ab06a86e85d5..d5002889773e 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o
19obj-$(CONFIG_ISA_DMA) += dma-isa.o 19obj-$(CONFIG_ISA_DMA) += dma-isa.o
20obj-$(CONFIG_PCI) += bios32.o isa.o 20obj-$(CONFIG_PCI) += bios32.o isa.o
21obj-$(CONFIG_SMP) += smp.o 21obj-$(CONFIG_SMP) += smp.o
22obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
22obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o 23obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
23 24
24obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o 25obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index f7598cbc7ec5..ae89cdd82b16 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -356,6 +356,7 @@
356 CALL(sys_move_pages) 356 CALL(sys_move_pages)
357/* 345 */ CALL(sys_getcpu) 357/* 345 */ CALL(sys_getcpu)
358 CALL(sys_ni_syscall) /* eventually epoll_pwait */ 358 CALL(sys_ni_syscall) /* eventually epoll_pwait */
359 CALL(sys_kexec_load)
359#ifndef syscalls_counted 360#ifndef syscalls_counted
360.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls 361.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
361#define syscalls_counted 362#define syscalls_counted
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
new file mode 100644
index 000000000000..863c66454f2b
--- /dev/null
+++ b/arch/arm/kernel/machine_kexec.c
@@ -0,0 +1,78 @@
1/*
2 * machine_kexec.c - handle transition of Linux booting another kernel
3 */
4
5#include <linux/mm.h>
6#include <linux/kexec.h>
7#include <linux/delay.h>
8#include <linux/reboot.h>
9#include <asm/pgtable.h>
10#include <asm/pgalloc.h>
11#include <asm/mmu_context.h>
12#include <asm/io.h>
13#include <asm/cacheflush.h>
14#include <asm/mach-types.h>
15
16const extern unsigned char relocate_new_kernel[];
17const extern unsigned int relocate_new_kernel_size;
18
19extern void setup_mm_for_reboot(char mode);
20
21extern unsigned long kexec_start_address;
22extern unsigned long kexec_indirection_page;
23extern unsigned long kexec_mach_type;
24
25/*
26 * Provide a dummy crash_notes definition while crash dump arrives to arm.
27 * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
28 */
29
30int machine_kexec_prepare(struct kimage *image)
31{
32 return 0;
33}
34
35void machine_kexec_cleanup(struct kimage *image)
36{
37}
38
39void machine_shutdown(void)
40{
41}
42
43void machine_crash_shutdown(struct pt_regs *regs)
44{
45}
46
47void machine_kexec(struct kimage *image)
48{
49 unsigned long page_list;
50 unsigned long reboot_code_buffer_phys;
51 void *reboot_code_buffer;
52
53
54 page_list = image->head & PAGE_MASK;
55
56 /* we need both effective and real address here */
57 reboot_code_buffer_phys =
58 page_to_pfn(image->control_code_page) << PAGE_SHIFT;
59 reboot_code_buffer = page_address(image->control_code_page);
60
61 /* Prepare parameters for reboot_code_buffer*/
62 kexec_start_address = image->start;
63 kexec_indirection_page = page_list;
64 kexec_mach_type = machine_arch_type;
65
66 /* copy our kernel relocation code to the control code page */
67 memcpy(reboot_code_buffer,
68 relocate_new_kernel, relocate_new_kernel_size);
69
70
71 flush_icache_range((unsigned long) reboot_code_buffer,
72 (unsigned long) reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
73 printk(KERN_INFO "Bye!\n");
74
75 cpu_proc_fin();
76 setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
77 cpu_reset(reboot_code_buffer_phys);
78}
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..7baadae7cb27
--- /dev/null
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -0,0 +1,74 @@
1/*
2 * relocate_kernel.S - put the kernel image in place to boot
3 */
4
5#include <asm/kexec.h>
6
7 .globl relocate_new_kernel
8relocate_new_kernel:
9
10 ldr r0,kexec_indirection_page
11 ldr r1,kexec_start_address
12
13
140: /* top, read another word for the indirection page */
15 ldr r3, [r0],#4
16
17 /* Is it a destination page. Put destination address to r4 */
18 tst r3,#1,0
19 beq 1f
20 bic r4,r3,#1
21 b 0b
221:
23 /* Is it an indirection page */
24 tst r3,#2,0
25 beq 1f
26 bic r0,r3,#2
27 b 0b
281:
29
30 /* are we done ? */
31 tst r3,#4,0
32 beq 1f
33 b 2f
34
351:
36 /* is it source ? */
37 tst r3,#8,0
38 beq 0b
39 bic r3,r3,#8
40 mov r6,#1024
419:
42 ldr r5,[r3],#4
43 str r5,[r4],#4
44 subs r6,r6,#1
45 bne 9b
46 b 0b
47
482:
49 /* Jump to relocated kernel */
50 mov lr,r1
51 mov r0,#0
52 ldr r1,kexec_mach_type
53 mov r2,#0
54 mov pc,lr
55
56 .globl kexec_start_address
57kexec_start_address:
58 .long 0x0
59
60 .globl kexec_indirection_page
61kexec_indirection_page:
62 .long 0x0
63
64 .globl kexec_mach_type
65kexec_mach_type:
66 .long 0x0
67
68relocate_new_kernel_end:
69
70 .globl relocate_new_kernel_size
71relocate_new_kernel_size:
72 .long relocate_new_kernel_end - relocate_new_kernel
73
74
diff --git a/include/asm-arm/kexec.h b/include/asm-arm/kexec.h
new file mode 100644
index 000000000000..8c1c6162a80c
--- /dev/null
+++ b/include/asm-arm/kexec.h
@@ -0,0 +1,30 @@
1#ifndef _ARM_KEXEC_H
2#define _ARM_KEXEC_H
3
4#ifdef CONFIG_KEXEC
5
6/* Maximum physical address we can use pages from */
7#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
8/* Maximum address we can reach in physical address mode */
9#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
10/* Maximum address we can use for the control code buffer */
11#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
12
13#define KEXEC_CONTROL_CODE_SIZE 4096
14
15#define KEXEC_ARCH KEXEC_ARCH_ARM
16
17#ifndef __ASSEMBLY__
18
19#define MAX_NOTE_BYTES 1024
20
21struct kimage;
22/* Provide a dummy definition to avoid build failures. */
23static inline void crash_setup_regs(struct pt_regs *newregs,
24 struct pt_regs *oldregs) { }
25
26#endif /* __ASSEMBLY__ */
27
28#endif /* CONFIG_KEXEC */
29
30#endif /* _ARM_KEXEC_H */
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index 97e7060000cf..0991b7bc3f78 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -372,6 +372,7 @@
372#define __NR_move_pages (__NR_SYSCALL_BASE+344) 372#define __NR_move_pages (__NR_SYSCALL_BASE+344)
373#define __NR_getcpu (__NR_SYSCALL_BASE+345) 373#define __NR_getcpu (__NR_SYSCALL_BASE+345)
374 /* 346 for epoll_pwait */ 374 /* 346 for epoll_pwait */
375#define __NR_sys_kexec_load (__NR_SYSCALL_BASE+347)
375 376
376/* 377/*
377 * The following SWIs are ARM private. 378 * The following SWIs are ARM private.
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index d02425cdd801..696e5ec63f77 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -125,6 +125,7 @@ extern struct kimage *kexec_crash_image;
125#define KEXEC_ARCH_PPC (20 << 16) 125#define KEXEC_ARCH_PPC (20 << 16)
126#define KEXEC_ARCH_PPC64 (21 << 16) 126#define KEXEC_ARCH_PPC64 (21 << 16)
127#define KEXEC_ARCH_IA_64 (50 << 16) 127#define KEXEC_ARCH_IA_64 (50 << 16)
128#define KEXEC_ARCH_ARM (40 << 16)
128#define KEXEC_ARCH_S390 (22 << 16) 129#define KEXEC_ARCH_S390 (22 << 16)
129#define KEXEC_ARCH_SH (42 << 16) 130#define KEXEC_ARCH_SH (42 << 16)
130#define KEXEC_ARCH_MIPS_LE (10 << 16) 131#define KEXEC_ARCH_MIPS_LE (10 << 16)