Commit c587e4a6a4d808fd2a1c4e7fb2d5a3a31e300d23

Authored by Richard Purdie
Committed by Russell King
1 parent 3b581f5485

[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: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Showing 8 changed files with 200 additions and 0 deletions Side-by-side Diff

... ... @@ -738,6 +738,20 @@
738 738 be linked for and stored to. This address is dependent on your
739 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 755 endmenu
742 756  
743 757 if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
arch/arm/kernel/Makefile
... ... @@ -19,6 +19,7 @@
19 19 obj-$(CONFIG_ISA_DMA) += dma-isa.o
20 20 obj-$(CONFIG_PCI) += bios32.o isa.o
21 21 obj-$(CONFIG_SMP) += smp.o
  22 +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
22 23 obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
23 24  
24 25 obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
arch/arm/kernel/calls.S
... ... @@ -356,6 +356,7 @@
356 356 CALL(sys_move_pages)
357 357 /* 345 */ CALL(sys_getcpu)
358 358 CALL(sys_ni_syscall) /* eventually epoll_pwait */
  359 + CALL(sys_kexec_load)
359 360 #ifndef syscalls_counted
360 361 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
361 362 #define syscalls_counted
arch/arm/kernel/machine_kexec.c
  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 +}
arch/arm/kernel/relocate_kernel.S
  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
include/asm-arm/kexec.h
  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 */
include/asm-arm/unistd.h
... ... @@ -372,6 +372,7 @@
372 372 #define __NR_move_pages (__NR_SYSCALL_BASE+344)
373 373 #define __NR_getcpu (__NR_SYSCALL_BASE+345)
374 374 /* 346 for epoll_pwait */
  375 +#define __NR_sys_kexec_load (__NR_SYSCALL_BASE+347)
375 376  
376 377 /*
377 378 * The following SWIs are ARM private.
include/linux/kexec.h
... ... @@ -125,6 +125,7 @@
125 125 #define KEXEC_ARCH_PPC (20 << 16)
126 126 #define KEXEC_ARCH_PPC64 (21 << 16)
127 127 #define KEXEC_ARCH_IA_64 (50 << 16)
  128 +#define KEXEC_ARCH_ARM (40 << 16)
128 129 #define KEXEC_ARCH_S390 (22 << 16)
129 130 #define KEXEC_ARCH_SH (42 << 16)
130 131 #define KEXEC_ARCH_MIPS_LE (10 << 16)