linux/arch/sh/kernel/machine_kexec.c
<<
>>
Prefs
   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 * LANDISK/sh4 supported by kogiidena
   7 *
   8 * This source code is licensed under the GNU General Public License,
   9 * Version 2.  See the file COPYING for more details.
  10 */
  11#include <linux/mm.h>
  12#include <linux/kexec.h>
  13#include <linux/delay.h>
  14#include <linux/reboot.h>
  15#include <linux/numa.h>
  16#include <linux/ftrace.h>
  17#include <linux/suspend.h>
  18#include <linux/memblock.h>
  19#include <asm/pgtable.h>
  20#include <asm/pgalloc.h>
  21#include <asm/mmu_context.h>
  22#include <asm/io.h>
  23#include <asm/cacheflush.h>
  24#include <asm/sh_bios.h>
  25#include <asm/reboot.h>
  26
  27typedef void (*relocate_new_kernel_t)(unsigned long indirection_page,
  28                                      unsigned long reboot_code_buffer,
  29                                      unsigned long start_address);
  30
  31extern const unsigned char relocate_new_kernel[];
  32extern const unsigned int relocate_new_kernel_size;
  33extern void *vbr_base;
  34
  35void native_machine_crash_shutdown(struct pt_regs *regs)
  36{
  37        /* Nothing to do for UP, but definitely broken for SMP.. */
  38}
  39
  40/*
  41 * Do what every setup is needed on image and the
  42 * reboot code buffer to allow us to avoid allocations
  43 * later.
  44 */
  45int machine_kexec_prepare(struct kimage *image)
  46{
  47        return 0;
  48}
  49
  50void machine_kexec_cleanup(struct kimage *image)
  51{
  52}
  53
  54static void kexec_info(struct kimage *image)
  55{
  56        int i;
  57        printk("kexec information\n");
  58        for (i = 0; i < image->nr_segments; i++) {
  59                printk("  segment[%d]: 0x%08x - 0x%08x (0x%08x)\n",
  60                       i,
  61                       (unsigned int)image->segment[i].mem,
  62                       (unsigned int)image->segment[i].mem +
  63                                     image->segment[i].memsz,
  64                       (unsigned int)image->segment[i].memsz);
  65        }
  66        printk("  start     : 0x%08x\n\n", (unsigned int)image->start);
  67}
  68
  69/*
  70 * Do not allocate memory (or fail in any way) in machine_kexec().
  71 * We are past the point of no return, committed to rebooting now.
  72 */
  73void machine_kexec(struct kimage *image)
  74{
  75        unsigned long page_list;
  76        unsigned long reboot_code_buffer;
  77        relocate_new_kernel_t rnk;
  78        unsigned long entry;
  79        unsigned long *ptr;
  80        int save_ftrace_enabled;
  81
  82        /*
  83         * Nicked from the mips version of machine_kexec():
  84         * The generic kexec code builds a page list with physical
  85         * addresses. Use phys_to_virt() to convert them to virtual.
  86         */
  87        for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
  88             ptr = (entry & IND_INDIRECTION) ?
  89               phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
  90                if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
  91                    *ptr & IND_DESTINATION)
  92                        *ptr = (unsigned long) phys_to_virt(*ptr);
  93        }
  94
  95#ifdef CONFIG_KEXEC_JUMP
  96        if (image->preserve_context)
  97                save_processor_state();
  98#endif
  99
 100        save_ftrace_enabled = __ftrace_enabled_save();
 101
 102        /* Interrupts aren't acceptable while we reboot */
 103        local_irq_disable();
 104
 105        page_list = image->head;
 106
 107        /* we need both effective and real address here */
 108        reboot_code_buffer =
 109                        (unsigned long)page_address(image->control_code_page);
 110
 111        /* copy our kernel relocation code to the control code page */
 112        memcpy((void *)reboot_code_buffer, relocate_new_kernel,
 113                                                relocate_new_kernel_size);
 114
 115        kexec_info(image);
 116        flush_cache_all();
 117
 118        sh_bios_vbr_reload();
 119
 120        /* now call it */
 121        rnk = (relocate_new_kernel_t) reboot_code_buffer;
 122        (*rnk)(page_list, reboot_code_buffer,
 123               (unsigned long)phys_to_virt(image->start));
 124
 125#ifdef CONFIG_KEXEC_JUMP
 126        asm volatile("ldc %0, vbr" : : "r" (&vbr_base) : "memory");
 127
 128        if (image->preserve_context)
 129                restore_processor_state();
 130
 131        /* Convert page list back to physical addresses, what a mess. */
 132        for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
 133             ptr = (*ptr & IND_INDIRECTION) ?
 134               phys_to_virt(*ptr & PAGE_MASK) : ptr + 1) {
 135                if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
 136                    *ptr & IND_DESTINATION)
 137                        *ptr = virt_to_phys(*ptr);
 138        }
 139#endif
 140
 141        __ftrace_enabled_restore(save_ftrace_enabled);
 142}
 143
 144void arch_crash_save_vmcoreinfo(void)
 145{
 146#ifdef CONFIG_NUMA
 147        VMCOREINFO_SYMBOL(node_data);
 148        VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
 149#endif
 150#ifdef CONFIG_X2TLB
 151        VMCOREINFO_CONFIG(X2TLB);
 152#endif
 153}
 154
 155void __init reserve_crashkernel(void)
 156{
 157        unsigned long long crash_size, crash_base;
 158        int ret;
 159
 160        ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
 161                        &crash_size, &crash_base);
 162        if (ret == 0 && crash_size > 0) {
 163                crashk_res.start = crash_base;
 164                crashk_res.end = crash_base + crash_size - 1;
 165        }
 166
 167        if (crashk_res.end == crashk_res.start)
 168                goto disable;
 169
 170        crash_size = PAGE_ALIGN(resource_size(&crashk_res));
 171        if (!crashk_res.start) {
 172                unsigned long max = memblock_end_of_DRAM() - memory_limit;
 173                crashk_res.start = __memblock_alloc_base(crash_size, PAGE_SIZE, max);
 174                if (!crashk_res.start) {
 175                        pr_err("crashkernel allocation failed\n");
 176                        goto disable;
 177                }
 178        } else {
 179                ret = memblock_reserve(crashk_res.start, crash_size);
 180                if (unlikely(ret < 0)) {
 181                        pr_err("crashkernel reservation failed - "
 182                               "memory is in use\n");
 183                        goto disable;
 184                }
 185        }
 186
 187        crashk_res.end = crashk_res.start + crash_size - 1;
 188
 189        /*
 190         * Crash kernel trumps memory limit
 191         */
 192        if ((memblock_end_of_DRAM() - memory_limit) <= crashk_res.end) {
 193                memory_limit = 0;
 194                pr_info("Disabled memory limit for crashkernel\n");
 195        }
 196
 197        pr_info("Reserving %ldMB of memory at 0x%08lx "
 198                "for crashkernel (System RAM: %ldMB)\n",
 199                (unsigned long)(crash_size >> 20),
 200                (unsigned long)(crashk_res.start),
 201                (unsigned long)(memblock_phys_mem_size() >> 20));
 202
 203        return;
 204
 205disable:
 206        crashk_res.start = crashk_res.end = 0;
 207}
 208