X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc%2Fkernel%2Fmachine_kexec.c;h=84d65a87191ed6048a81eee508e43d1629055f9b;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=9daefb31650d7dbb9b6b5d582a33ecdb297576df;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c index 9daefb316..84d65a871 100644 --- a/arch/ppc/kernel/machine_kexec.c +++ b/arch/ppc/kernel/machine_kexec.c @@ -2,7 +2,7 @@ * machine_kexec.c - handle transition of Linux booting another kernel * Copyright (C) 2002-2003 Eric Biederman * - * GAMECUBE/PPC32 port Copyright (C) 2004 Albert Herranz + * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. @@ -11,66 +11,33 @@ #include #include #include +#include #include #include #include #include #include #include +#include -typedef void (*relocate_new_kernel_t)( - unsigned long indirection_page, unsigned long reboot_code_buffer, - unsigned long start_address); +typedef NORET_TYPE void (*relocate_new_kernel_t)( + unsigned long indirection_page, + unsigned long reboot_code_buffer, + unsigned long start_address) ATTRIB_NORET; const extern unsigned char relocate_new_kernel[]; const extern unsigned int relocate_new_kernel_size; -extern void use_mm(struct mm_struct *mm); -static int identity_map_pages(struct page *pages, int order) +void machine_shutdown(void) { - struct mm_struct *mm; - struct vm_area_struct *vma; - int error; - - mm = &init_mm; - vma = NULL; - - down_write(&mm->mmap_sem); - error = -ENOMEM; - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!vma) { - goto out; - } - - memset(vma, 0, sizeof(*vma)); - vma->vm_mm = mm; - vma->vm_start = page_to_pfn(pages) << PAGE_SHIFT; - vma->vm_end = vma->vm_start + (1 << (order + PAGE_SHIFT)); - vma->vm_ops = NULL; - vma->vm_flags = VM_SHARED \ - | VM_READ | VM_WRITE | VM_EXEC \ - | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC \ - | VM_DONTCOPY | VM_RESERVED; - vma->vm_page_prot = protection_map[vma->vm_flags & 0xf]; - vma->vm_file = NULL; - vma->vm_private_data = NULL; - insert_vm_struct(mm, vma); - - error = remap_page_range(vma, vma->vm_start, vma->vm_start, - vma->vm_end - vma->vm_start, vma->vm_page_prot); - if (error) { - goto out; - } - - error = 0; - out: - if (error && vma) { - kmem_cache_free(vm_area_cachep, vma); - vma = NULL; - } - up_write(&mm->mmap_sem); + if (ppc_md.machine_shutdown) + ppc_md.machine_shutdown(); +} - return error; +void machine_crash_shutdown(struct pt_regs *regs) +{ + if (ppc_md.machine_crash_shutdown) + ppc_md.machine_crash_shutdown(); } /* @@ -80,53 +47,72 @@ static int identity_map_pages(struct page *pages, int order) */ int machine_kexec_prepare(struct kimage *image) { - unsigned int order; - order = get_order(KEXEC_CONTROL_CODE_SIZE); - return identity_map_pages(image->control_code_page, order); + if (ppc_md.machine_kexec_prepare) + return ppc_md.machine_kexec_prepare(image); + /* + * Fail if platform doesn't provide its own machine_kexec_prepare + * implementation. + */ + return -ENOSYS; } void machine_kexec_cleanup(struct kimage *image) { - unsigned int order; - order = get_order(KEXEC_CONTROL_CODE_SIZE); - do_munmap(&init_mm, - page_to_pfn(image->control_code_page) << PAGE_SHIFT, - 1 << (order + PAGE_SHIFT)); + if (ppc_md.machine_kexec_cleanup) + ppc_md.machine_kexec_cleanup(image); } -void machine_shutdown(void) +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +NORET_TYPE void machine_kexec(struct kimage *image) { + if (ppc_md.machine_kexec) + ppc_md.machine_kexec(image); + else { + /* + * Fall back to normal restart if platform doesn't provide + * its own kexec function, and user insist to kexec... + */ + machine_restart(NULL); + } + for(;;); } /* - * Do not allocate memory (or fail in any way) in machine_kexec(). - * We are past the point of no return, committed to rebooting now. + * This is a generic machine_kexec function suitable at least for + * non-OpenFirmware embedded platforms. + * It merely copies the image relocation code to the control page and + * jumps to it. + * A platform specific function may just call this one. */ -void machine_kexec(struct kimage *image) +void machine_kexec_simple(struct kimage *image) { - unsigned long indirection_page; - unsigned long reboot_code_buffer; + unsigned long page_list; + unsigned long reboot_code_buffer, reboot_code_buffer_phys; relocate_new_kernel_t rnk; - /* switch to an mm where the reboot_code_buffer is identity mapped */ - use_mm(&init_mm); - /* Interrupts aren't acceptable while we reboot */ local_irq_disable(); - reboot_code_buffer = page_to_pfn(image->control_code_page) <head & PAGE_MASK; + page_list = image->head; + + /* we need both effective and real address here */ + reboot_code_buffer = + (unsigned long)page_address(image->control_code_page); + reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer); - /* copy it out */ - memcpy((void *)reboot_code_buffer, - relocate_new_kernel, relocate_new_kernel_size); + /* copy our kernel relocation code to the control code page */ + memcpy((void *)reboot_code_buffer, relocate_new_kernel, + relocate_new_kernel_size); flush_icache_range(reboot_code_buffer, - reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); + reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); printk(KERN_INFO "Bye!\n"); /* now call it */ rnk = (relocate_new_kernel_t) reboot_code_buffer; - (*rnk)(indirection_page, reboot_code_buffer, image->start); + (*rnk)(page_list, reboot_code_buffer_phys, image->start); }