diff options
| -rw-r--r-- | arch/arm/Kconfig | 14 | ||||
| -rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/kernel/calls.S | 1 | ||||
| -rw-r--r-- | arch/arm/kernel/machine_kexec.c | 78 | ||||
| -rw-r--r-- | arch/arm/kernel/relocate_kernel.S | 74 | ||||
| -rw-r--r-- | include/asm-arm/kexec.h | 30 | ||||
| -rw-r--r-- | include/asm-arm/unistd.h | 1 | ||||
| -rw-r--r-- | include/linux/kexec.h | 1 |
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 | ||
| 741 | config 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 | |||
| 741 | endmenu | 755 | endmenu |
| 742 | 756 | ||
| 743 | if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX ) | 757 | if (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 | |||
| 19 | obj-$(CONFIG_ISA_DMA) += dma-isa.o | 19 | obj-$(CONFIG_ISA_DMA) += dma-isa.o |
| 20 | obj-$(CONFIG_PCI) += bios32.o isa.o | 20 | obj-$(CONFIG_PCI) += bios32.o isa.o |
| 21 | obj-$(CONFIG_SMP) += smp.o | 21 | obj-$(CONFIG_SMP) += smp.o |
| 22 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | ||
| 22 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | 23 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o |
| 23 | 24 | ||
| 24 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o | 25 | obj-$(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 | |||
| 16 | const extern unsigned char relocate_new_kernel[]; | ||
| 17 | const extern unsigned int relocate_new_kernel_size; | ||
| 18 | |||
| 19 | extern void setup_mm_for_reboot(char mode); | ||
| 20 | |||
| 21 | extern unsigned long kexec_start_address; | ||
| 22 | extern unsigned long kexec_indirection_page; | ||
| 23 | extern 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 | |||
| 30 | int machine_kexec_prepare(struct kimage *image) | ||
| 31 | { | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | void machine_kexec_cleanup(struct kimage *image) | ||
| 36 | { | ||
| 37 | } | ||
| 38 | |||
| 39 | void machine_shutdown(void) | ||
| 40 | { | ||
| 41 | } | ||
| 42 | |||
| 43 | void machine_crash_shutdown(struct pt_regs *regs) | ||
| 44 | { | ||
| 45 | } | ||
| 46 | |||
| 47 | void 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 | ||
| 8 | relocate_new_kernel: | ||
| 9 | |||
| 10 | ldr r0,kexec_indirection_page | ||
| 11 | ldr r1,kexec_start_address | ||
| 12 | |||
| 13 | |||
| 14 | 0: /* 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 | ||
| 22 | 1: | ||
| 23 | /* Is it an indirection page */ | ||
| 24 | tst r3,#2,0 | ||
| 25 | beq 1f | ||
| 26 | bic r0,r3,#2 | ||
| 27 | b 0b | ||
| 28 | 1: | ||
| 29 | |||
| 30 | /* are we done ? */ | ||
| 31 | tst r3,#4,0 | ||
| 32 | beq 1f | ||
| 33 | b 2f | ||
| 34 | |||
| 35 | 1: | ||
| 36 | /* is it source ? */ | ||
| 37 | tst r3,#8,0 | ||
| 38 | beq 0b | ||
| 39 | bic r3,r3,#8 | ||
| 40 | mov r6,#1024 | ||
| 41 | 9: | ||
| 42 | ldr r5,[r3],#4 | ||
| 43 | str r5,[r4],#4 | ||
| 44 | subs r6,r6,#1 | ||
| 45 | bne 9b | ||
| 46 | b 0b | ||
| 47 | |||
| 48 | 2: | ||
| 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 | ||
| 57 | kexec_start_address: | ||
| 58 | .long 0x0 | ||
| 59 | |||
| 60 | .globl kexec_indirection_page | ||
| 61 | kexec_indirection_page: | ||
| 62 | .long 0x0 | ||
| 63 | |||
| 64 | .globl kexec_mach_type | ||
| 65 | kexec_mach_type: | ||
| 66 | .long 0x0 | ||
| 67 | |||
| 68 | relocate_new_kernel_end: | ||
| 69 | |||
| 70 | .globl relocate_new_kernel_size | ||
| 71 | relocate_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 | |||
| 21 | struct kimage; | ||
| 22 | /* Provide a dummy definition to avoid build failures. */ | ||
| 23 | static 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) |
