2005-06-26 01:58:11 +04:00
/*
2012-07-20 13:15:04 +04:00
* Copyright IBM Corp . 2005 , 2011
2005-06-26 01:58:11 +04:00
*
2006-12-04 17:40:33 +03:00
* Author ( s ) : Rolf Adelsberger ,
* Heiko Carstens < heiko . carstens @ de . ibm . com >
2011-10-30 18:16:40 +04:00
* Michael Holzheu < holzheu @ linux . vnet . ibm . com >
2005-06-26 01:58:11 +04:00
*/
# include <linux/device.h>
# include <linux/mm.h>
# include <linux/kexec.h>
# include <linux/delay.h>
2007-02-05 23:16:47 +03:00
# include <linux/reboot.h>
2011-03-15 19:08:33 +03:00
# include <linux/ftrace.h>
2012-03-11 19:59:32 +04:00
# include <linux/debug_locks.h>
2013-04-04 21:49:53 +04:00
# include <linux/suspend.h>
2006-02-12 04:56:01 +03:00
# include <asm/cio.h>
# include <asm/setup.h>
2005-06-26 01:58:11 +04:00
# include <asm/pgtable.h>
# include <asm/pgalloc.h>
2006-02-12 04:56:01 +03:00
# include <asm/smp.h>
2006-12-04 17:40:26 +03:00
# include <asm/reset.h>
2007-03-06 01:35:45 +03:00
# include <asm/ipl.h>
2011-10-30 18:16:40 +04:00
# include <asm/diag.h>
2012-09-14 16:11:32 +04:00
# include <asm/elf.h>
2011-10-30 18:16:40 +04:00
# include <asm/asm-offsets.h>
2016-05-31 10:14:00 +03:00
# include <asm/cacheflush.h>
2012-05-18 17:10:05 +04:00
# include <asm/os_info.h>
2017-05-09 01:58:08 +03:00
# include <asm/set_memory.h>
2014-10-06 19:57:43 +04:00
# include <asm/switch_to.h>
2016-01-26 16:10:34 +03:00
# include <asm/nmi.h>
2005-06-26 01:58:11 +04:00
2006-12-04 17:40:33 +03:00
typedef void ( * relocate_kernel_t ) ( kimage_entry_t * , unsigned long ) ;
2005-06-26 01:58:11 +04:00
2006-06-26 20:57:34 +04:00
extern const unsigned char relocate_kernel [ ] ;
extern const unsigned long long relocate_kernel_len ;
2005-06-26 01:58:11 +04:00
2011-10-30 18:16:40 +04:00
# ifdef CONFIG_CRASH_DUMP
2013-04-04 21:49:53 +04: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-24 02:24:22 +03:00
if ( kexec_crash_image )
arch_kexec_unprotect_crashkres ( ) ;
2013-04-04 21:49:53 +04:00
break ;
case PM_POST_SUSPEND :
case PM_POST_HIBERNATION :
2016-05-24 02:24:22 +03:00
if ( kexec_crash_image )
arch_kexec_protect_crashkres ( ) ;
2013-04-04 21:49:53 +04: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 18:16:40 +04:00
/*
2015-10-29 12:28:26 +03:00
* Reset the system , copy boot CPU registers to absolute zero ,
* and jump to the kdump image
2011-10-30 18:16:40 +04:00
*/
static void __do_machine_kdump ( void * image )
{
2015-10-29 12:28:26 +03: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 18:16:40 +04:00
2012-05-21 13:30:30 +04:00
__load_psw_mask ( PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA ) ;
2015-10-29 12:28:26 +03:00
start_kdump = ( void * ) ( ( struct kimage * ) image ) - > start ;
2011-10-30 18:16:40 +04:00
start_kdump ( 1 ) ;
2015-10-29 12:28:26 +03: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 )
{
2016-01-26 16:10:34 +03:00
struct mcesa * mcesa ;
unsigned long cr2_old , cr2_new ;
2015-10-29 12:28:26 +03:00
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 */
2016-01-26 16:10:34 +03:00
mcesa = ( struct mcesa * ) ( S390_lowcore . mcesad & MCESA_ORIGIN_MASK ) ;
2015-10-29 12:28:26 +03:00
if ( MACHINE_HAS_VX )
2016-01-26 16:10:34 +03:00
save_vx_regs ( ( __vector128 * ) mcesa - > vector_save_area ) ;
if ( MACHINE_HAS_GS ) {
__ctl_store ( cr2_old , 2 , 2 ) ;
cr2_new = cr2_old | ( 1UL < < 4 ) ;
__ctl_load ( cr2_new , 2 , 2 ) ;
save_gs_cb ( ( struct gs_cb * ) mcesa - > guarded_storage_save_area ) ;
__ctl_load ( cr2_old , 2 , 2 ) ;
}
2015-10-29 12:28:26 +03:00
/*
* 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 18:16:40 +04:00
}
2015-01-14 19:52:10 +03:00
# endif
2011-10-30 18:16:40 +04: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-24 02:24:22 +03:00
# ifdef CONFIG_CRASH_DUMP
2016-05-31 10:13:59 +03: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 10:14:00 +03:00
static void crash_protect_pages ( int protect )
2011-10-30 18:16:44 +04:00
{
2016-05-31 10:14:00 +03:00
unsigned long size ;
2011-10-30 18:16:44 +04:00
2016-05-31 10:14:00 +03: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 10:13:59 +03:00
else
2016-05-31 10:14:00 +03:00
set_memory_rw ( crashk_res . start , size > > PAGE_SHIFT ) ;
2011-10-30 18:16:44 +04:00
}
2016-05-24 02:24:22 +03:00
void arch_kexec_protect_crashkres ( void )
2011-10-30 18:16:44 +04:00
{
2016-05-31 10:14:00 +03:00
crash_protect_pages ( 1 ) ;
2011-10-30 18:16:44 +04:00
}
2016-05-24 02:24:22 +03:00
void arch_kexec_unprotect_crashkres ( void )
2011-10-30 18:16:44 +04:00
{
2016-05-31 10:14:00 +03:00
crash_protect_pages ( 0 ) ;
2011-10-30 18:16:44 +04:00
}
2016-05-24 02:24:22 +03:00
# endif
2011-10-30 18:16:40 +04: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 17:40:33 +03:00
int machine_kexec_prepare ( struct kimage * image )
2005-06-26 01:58:11 +04:00
{
2006-12-04 17:40:33 +03:00
void * reboot_code_buffer ;
2005-06-26 01:58:11 +04:00
2007-03-06 01:35:45 +03:00
/* Can't replace kernel image since it is read-only. */
if ( ipl_flags & IPL_NSS_VALID )
2012-09-06 17:19:08 +04:00
return - EOPNOTSUPP ;
2007-03-06 01:35:45 +03:00
2011-10-30 18:16:40 +04:00
if ( image - > type = = KEXEC_TYPE_CRASH )
return machine_kexec_prepare_kdump ( ) ;
2005-06-26 01:58:11 +04: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 17:40:33 +03:00
reboot_code_buffer = ( void * ) page_to_phys ( image - > control_code_page ) ;
2005-06-26 01:58:11 +04:00
/* Then copy it */
2006-12-04 17:40:33 +03:00
memcpy ( reboot_code_buffer , relocate_kernel , relocate_kernel_len ) ;
2005-06-26 01:58:11 +04:00
return 0 ;
}
2006-12-04 17:40:33 +03:00
void machine_kexec_cleanup ( struct kimage * image )
2005-06-26 01:58:11 +04:00
{
}
2011-10-30 18:16:40 +04:00
void arch_crash_save_vmcoreinfo ( void )
{
VMCOREINFO_SYMBOL ( lowcore_ptr ) ;
2011-12-27 14:27:24 +04:00
VMCOREINFO_SYMBOL ( high_memory ) ;
2011-10-30 18:16:40 +04:00
VMCOREINFO_LENGTH ( lowcore_ptr , NR_CPUS ) ;
2017-07-13 00:33:14 +03:00
mem_assign_absolute ( S390_lowcore . vmcore_info , paddr_vmcoreinfo_note ( ) ) ;
2011-10-30 18:16:40 +04:00
}
2006-12-04 17:40:33 +03:00
void machine_shutdown ( void )
2005-06-26 01:58:11 +04:00
{
}
2012-08-27 17:50:29 +04:00
void machine_crash_shutdown ( struct pt_regs * regs )
{
}
2011-10-30 18:16:40 +04:00
/*
* Do normal kexec
*/
static void __do_machine_kexec ( void * data )
2005-06-26 01:58:11 +04:00
{
relocate_kernel_t data_mover ;
2010-02-27 00:37:34 +03:00
struct kimage * image = data ;
2005-06-26 01:58:11 +04:00
2015-10-29 12:28:26 +03:00
s390_reset_system ( ) ;
2006-12-04 17:40:33 +03:00
data_mover = ( relocate_kernel_t ) page_to_phys ( image - > control_code_page ) ;
2005-06-26 01:58:11 +04:00
/* Call the moving routine */
2006-12-04 17:40:33 +03:00
( * data_mover ) ( & image - > head , image - > start ) ;
2015-10-29 12:28:26 +03:00
/* Die if kexec returns */
disabled_wait ( ( unsigned long ) __builtin_return_address ( 0 ) ) ;
2005-06-26 01:58:11 +04:00
}
2010-02-27 00:37:34 +03:00
2011-10-30 18:16:40 +04:00
/*
* Reset system and call either kdump or normal kexec
*/
static void __machine_kexec ( void * data )
{
2012-05-21 13:30:30 +04:00
__arch_local_irq_stosm ( 0x04 ) ; /* enable DAT */
2011-10-30 18:16:40 +04:00
pfault_fini ( ) ;
2012-03-11 19:59:32 +04:00
tracing_off ( ) ;
debug_locks_off ( ) ;
2015-01-14 19:52:10 +03:00
# ifdef CONFIG_CRASH_DUMP
2015-10-29 12:28:26 +03:00
if ( ( ( struct kimage * ) data ) - > type = = KEXEC_TYPE_CRASH )
__machine_kdump ( data ) ;
2015-01-14 19:52:10 +03:00
# endif
2015-10-29 12:28:26 +03:00
__do_machine_kexec ( data ) ;
2011-10-30 18:16:40 +04:00
}
/*
* Do either kdump or normal kexec . In case of kdump we first ask
* purgatory , if kdump checksums are valid .
*/
2010-02-27 00:37:34 +03:00
void machine_kexec ( struct kimage * image )
{
2011-10-30 18:16:40 +04:00
if ( image - > type = = KEXEC_TYPE_CRASH & & ! kdump_csum_valid ( image ) )
return ;
2011-03-15 19:08:33 +03:00
tracer_disable ( ) ;
2010-02-27 00:37:34 +03:00
smp_send_stop ( ) ;
2012-03-11 19:59:26 +04:00
smp_call_ipl_cpu ( __machine_kexec , image ) ;
2010-02-27 00:37:34 +03:00
}