linux/arch/arm/kernel/machine_kexec.c
Richard Purdie 4cd9d6f774 [ARM] 4736/1: Export atags to userspace and allow kexec to use customised atags
Currently, the atags used by kexec are fixed to the ones originally used
to boot the kernel. This is less than ideal as changing the commandline,
initrd and other options would be a useful feature.

This patch exports the atags used for the current kernel to userspace
through an "atags" file in procfs. The presence of the file is
controlled by its own Kconfig option and cleans up several ifdef blocks
into a separate file. The tags for the new kernel are assumed to be at
a fixed location before the kernel image itself. The location of the
tags used to boot the original kernel is unimportant and no longer
saved.

Based on a patch from Uli Luckas <u.luckas@road.de>

Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Acked-by: Uli Luckas <u.luckas@road.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2008-02-04 13:21:03 +00:00

81 lines
2 KiB
C

/*
* machine_kexec.c - handle transition of Linux booting another kernel
*/
#include <linux/mm.h>
#include <linux/kexec.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
#include <asm/cacheflush.h>
#include <asm/mach-types.h>
const extern unsigned char relocate_new_kernel[];
const extern unsigned int relocate_new_kernel_size;
extern void setup_mm_for_reboot(char mode);
extern unsigned long kexec_start_address;
extern unsigned long kexec_indirection_page;
extern unsigned long kexec_mach_type;
extern unsigned long kexec_boot_atags;
/*
* Provide a dummy crash_notes definition while crash dump arrives to arm.
* This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
*/
int machine_kexec_prepare(struct kimage *image)
{
return 0;
}
void machine_kexec_cleanup(struct kimage *image)
{
}
void machine_shutdown(void)
{
}
void machine_crash_shutdown(struct pt_regs *regs)
{
}
void machine_kexec(struct kimage *image)
{
unsigned long page_list;
unsigned long reboot_code_buffer_phys;
void *reboot_code_buffer;
page_list = image->head & PAGE_MASK;
/* we need both effective and real address here */
reboot_code_buffer_phys =
page_to_pfn(image->control_code_page) << PAGE_SHIFT;
reboot_code_buffer = page_address(image->control_code_page);
/* Prepare parameters for reboot_code_buffer*/
kexec_start_address = image->start;
kexec_indirection_page = page_list;
kexec_mach_type = machine_arch_type;
kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
/* copy our kernel relocation code to the control code page */
memcpy(reboot_code_buffer,
relocate_new_kernel, relocate_new_kernel_size);
flush_icache_range((unsigned long) reboot_code_buffer,
(unsigned long) reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
printk(KERN_INFO "Bye!\n");
cpu_proc_fin();
setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
cpu_reset(reboot_code_buffer_phys);
}