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>
2016-05-31 09:14:00 +02:00
# include <asm/cacheflush.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
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 :
2016-05-23 16:24:22 -07:00
if ( kexec_crash_image )
arch_kexec_unprotect_crashkres ( ) ;
2013-04-04 19:49:53 +02:00
break ;
case PM_POST_SUSPEND :
case PM_POST_HIBERNATION :
2016-05-23 16:24:22 -07:00
if ( kexec_crash_image )
arch_kexec_protect_crashkres ( ) ;
2013-04-04 19:49:53 +02:00
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
/*
2015-10-29 10:28:26 +01:00
* Reset the system , copy boot CPU registers to absolute zero ,
* and jump to the kdump image
2011-10-30 15:16:40 +01:00
*/
static void __do_machine_kdump ( void * image )
{
2015-10-29 10:28:26 +01:00
int ( * start_kdump ) ( int ) ;
unsigned long prefix ;
/* store_status() saved the prefix register to lowcore */
prefix = ( unsigned long ) S390_lowcore . prefixreg_save_area ;
/* Now do the reset */
s390_reset_system ( ) ;
/*
* Copy dump CPU store status info to absolute zero .
* This need to be done * after * s390_reset_system set the
* prefix register of this CPU to zero
*/
memcpy ( ( void * ) __LC_FPREGS_SAVE_AREA ,
( void * ) ( prefix + __LC_FPREGS_SAVE_AREA ) , 512 ) ;
2011-10-30 15:16:40 +01:00
2012-05-21 11:30:30 +02:00
__load_psw_mask ( PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA ) ;
2015-10-29 10:28:26 +01:00
start_kdump = ( void * ) ( ( struct kimage * ) image ) - > start ;
2011-10-30 15:16:40 +01:00
start_kdump ( 1 ) ;
2015-10-29 10:28:26 +01:00
/* Die if start_kdump returns */
disabled_wait ( ( unsigned long ) __builtin_return_address ( 0 ) ) ;
}
/*
* Start kdump : create a LGR log entry , store status of all CPUs and
* branch to __do_machine_kdump .
*/
static noinline void __machine_kdump ( void * image )
{
int this_cpu , cpu ;
lgr_info_log ( ) ;
/* Get status of the other CPUs */
this_cpu = smp_find_processor_id ( stap ( ) ) ;
for_each_online_cpu ( cpu ) {
if ( cpu = = this_cpu )
continue ;
if ( smp_store_status ( cpu ) )
continue ;
}
/* Store status of the boot CPU */
if ( MACHINE_HAS_VX )
save_vx_regs ( ( void * ) & S390_lowcore . vector_save_area ) ;
/*
* To create a good backchain for this CPU in the dump store_status
* is passed the address of a function . The address is saved into
* the PSW save area of the boot CPU and the function is invoked as
* a tail call of store_status . The backchain in the dump will look
* like this :
* restart_int_handler - > __machine_kexec - > __do_machine_kdump
* The call to store_status ( ) will not return .
*/
store_status ( __do_machine_kdump , image ) ;
2011-10-30 15:16:40 +01:00
}
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
}
2016-05-23 16:24:22 -07:00
# ifdef CONFIG_CRASH_DUMP
2016-05-31 09:13:59 +02:00
void crash_free_reserved_phys_range ( unsigned long begin , unsigned long end )
{
unsigned long addr , size ;
for ( addr = begin ; addr < end ; addr + = PAGE_SIZE )
free_reserved_page ( pfn_to_page ( addr > > PAGE_SHIFT ) ) ;
size = begin - crashk_res . start ;
if ( size )
os_info_crashkernel_add ( crashk_res . start , size ) ;
else
os_info_crashkernel_add ( 0 , 0 ) ;
}
2016-05-31 09:14:00 +02:00
static void crash_protect_pages ( int protect )
2011-10-30 15:16:44 +01:00
{
2016-05-31 09:14:00 +02:00
unsigned long size ;
2011-10-30 15:16:44 +01:00
2016-05-31 09:14:00 +02:00
if ( ! crashk_res . end )
return ;
size = resource_size ( & crashk_res ) ;
if ( protect )
set_memory_ro ( crashk_res . start , size > > PAGE_SHIFT ) ;
2016-05-31 09:13:59 +02:00
else
2016-05-31 09:14:00 +02:00
set_memory_rw ( crashk_res . start , size > > PAGE_SHIFT ) ;
2011-10-30 15:16:44 +01:00
}
2016-05-23 16:24:22 -07:00
void arch_kexec_protect_crashkres ( void )
2011-10-30 15:16:44 +01:00
{
2016-05-31 09:14:00 +02:00
crash_protect_pages ( 1 ) ;
2011-10-30 15:16:44 +01:00
}
2016-05-23 16:24:22 -07:00
void arch_kexec_unprotect_crashkres ( void )
2011-10-30 15:16:44 +01:00
{
2016-05-31 09:14:00 +02:00
crash_protect_pages ( 0 ) ;
2011-10-30 15:16:44 +01:00
}
2016-05-23 16:24:22 -07:00
# endif
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
2015-10-29 10:28:26 +01:00
s390_reset_system ( ) ;
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 ) ;
2015-10-29 10:28:26 +01:00
/* Die if kexec returns */
disabled_wait ( ( unsigned long ) __builtin_return_address ( 0 ) ) ;
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
2015-10-29 10:28:26 +01:00
if ( ( ( struct kimage * ) data ) - > type = = KEXEC_TYPE_CRASH )
__machine_kdump ( data ) ;
2015-01-14 17:52:10 +01:00
# endif
2015-10-29 10:28:26 +01:00
__do_machine_kexec ( data ) ;
2011-10-30 15:16:40 +01:00
}
/*
* 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
}