linux/arch/mips/kernel/machine_kexec.c
<<
>>
Prefs
   1/*
   2 * machine_kexec.c for kexec
   3 * Created by <nschichan@corp.free.fr> on Thu Oct 12 15:15:06 2006
   4 *
   5 * This source code is licensed under the GNU General Public License,
   6 * Version 2.  See the file COPYING for more details.
   7 */
   8#include <linux/compiler.h>
   9#include <linux/kexec.h>
  10#include <linux/mm.h>
  11#include <linux/delay.h>
  12
  13#include <asm/cacheflush.h>
  14#include <asm/page.h>
  15
  16extern const unsigned char relocate_new_kernel[];
  17extern const size_t relocate_new_kernel_size;
  18
  19extern unsigned long kexec_start_address;
  20extern unsigned long kexec_indirection_page;
  21
  22int (*_machine_kexec_prepare)(struct kimage *) = NULL;
  23void (*_machine_kexec_shutdown)(void) = NULL;
  24void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
  25#ifdef CONFIG_SMP
  26void (*relocated_kexec_smp_wait) (void *);
  27atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
  28#endif
  29
  30int
  31machine_kexec_prepare(struct kimage *kimage)
  32{
  33        if (_machine_kexec_prepare)
  34                return _machine_kexec_prepare(kimage);
  35        return 0;
  36}
  37
  38void
  39machine_kexec_cleanup(struct kimage *kimage)
  40{
  41}
  42
  43void
  44machine_shutdown(void)
  45{
  46        if (_machine_kexec_shutdown)
  47                _machine_kexec_shutdown();
  48}
  49
  50void
  51machine_crash_shutdown(struct pt_regs *regs)
  52{
  53        if (_machine_crash_shutdown)
  54                _machine_crash_shutdown(regs);
  55        else
  56                default_machine_crash_shutdown(regs);
  57}
  58
  59typedef void (*noretfun_t)(void) __noreturn;
  60
  61void
  62machine_kexec(struct kimage *image)
  63{
  64        unsigned long reboot_code_buffer;
  65        unsigned long entry;
  66        unsigned long *ptr;
  67
  68        reboot_code_buffer =
  69          (unsigned long)page_address(image->control_code_page);
  70
  71        kexec_start_address =
  72                (unsigned long) phys_to_virt(image->start);
  73
  74        kexec_indirection_page =
  75                (unsigned long) phys_to_virt(image->head & PAGE_MASK);
  76
  77        memcpy((void*)reboot_code_buffer, relocate_new_kernel,
  78               relocate_new_kernel_size);
  79
  80        /*
  81         * The generic kexec code builds a page list with physical
  82         * addresses. they are directly accessible through KSEG0 (or
  83         * CKSEG0 or XPHYS if on 64bit system), hence the
  84         * phys_to_virt() call.
  85         */
  86        for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE);
  87             ptr = (entry & IND_INDIRECTION) ?
  88               phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
  89                if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
  90                    *ptr & IND_DESTINATION)
  91                        *ptr = (unsigned long) phys_to_virt(*ptr);
  92        }
  93
  94        /*
  95         * we do not want to be bothered.
  96         */
  97        local_irq_disable();
  98
  99        printk("Will call new kernel at %08lx\n", image->start);
 100        printk("Bye ...\n");
 101        __flush_cache_all();
 102#ifdef CONFIG_SMP
 103        /* All secondary cpus now may jump to kexec_wait cycle */
 104        relocated_kexec_smp_wait = reboot_code_buffer +
 105                (void *)(kexec_smp_wait - relocate_new_kernel);
 106        smp_wmb();
 107        atomic_set(&kexec_ready_to_reboot, 1);
 108#endif
 109        ((noretfun_t) reboot_code_buffer)();
 110}
 111