2005-06-25 14:58:11 -07:00
/*
2012-07-20 11:15:04 +02:00
* Copyright IBM Corp . 2005 , 2011
2005-06-25 14:58:11 -07:00
*
2006-12-04 15:40:33 +01:00
* Author ( s ) : Rolf Adelsberger ,
* Heiko Carstens < heiko . carstens @ de . ibm . com >
2011-10-30 15:16:40 +01:00
* Michael Holzheu < holzheu @ linux . vnet . ibm . com >
2005-06-25 14:58:11 -07:00
*/
# include <linux/device.h>
# include <linux/mm.h>
# include <linux/kexec.h>
# include <linux/delay.h>
2007-02-05 21:16:47 +01:00
# include <linux/reboot.h>
2011-03-15 17:08:33 +01:00
# include <linux/ftrace.h>
2012-03-11 11:59:32 -04:00
# include <linux/debug_locks.h>
2013-04-04 19:49:53 +02:00
# include <linux/suspend.h>
2006-02-11 17:56:01 -08:00
# include <asm/cio.h>
# include <asm/setup.h>
2005-06-25 14:58:11 -07:00
# include <asm/pgtable.h>
# include <asm/pgalloc.h>
2006-02-11 17:56:01 -08:00
# include <asm/smp.h>
2006-12-04 15:40:26 +01:00
# include <asm/reset.h>
2007-03-05 23:35:45 +01:00
# include <asm/ipl.h>
2011-10-30 15:16:40 +01:00
# include <asm/diag.h>
2012-09-14 14:11:32 +02:00
# include <asm/elf.h>
2011-10-30 15:16:40 +01:00
# include <asm/asm-offsets.h>
2012-05-18 15:10:05 +02:00
# include <asm/os_info.h>
2014-10-06 17:57:43 +02:00
# include <asm/switch_to.h>
2005-06-25 14:58:11 -07:00
2006-12-04 15:40:33 +01:00
typedef void ( * relocate_kernel_t ) ( kimage_entry_t * , unsigned long ) ;
2005-06-25 14:58:11 -07:00
2006-06-26 18:57:34 +02:00
extern const unsigned char relocate_kernel [ ] ;
extern const unsigned long long relocate_kernel_len ;
2005-06-25 14:58:11 -07:00
2011-10-30 15:16:40 +01:00
# ifdef CONFIG_CRASH_DUMP
/*
* Create ELF notes for one CPU
*/
static void add_elf_notes ( int cpu )
{
struct save_area * sa = ( void * ) 4608 + store_prefix ( ) ;
void * ptr ;
memcpy ( ( void * ) ( 4608UL + sa - > pref_reg ) , sa , sizeof ( * sa ) ) ;
ptr = ( u64 * ) per_cpu_ptr ( crash_notes , cpu ) ;
2014-10-06 17:57:43 +02:00
ptr = fill_cpu_elf_notes ( ptr , sa , NULL ) ;
2011-10-30 15:16:40 +01:00
memset ( ptr , 0 , sizeof ( struct elf_note ) ) ;
}
/*
* Initialize CPU ELF notes
*/
2013-09-06 19:10:48 +02:00
static void setup_regs ( void )
2011-10-30 15:16:40 +01:00
{
unsigned long sa = S390_lowcore . prefixreg_save_area + SAVE_AREA_BASE ;
2014-10-06 17:57:43 +02:00
struct _lowcore * lc ;
2012-03-11 11:59:26 -04:00
int cpu , this_cpu ;
2011-10-30 15:16:40 +01:00
2014-10-06 17:57:43 +02:00
/* Get lowcore pointer from store status of this CPU (absolute zero) */
lc = ( struct _lowcore * ) ( unsigned long ) S390_lowcore . prefixreg_save_area ;
2012-03-11 11:59:26 -04:00
this_cpu = smp_find_processor_id ( stap ( ) ) ;
add_elf_notes ( this_cpu ) ;
2011-10-30 15:16:40 +01:00
for_each_online_cpu ( cpu ) {
2012-03-11 11:59:26 -04:00
if ( cpu = = this_cpu )
continue ;
if ( smp_store_status ( cpu ) )
2011-10-30 15:16:40 +01:00
continue ;
add_elf_notes ( cpu ) ;
}
2014-10-06 17:57:43 +02:00
if ( MACHINE_HAS_VX )
save_vx_regs_safe ( ( void * ) lc - > vector_save_area_addr ) ;
2011-10-30 15:16:40 +01:00
/* Copy dump CPU store status info to absolute zero */
memcpy ( ( void * ) SAVE_AREA_BASE , ( void * ) sa , sizeof ( struct save_area ) ) ;
}
2013-04-04 19:49:53 +02:00
/*
* PM notifier callback for kdump
*/
static int machine_kdump_pm_cb ( struct notifier_block * nb , unsigned long action ,
void * ptr )
{
switch ( action ) {
case PM_SUSPEND_PREPARE :
case PM_HIBERNATION_PREPARE :
if ( crashk_res . start )
crash_map_reserved_pages ( ) ;
break ;
case PM_POST_SUSPEND :
case PM_POST_HIBERNATION :
if ( crashk_res . start )
crash_unmap_reserved_pages ( ) ;
break ;
default :
return NOTIFY_DONE ;
}
return NOTIFY_OK ;
}
static int __init machine_kdump_pm_init ( void )
{
pm_notifier ( machine_kdump_pm_cb , 0 ) ;
return 0 ;
}
arch_initcall ( machine_kdump_pm_init ) ;
2011-10-30 15:16:40 +01:00
/*
* Start kdump : We expect here that a store status has been done on our CPU
*/
static void __do_machine_kdump ( void * image )
{
int ( * start_kdump ) ( int ) = ( void * ) ( ( struct kimage * ) image ) - > start ;
2012-05-21 11:30:30 +02:00
__load_psw_mask ( PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA ) ;
2011-10-30 15:16:40 +01:00
start_kdump ( 1 ) ;
}
2015-01-14 17:52:10 +01:00
# endif
2011-10-30 15:16:40 +01:00
/*
* Check if kdump checksums are valid : We call purgatory with parameter " 0 "
*/
static int kdump_csum_valid ( struct kimage * image )
{
# ifdef CONFIG_CRASH_DUMP
int ( * start_kdump ) ( int ) = ( void * ) image - > start ;
int rc ;
__arch_local_irq_stnsm ( 0xfb ) ; /* disable DAT */
rc = start_kdump ( 0 ) ;
__arch_local_irq_stosm ( 0x04 ) ; /* enable DAT */
return rc ? 0 : - EINVAL ;
# else
return - EINVAL ;
# endif
}
2011-10-30 15:16:44 +01:00
/*
* Map or unmap crashkernel memory
*/
static void crash_map_pages ( int enable )
{
unsigned long size = resource_size ( & crashk_res ) ;
BUG_ON ( crashk_res . start % KEXEC_CRASH_MEM_ALIGN | |
size % KEXEC_CRASH_MEM_ALIGN ) ;
if ( enable )
vmem_add_mapping ( crashk_res . start , size ) ;
2012-05-18 15:10:05 +02:00
else {
2011-10-30 15:16:44 +01:00
vmem_remove_mapping ( crashk_res . start , size ) ;
2012-05-18 15:10:05 +02:00
if ( size )
os_info_crashkernel_add ( crashk_res . start , size ) ;
else
os_info_crashkernel_add ( 0 , 0 ) ;
}
2011-10-30 15:16:44 +01:00
}
/*
* Map crashkernel memory
*/
void crash_map_reserved_pages ( void )
{
crash_map_pages ( 1 ) ;
}
/*
* Unmap crashkernel memory
*/
void crash_unmap_reserved_pages ( void )
{
crash_map_pages ( 0 ) ;
}
2011-10-30 15:16:40 +01:00
/*
* Give back memory to hypervisor before new kdump is loaded
*/
static int machine_kexec_prepare_kdump ( void )
{
# ifdef CONFIG_CRASH_DUMP
if ( MACHINE_IS_VM )
diag10_range ( PFN_DOWN ( crashk_res . start ) ,
PFN_DOWN ( crashk_res . end - crashk_res . start + 1 ) ) ;
return 0 ;
# else
return - EINVAL ;
# endif
}
2006-12-04 15:40:33 +01:00
int machine_kexec_prepare ( struct kimage * image )
2005-06-25 14:58:11 -07:00
{
2006-12-04 15:40:33 +01:00
void * reboot_code_buffer ;
2005-06-25 14:58:11 -07:00
2007-03-05 23:35:45 +01:00
/* Can't replace kernel image since it is read-only. */
if ( ipl_flags & IPL_NSS_VALID )
2012-09-06 15:19:08 +02:00
return - EOPNOTSUPP ;
2007-03-05 23:35:45 +01:00
2011-10-30 15:16:40 +01:00
if ( image - > type = = KEXEC_TYPE_CRASH )
return machine_kexec_prepare_kdump ( ) ;
2005-06-25 14:58:11 -07:00
/* We don't support anything but the default image type for now. */
if ( image - > type ! = KEXEC_TYPE_DEFAULT )
return - EINVAL ;
/* Get the destination where the assembler code should be copied to.*/
2006-12-04 15:40:33 +01:00
reboot_code_buffer = ( void * ) page_to_phys ( image - > control_code_page ) ;
2005-06-25 14:58:11 -07:00
/* Then copy it */
2006-12-04 15:40:33 +01:00
memcpy ( reboot_code_buffer , relocate_kernel , relocate_kernel_len ) ;
2005-06-25 14:58:11 -07:00
return 0 ;
}
2006-12-04 15:40:33 +01:00
void machine_kexec_cleanup ( struct kimage * image )
2005-06-25 14:58:11 -07:00
{
}
2011-10-30 15:16:40 +01:00
void arch_crash_save_vmcoreinfo ( void )
{
VMCOREINFO_SYMBOL ( lowcore_ptr ) ;
2011-12-27 11:27:24 +01:00
VMCOREINFO_SYMBOL ( high_memory ) ;
2011-10-30 15:16:40 +01:00
VMCOREINFO_LENGTH ( lowcore_ptr , NR_CPUS ) ;
}
2006-12-04 15:40:33 +01:00
void machine_shutdown ( void )
2005-06-25 14:58:11 -07:00
{
}
2012-08-27 15:50:29 +02:00
void machine_crash_shutdown ( struct pt_regs * regs )
{
}
2011-10-30 15:16:40 +01:00
/*
* Do normal kexec
*/
static void __do_machine_kexec ( void * data )
2005-06-25 14:58:11 -07:00
{
relocate_kernel_t data_mover ;
2010-02-26 22:37:34 +01:00
struct kimage * image = data ;
2005-06-25 14:58:11 -07:00
2006-12-04 15:40:33 +01:00
data_mover = ( relocate_kernel_t ) page_to_phys ( image - > control_code_page ) ;
2005-06-25 14:58:11 -07:00
/* Call the moving routine */
2006-12-04 15:40:33 +01:00
( * data_mover ) ( & image - > head , image - > start ) ;
2005-06-25 14:58:11 -07:00
}
2010-02-26 22:37:34 +01:00
2011-10-30 15:16:40 +01:00
/*
* Reset system and call either kdump or normal kexec
*/
static void __machine_kexec ( void * data )
{
2012-05-21 11:30:30 +02:00
__arch_local_irq_stosm ( 0x04 ) ; /* enable DAT */
2011-10-30 15:16:40 +01:00
pfault_fini ( ) ;
2012-03-11 11:59:32 -04:00
tracing_off ( ) ;
debug_locks_off ( ) ;
2015-01-14 17:52:10 +01:00
# ifdef CONFIG_CRASH_DUMP
if ( ( ( struct kimage * ) data ) - > type = = KEXEC_TYPE_CRASH ) {
2012-03-11 11:59:32 -04:00
lgr_info_log ( ) ;
2015-01-14 17:52:10 +01:00
s390_reset_system ( setup_regs , __do_machine_kdump , data ) ;
} else
# endif
s390_reset_system ( NULL , __do_machine_kexec , data ) ;
2011-10-30 15:16:40 +01:00
disabled_wait ( ( unsigned long ) __builtin_return_address ( 0 ) ) ;
}
/*
* Do either kdump or normal kexec . In case of kdump we first ask
* purgatory , if kdump checksums are valid .
*/
2010-02-26 22:37:34 +01:00
void machine_kexec ( struct kimage * image )
{
2011-10-30 15:16:40 +01:00
if ( image - > type = = KEXEC_TYPE_CRASH & & ! kdump_csum_valid ( image ) )
return ;
2011-03-15 17:08:33 +01:00
tracer_disable ( ) ;
2010-02-26 22:37:34 +01:00
smp_send_stop ( ) ;
2012-03-11 11:59:26 -04:00
smp_call_ipl_cpu ( __machine_kexec , image ) ;
2010-02-26 22:37:34 +01:00
}