machine_kexec.c 2.83 KB
Newer Older
kogiidena's avatar
kogiidena committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * machine_kexec.c - handle transition of Linux booting another kernel
 * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
 *
 * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
 * LANDISK/sh4 supported by kogiidena
 *
 * This source code is licensed under the GNU General Public License,
 * Version 2.  See the file COPYING for more details.
 */

#include <linux/mm.h>
#include <linux/kexec.h>
#include <linux/delay.h>
#include <linux/reboot.h>
16
#include <linux/numa.h>
kogiidena's avatar
kogiidena committed
17 18 19 20 21 22 23 24 25 26 27 28
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
#include <asm/cacheflush.h>

typedef NORET_TYPE void (*relocate_new_kernel_t)(
				unsigned long indirection_page,
				unsigned long reboot_code_buffer,
				unsigned long start_address,
				unsigned long vbr_reg) ATTRIB_NORET;

29 30
extern const unsigned char relocate_new_kernel[];
extern const unsigned int relocate_new_kernel_size;
kogiidena's avatar
kogiidena committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
extern void *gdb_vbr_vector;

void machine_shutdown(void)
{
}

void machine_crash_shutdown(struct pt_regs *regs)
{
}

/*
 * Do what every setup is needed on image and the
 * reboot code buffer to allow us to avoid allocations
 * later.
 */
int machine_kexec_prepare(struct kimage *image)
{
	return 0;
}

void machine_kexec_cleanup(struct kimage *image)
{
}

static void kexec_info(struct kimage *image)
{
        int i;
	printk("kexec information\n");
	for (i = 0; i < image->nr_segments; i++) {
	        printk("  segment[%d]: 0x%08x - 0x%08x (0x%08x)\n",
		       i,
		       (unsigned int)image->segment[i].mem,
Paul Mundt's avatar
Paul Mundt committed
63 64
		       (unsigned int)image->segment[i].mem +
				     image->segment[i].memsz,
kogiidena's avatar
kogiidena committed
65
		       (unsigned int)image->segment[i].memsz);
Paul Mundt's avatar
Paul Mundt committed
66
	}
kogiidena's avatar
kogiidena committed
67 68 69 70 71 72 73
	printk("  start     : 0x%08x\n\n", (unsigned int)image->start);
}

/*
 * Do not allocate memory (or fail in any way) in machine_kexec().
 * We are past the point of no return, committed to rebooting now.
 */
Huang Ying's avatar
Huang Ying committed
74
void machine_kexec(struct kimage *image)
kogiidena's avatar
kogiidena committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
{

	unsigned long page_list;
	unsigned long reboot_code_buffer;
	unsigned long vbr_reg;
	relocate_new_kernel_t rnk;

#if defined(CONFIG_SH_STANDARD_BIOS)
	vbr_reg = ((unsigned long )gdb_vbr_vector) - 0x100;
#else
	vbr_reg = 0x80000000;  // dummy
#endif
	/* Interrupts aren't acceptable while we reboot */
	local_irq_disable();

	page_list = image->head;

	/* we need both effective and real address here */
	reboot_code_buffer =
			(unsigned long)page_address(image->control_code_page);

	/* copy our kernel relocation code to the control code page */
	memcpy((void *)reboot_code_buffer, relocate_new_kernel,
						relocate_new_kernel_size);

        kexec_info(image);
	flush_cache_all();

	/* now call it */
	rnk = (relocate_new_kernel_t) reboot_code_buffer;
105
	(*rnk)(page_list, reboot_code_buffer, P2SEGADDR(image->start), vbr_reg);
kogiidena's avatar
kogiidena committed
106 107
}

108 109 110 111 112 113 114
void arch_crash_save_vmcoreinfo(void)
{
#ifdef CONFIG_NUMA
	VMCOREINFO_SYMBOL(node_data);
	VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
#endif
}