2007-02-06 21:29:00 +01:00
/*
* 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>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2007-02-06 21:29:00 +01:00
# include <asm/pgtable.h>
# include <asm/pgalloc.h>
# include <asm/mmu_context.h>
# include <asm/cacheflush.h>
# include <asm/mach-types.h>
2009-02-09 21:35:39 +01:00
extern const unsigned char relocate_new_kernel [ ] ;
extern const unsigned int relocate_new_kernel_size ;
2007-02-06 21:29:00 +01:00
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 ;
2008-01-02 00:56:46 +01:00
extern unsigned long kexec_boot_atags ;
2007-02-06 21:29:00 +01:00
/*
* 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 ;
2008-01-02 00:56:46 +01:00
kexec_boot_atags = image - > start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET ;
2007-02-06 21:29:00 +01:00
/* 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 ,
2008-08-15 00:40:22 -07:00
( unsigned long ) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE ) ;
2007-02-06 21:29:00 +01:00
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 ) ;
}