Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] kexec: kexec ppc support

I have tweaked this patch slightly to handle an empty list
of pages to relocate passed to relocate_new_kernel. And
I have added ppc_md.machine_crash_shutdown. To keep up with
the changes in the generic kexec infrastructure.

From: Albert Herranz <albert_herranz@yahoo.es>

The following patch adds support for kexec on the ppc32 platform.

Non-OpenFirmware based platforms are likely to work directly without
additional changes on the kernel side. The kexec-tools userland package
may need to be slightly updated, though.

For OpenFirmware based machines, additional work is still needed on the
kernel side before kexec support is ready. Benjamin Herrenschmidt is
kindly working on that part.

In order for a ppc platform to use the kexec kernel services it must
implement some ppc_md hooks. Otherwise, kexec will be explicitly disabled,
as suggested by benh.

There are 3+1 new ppc_md hooks that a platform supporting kexec may
implement. Two of them are mandatory for kexec to work. See
include/asm-ppc/machdep.h for details.

- machine_kexec_prepare(image)

This function is called to make any arrangements to the image before it
is loaded.

This hook _MUST_ be provided by a platform in order to activate kexec
support for that platform. Otherwise, the platform is considered to not
support kexec and the kexec_load system call will fail (that makes all
existing platforms by default non-kexec'able).

- machine_kexec_cleanup(image)

This function is called to make any cleanups on image after the loaded
image data it is freed. This hook is optional. A platform may or may
not provide this hook.

- machine_kexec(image)

This function is called to perform the _actual_ kexec. This hook
_MUST_ be provided by a platform in order to activate kexec support for
that platform.

If a platform provides machine_kexec_prepare but forgets to provide
machine_kexec, a kexec will fall back to a reboot.

A ready-to-use machine_kexec_simple() generic function is provided to,
hopefully, simplify kexec adoption for embedded platforms. A platform
may call this function from its specific machine_kexec hook, like this:

void myplatform_kexec(struct kimage *image)
{
machine_kexec_simple(image);
}

- machine_shutdown()

This function is called to perform any machine specific shutdowns, not
already done by drivers. This hook is optional. A platform may or may
not provide this hook.

An example (trimmed) platform specific module for a platform supporting
kexec through the existing machine_kexec_simple follows:

/* ... */

#ifdef CONFIG_KEXEC
int myplatform_kexec_prepare(struct kimage *image)
{
/* here, we can place additional preparations
*/
return 0; /* yes, we support kexec */
}

void myplatform_kexec(struct kimage *image)
{
machine_kexec_simple(image);
}
#endif /* CONFIG_KEXEC */

/* ... */

void __init
platform_init(unsigned long r3, unsigned long r4,
unsigned long r5,
unsigned long r6, unsigned long r7)
{

/* ... */

#ifdef CONFIG_KEXEC
ppc_md.machine_kexec_prepare =
myplatform_kexec_prepare;
ppc_md.machine_kexec =
myplatform_kexec;
#endif /* CONFIG_KEXEC */

/* ... */

}

The kexec ppc kernel support has been heavily tested on the GameCube Linux
port, and, as reported in the fastboot mailing list, it has been tested too
on a Moto 82xx ppc by Rick Richardson.

Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
Signed-off-by: Eric Biederman <ebiederm@xmission.com>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Eric W. Biederman and committed by
Linus Torvalds
70765aa4 5f5609df

+336 -1
+20
arch/ppc/Kconfig
··· 217 217 here. Saying Y here will not hurt performance (on any machine) but 218 218 will increase the size of the kernel. 219 219 220 + config KEXEC 221 + bool "kexec system call (EXPERIMENTAL)" 222 + depends on EXPERIMENTAL 223 + help 224 + kexec is a system call that implements the ability to shutdown your 225 + current kernel, and to start another kernel. It is like a reboot 226 + but it is indepedent of the system firmware. And like a reboot 227 + you can start any kernel with it, not just Linux. 228 + 229 + The name comes from the similiarity to the exec system call. 230 + 231 + It is an ongoing process to be certain the hardware in a machine 232 + is properly shutdown, so do not be surprised if this code does not 233 + initially work for you. It may help to enable device hotplugging 234 + support. As of this writing the exact hardware interface is 235 + strongly in flux, so no good recommendation can be made. 236 + 237 + In the GameCube implementation, kexec allows you to load and 238 + run DOL files, including kernel and homebrew DOLs. 239 + 220 240 source "drivers/cpufreq/Kconfig" 221 241 222 242 config CPU_FREQ_PMAC
+1
arch/ppc/kernel/Makefile
··· 29 29 ifndef CONFIG_E200 30 30 obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o 31 31 endif 32 + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o 32 33 33 34 ifndef CONFIG_MATH_EMULATION 34 35 obj-$(CONFIG_8xx) += softemu8xx.o
+122
arch/ppc/kernel/machine_kexec.c
··· 1 + /* 2 + * machine_kexec.c - handle transition of Linux booting another kernel 3 + * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> 4 + * 5 + * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz 6 + * 7 + * This source code is licensed under the GNU General Public License, 8 + * Version 2. See the file COPYING for more details. 9 + */ 10 + 11 + #include <linux/mm.h> 12 + #include <linux/kexec.h> 13 + #include <linux/delay.h> 14 + #include <linux/reboot.h> 15 + #include <asm/pgtable.h> 16 + #include <asm/pgalloc.h> 17 + #include <asm/mmu_context.h> 18 + #include <asm/io.h> 19 + #include <asm/hw_irq.h> 20 + #include <asm/cacheflush.h> 21 + #include <asm/machdep.h> 22 + 23 + typedef NORET_TYPE void (*relocate_new_kernel_t)( 24 + unsigned long indirection_page, unsigned long reboot_code_buffer, 25 + unsigned long start_address) ATTRIB_NORET; 26 + 27 + const extern unsigned char relocate_new_kernel[]; 28 + const extern unsigned int relocate_new_kernel_size; 29 + 30 + void machine_shutdown(void) 31 + { 32 + if (ppc_md.machine_shutdown) { 33 + ppc_md.machine_shutdown(); 34 + } 35 + } 36 + 37 + void machine_crash_shutdown(void) 38 + { 39 + if (ppc_md.machine_crash_shutdown) { 40 + ppc_md.machine_crash_shutdown(); 41 + } 42 + } 43 + 44 + /* 45 + * Do what every setup is needed on image and the 46 + * reboot code buffer to allow us to avoid allocations 47 + * later. 48 + */ 49 + int machine_kexec_prepare(struct kimage *image) 50 + { 51 + if (ppc_md.machine_kexec_prepare) { 52 + return ppc_md.machine_kexec_prepare(image); 53 + } 54 + /* 55 + * Fail if platform doesn't provide its own machine_kexec_prepare 56 + * implementation. 57 + */ 58 + return -ENOSYS; 59 + } 60 + 61 + void machine_kexec_cleanup(struct kimage *image) 62 + { 63 + if (ppc_md.machine_kexec_cleanup) { 64 + ppc_md.machine_kexec_cleanup(image); 65 + } 66 + } 67 + 68 + /* 69 + * Do not allocate memory (or fail in any way) in machine_kexec(). 70 + * We are past the point of no return, committed to rebooting now. 71 + */ 72 + NORET_TYPE void machine_kexec(struct kimage *image) 73 + { 74 + if (ppc_md.machine_kexec) { 75 + ppc_md.machine_kexec(image); 76 + } else { 77 + /* 78 + * Fall back to normal restart if platform doesn't provide 79 + * its own kexec function, and user insist to kexec... 80 + */ 81 + machine_restart(NULL); 82 + } 83 + for(;;); 84 + } 85 + 86 + 87 + /* 88 + * This is a generic machine_kexec function suitable at least for 89 + * non-OpenFirmware embedded platforms. 90 + * It merely copies the image relocation code to the control page and 91 + * jumps to it. 92 + * A platform specific function may just call this one. 93 + */ 94 + void machine_kexec_simple(struct kimage *image) 95 + { 96 + unsigned long page_list; 97 + unsigned long reboot_code_buffer, reboot_code_buffer_phys; 98 + relocate_new_kernel_t rnk; 99 + 100 + /* Interrupts aren't acceptable while we reboot */ 101 + local_irq_disable(); 102 + 103 + page_list = image->head; 104 + 105 + /* we need both effective and real address here */ 106 + reboot_code_buffer = 107 + (unsigned long)page_address(image->control_code_page); 108 + reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer); 109 + 110 + /* copy our kernel relocation code to the control code page */ 111 + memcpy((void *)reboot_code_buffer, 112 + relocate_new_kernel, relocate_new_kernel_size); 113 + 114 + flush_icache_range(reboot_code_buffer, 115 + reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); 116 + printk(KERN_INFO "Bye!\n"); 117 + 118 + /* now call it */ 119 + rnk = (relocate_new_kernel_t) reboot_code_buffer; 120 + (*rnk)(page_list, reboot_code_buffer_phys, image->start); 121 + } 122 +
+1 -1
arch/ppc/kernel/misc.S
··· 1444 1444 .long sys_mq_timedreceive /* 265 */ 1445 1445 .long sys_mq_notify 1446 1446 .long sys_mq_getsetattr 1447 - .long sys_ni_syscall /* 268 reserved for sys_kexec_load */ 1447 + .long sys_kexec_load 1448 1448 .long sys_add_key 1449 1449 .long sys_request_key /* 270 */ 1450 1450 .long sys_keyctl
+123
arch/ppc/kernel/relocate_kernel.S
··· 1 + /* 2 + * relocate_kernel.S - put the kernel image in place to boot 3 + * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> 4 + * 5 + * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz 6 + * 7 + * This source code is licensed under the GNU General Public License, 8 + * Version 2. See the file COPYING for more details. 9 + */ 10 + 11 + #include <asm/reg.h> 12 + #include <asm/ppc_asm.h> 13 + #include <asm/processor.h> 14 + 15 + #include <asm/kexec.h> 16 + 17 + #define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */ 18 + 19 + /* 20 + * Must be relocatable PIC code callable as a C function. 21 + */ 22 + .globl relocate_new_kernel 23 + relocate_new_kernel: 24 + /* r3 = page_list */ 25 + /* r4 = reboot_code_buffer */ 26 + /* r5 = start_address */ 27 + 28 + li r0, 0 29 + 30 + /* 31 + * Set Machine Status Register to a known status, 32 + * switch the MMU off and jump to 1: in a single step. 33 + */ 34 + 35 + mr r8, r0 36 + ori r8, r8, MSR_RI|MSR_ME 37 + mtspr SRR1, r8 38 + addi r8, r4, 1f - relocate_new_kernel 39 + mtspr SRR0, r8 40 + sync 41 + rfi 42 + 43 + 1: 44 + /* from this point address translation is turned off */ 45 + /* and interrupts are disabled */ 46 + 47 + /* set a new stack at the bottom of our page... */ 48 + /* (not really needed now) */ 49 + addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */ 50 + stw r0, 0(r1) 51 + 52 + /* Do the copies */ 53 + li r6, 0 /* checksum */ 54 + mr r0, r3 55 + b 1f 56 + 57 + 0: /* top, read another word for the indirection page */ 58 + lwzu r0, 4(r3) 59 + 60 + 1: 61 + /* is it a destination page? (r8) */ 62 + rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ 63 + beq 2f 64 + 65 + rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */ 66 + b 0b 67 + 68 + 2: /* is it an indirection page? (r3) */ 69 + rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ 70 + beq 2f 71 + 72 + rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */ 73 + subi r3, r3, 4 74 + b 0b 75 + 76 + 2: /* are we done? */ 77 + rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ 78 + beq 2f 79 + b 3f 80 + 81 + 2: /* is it a source page? (r9) */ 82 + rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ 83 + beq 0b 84 + 85 + rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */ 86 + 87 + li r7, PAGE_SIZE / 4 88 + mtctr r7 89 + subi r9, r9, 4 90 + subi r8, r8, 4 91 + 9: 92 + lwzu r0, 4(r9) /* do the copy */ 93 + xor r6, r6, r0 94 + stwu r0, 4(r8) 95 + dcbst 0, r8 96 + sync 97 + icbi 0, r8 98 + bdnz 9b 99 + 100 + addi r9, r9, 4 101 + addi r8, r8, 4 102 + b 0b 103 + 104 + 3: 105 + 106 + /* To be certain of avoiding problems with self-modifying code 107 + * execute a serializing instruction here. 108 + */ 109 + isync 110 + sync 111 + 112 + /* jump to the entry point, usually the setup routine */ 113 + mtlr r5 114 + blrl 115 + 116 + 1: b 1b 117 + 118 + relocate_new_kernel_end: 119 + 120 + .globl relocate_new_kernel_size 121 + relocate_new_kernel_size: 122 + .long relocate_new_kernel_end - relocate_new_kernel 123 +
+38
include/asm-ppc/kexec.h
··· 1 + #ifndef _PPC_KEXEC_H 2 + #define _PPC_KEXEC_H 3 + 4 + #ifdef CONFIG_KEXEC 5 + 6 + /* 7 + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. 8 + * I.e. Maximum page that is mapped directly into kernel memory, 9 + * and kmap is not required. 10 + * 11 + * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct 12 + * calculation for the amount of memory directly mappable into the 13 + * kernel memory space. 14 + */ 15 + 16 + /* Maximum physical address we can use pages from */ 17 + #define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) 18 + /* Maximum address we can reach in physical address mode */ 19 + #define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) 20 + /* Maximum address we can use for the control code buffer */ 21 + #define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE 22 + 23 + #define KEXEC_CONTROL_CODE_SIZE 4096 24 + 25 + /* The native architecture */ 26 + #define KEXEC_ARCH KEXEC_ARCH_PPC 27 + 28 + #ifndef __ASSEMBLY__ 29 + 30 + struct kimage; 31 + 32 + extern void machine_kexec_simple(struct kimage *image); 33 + 34 + #endif /* __ASSEMBLY__ */ 35 + 36 + #endif /* CONFIG_KEXEC */ 37 + 38 + #endif /* _PPC_KEXEC_H */
+31
include/asm-ppc/machdep.h
··· 4 4 5 5 #include <linux/config.h> 6 6 #include <linux/init.h> 7 + #include <linux/kexec.h> 7 8 8 9 #include <asm/setup.h> 9 10 #include <asm/page.h> ··· 115 114 /* functions for dealing with other cpus */ 116 115 struct smp_ops_t *smp_ops; 117 116 #endif /* CONFIG_SMP */ 117 + 118 + #ifdef CONFIG_KEXEC 119 + /* Called to shutdown machine specific hardware not already controlled 120 + * by other drivers. 121 + * XXX Should we move this one out of kexec scope? 122 + */ 123 + void (*machine_shutdown)(void); 124 + 125 + /* Called to do the minimal shutdown needed to run a kexec'd kernel 126 + * to run successfully. 127 + * XXX Should we move this one out of kexec scope? 128 + */ 129 + void (*machine_crash_shutdown)(void); 130 + 131 + /* Called to do what every setup is needed on image and the 132 + * reboot code buffer. Returns 0 on success. 133 + * Provide your own (maybe dummy) implementation if your platform 134 + * claims to support kexec. 135 + */ 136 + int (*machine_kexec_prepare)(struct kimage *image); 137 + 138 + /* Called to handle any machine specific cleanup on image */ 139 + void (*machine_kexec_cleanup)(struct kimage *image); 140 + 141 + /* Called to perform the _real_ kexec. 142 + * Do NOT allocate memory or fail here. We are past the point of 143 + * no return. 144 + */ 145 + void (*machine_kexec)(struct kimage *image); 146 + #endif /* CONFIG_KEXEC */ 118 147 }; 119 148 120 149 extern struct machdep_calls ppc_md;