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 23typedef NORET_TYPE void (*relocate_new_kernel_t)( 24 unsigned long indirection_page, 25 unsigned long reboot_code_buffer, 26 unsigned long start_address) ATTRIB_NORET; 27 28extern const unsigned char relocate_new_kernel[]; 29extern const unsigned int relocate_new_kernel_size; 30 31void machine_shutdown(void) 32{ 33 if (ppc_md.machine_shutdown) 34 ppc_md.machine_shutdown(); 35} 36 37void machine_crash_shutdown(struct pt_regs *regs) 38{ 39 if (ppc_md.machine_crash_shutdown) 40 ppc_md.machine_crash_shutdown(); 41} 42 43/* 44 * Do what every setup is needed on image and the 45 * reboot code buffer to allow us to avoid allocations 46 * later. 47 */ 48int machine_kexec_prepare(struct kimage *image) 49{ 50 if (ppc_md.machine_kexec_prepare) 51 return ppc_md.machine_kexec_prepare(image); 52 /* 53 * Fail if platform doesn't provide its own machine_kexec_prepare 54 * implementation. 55 */ 56 return -ENOSYS; 57} 58 59void machine_kexec_cleanup(struct kimage *image) 60{ 61 if (ppc_md.machine_kexec_cleanup) 62 ppc_md.machine_kexec_cleanup(image); 63} 64 65/* 66 * Do not allocate memory (or fail in any way) in machine_kexec(). 67 * We are past the point of no return, committed to rebooting now. 68 */ 69NORET_TYPE void machine_kexec(struct kimage *image) 70{ 71 if (ppc_md.machine_kexec) 72 ppc_md.machine_kexec(image); 73 else { 74 /* 75 * Fall back to normal restart if platform doesn't provide 76 * its own kexec function, and user insist to kexec... 77 */ 78 machine_restart(NULL); 79 } 80 for(;;); 81} 82 83/* 84 * This is a generic machine_kexec function suitable at least for 85 * non-OpenFirmware embedded platforms. 86 * It merely copies the image relocation code to the control page and 87 * jumps to it. 88 * A platform specific function may just call this one. 89 */ 90void machine_kexec_simple(struct kimage *image) 91{ 92 unsigned long page_list; 93 unsigned long reboot_code_buffer, reboot_code_buffer_phys; 94 relocate_new_kernel_t rnk; 95 96 /* Interrupts aren't acceptable while we reboot */ 97 local_irq_disable(); 98 99 page_list = image->head; 100 101 /* we need both effective and real address here */ 102 reboot_code_buffer = 103 (unsigned long)page_address(image->control_code_page); 104 reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer); 105 106 /* copy our kernel relocation code to the control code page */ 107 memcpy((void *)reboot_code_buffer, relocate_new_kernel, 108 relocate_new_kernel_size); 109 110 flush_icache_range(reboot_code_buffer, 111 reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); 112 printk(KERN_INFO "Bye!\n"); 113 114 /* now call it */ 115 rnk = (relocate_new_kernel_t) reboot_code_buffer; 116 (*rnk)(page_list, reboot_code_buffer_phys, image->start); 117} 118