2007-06-04 15:15:49 +10:00
/*
* Common signal handling code for both 32 and 64 bits
*
* Copyright ( c ) 2007 Benjamin Herrenschmidt , IBM Coproration
* Extracted from signal_32 . c and signal_64 . c
*
* This file is subject to the terms and conditions of the GNU General
* Public License . See the file README . legal in the main directory of
* this archive for more details .
*/
2008-07-27 16:49:50 +10:00
# include <linux/tracehook.h>
2007-06-04 15:15:49 +10:00
# include <linux/signal.h>
2012-08-23 21:31:32 +00:00
# include <linux/uprobes.h>
2012-02-22 16:48:32 +11:00
# include <linux/key.h>
2010-06-15 11:35:41 +05:30
# include <asm/hw_breakpoint.h>
2007-06-04 17:22:48 +10:00
# include <asm/uaccess.h>
2007-06-04 15:15:49 +10:00
# include <asm/unistd.h>
2012-03-28 18:30:02 +01:00
# include <asm/debug.h>
2007-06-04 15:15:49 +10:00
2007-06-04 15:15:51 +10:00
# include "signal.h"
2007-10-12 10:20:07 +10:00
/* Log an error when sending an unhandled signal to a process. Controlled
* through debug . exception - trace sysctl .
*/
int show_unhandled_signals = 0 ;
2007-06-04 17:22:48 +10:00
/*
* Allocate space for the signal frame
*/
void __user * get_sigframe ( struct k_sigaction * ka , struct pt_regs * regs ,
2009-03-25 06:23:59 +00:00
size_t frame_size , int is_32 )
2007-06-04 17:22:48 +10:00
{
unsigned long oldsp , newsp ;
/* Default to using normal stack */
2009-03-25 06:23:59 +00:00
oldsp = get_clean_sp ( regs , is_32 ) ;
2007-06-04 17:22:48 +10:00
/* Check for alt stack */
if ( ( ka - > sa . sa_flags & SA_ONSTACK ) & &
current - > sas_ss_size & & ! on_sig_stack ( oldsp ) )
oldsp = ( current - > sas_ss_sp + current - > sas_ss_size ) ;
/* Get aligned frame */
newsp = ( oldsp - frame_size ) & ~ 0xFUL ;
/* Check access */
if ( ! access_ok ( VERIFY_WRITE , ( void __user * ) newsp , oldsp - newsp ) )
return NULL ;
return ( void __user * ) newsp ;
}
2007-06-04 15:15:52 +10:00
static void check_syscall_restart ( struct pt_regs * regs , struct k_sigaction * ka ,
int has_handler )
2007-06-04 15:15:49 +10:00
{
unsigned long ret = regs - > gpr [ 3 ] ;
int restart = 1 ;
/* syscall ? */
if ( TRAP ( regs ) ! = 0x0C00 )
return ;
/* error signalled ? */
if ( ! ( regs - > ccr & 0x10000000 ) )
return ;
switch ( ret ) {
case ERESTART_RESTARTBLOCK :
case ERESTARTNOHAND :
/* ERESTARTNOHAND means that the syscall should only be
* restarted if there was no handler for the signal , and since
* we only get here if there is a handler , we dont restart .
*/
restart = ! has_handler ;
break ;
case ERESTARTSYS :
/* ERESTARTSYS means to restart the syscall if there is no
* handler or the handler was registered with SA_RESTART
*/
restart = ! has_handler | | ( ka - > sa . sa_flags & SA_RESTART ) ! = 0 ;
break ;
case ERESTARTNOINTR :
/* ERESTARTNOINTR means that the syscall should be
* called again after the signal handler returns .
*/
break ;
default :
return ;
}
if ( restart ) {
if ( ret = = ERESTART_RESTARTBLOCK )
regs - > gpr [ 0 ] = __NR_restart_syscall ;
else
regs - > gpr [ 3 ] = regs - > orig_gpr3 ;
regs - > nip - = 4 ;
regs - > result = 0 ;
} else {
regs - > result = - EINTR ;
regs - > gpr [ 3 ] = EINTR ;
regs - > ccr | = 0x10000000 ;
}
}
2007-06-04 15:15:50 +10:00
2012-02-22 16:48:32 +11:00
static int do_signal ( struct pt_regs * regs )
2007-06-04 15:15:52 +10:00
{
2012-05-02 09:59:21 -04:00
sigset_t * oldset = sigmask_to_save ( ) ;
2007-06-04 15:15:52 +10:00
siginfo_t info ;
int signr ;
struct k_sigaction ka ;
int ret ;
int is32 = is_32bit_task ( ) ;
signr = get_signal_to_deliver ( & info , & ka , regs , NULL ) ;
/* Is there any syscall restart business here ? */
check_syscall_restart ( regs , & ka , signr > 0 ) ;
if ( signr < = 0 ) {
/* No signal to deliver -- put the saved sigmask back */
2012-05-21 23:33:55 -04:00
restore_saved_sigmask ( ) ;
2010-09-20 21:48:57 +01:00
regs - > trap = 0 ;
2007-06-04 15:15:52 +10:00
return 0 ; /* no signals delivered */
}
2010-02-08 11:51:18 +00:00
# ifndef CONFIG_PPC_ADV_DEBUG_REGS
2007-06-04 15:15:52 +10:00
/*
* Reenable the DABR before delivering the signal to
* user space . The DABR will have been cleared if it
* triggered inside the kernel .
*/
2012-12-20 14:06:44 +00:00
if ( current - > thread . hw_brk . address & &
current - > thread . hw_brk . type )
2013-01-10 14:25:34 +00:00
set_breakpoint ( & current - > thread . hw_brk ) ;
2008-07-24 02:10:41 +10:00
# endif
2010-06-15 11:35:41 +05:30
/* Re-enable the breakpoints for the signal stack */
thread_change_pc ( current , regs ) ;
2007-06-04 15:15:52 +10:00
if ( is32 ) {
if ( ka . sa . sa_flags & SA_SIGINFO )
ret = handle_rt_signal32 ( signr , & ka , & info , oldset ,
2007-06-04 17:22:48 +10:00
regs ) ;
2007-06-04 15:15:52 +10:00
else
ret = handle_signal32 ( signr , & ka , & info , oldset ,
2007-06-04 17:22:48 +10:00
regs ) ;
2007-06-04 15:15:52 +10:00
} else {
ret = handle_rt_signal64 ( signr , & ka , & info , oldset , regs ) ;
}
2010-09-20 21:48:57 +01:00
regs - > trap = 0 ;
2007-06-04 15:15:52 +10:00
if ( ret ) {
2012-04-28 02:04:15 -04:00
signal_delivered ( signr , & info , & ka , regs ,
2008-07-27 16:49:50 +10:00
test_thread_flag ( TIF_SINGLESTEP ) ) ;
2007-06-04 15:15:52 +10:00
}
return ret ;
}
2012-02-22 16:48:32 +11:00
void do_notify_resume ( struct pt_regs * regs , unsigned long thread_info_flags )
2008-07-27 16:52:52 +10:00
{
2012-10-28 18:17:11 +01:00
if ( thread_info_flags & _TIF_UPROBE )
2012-08-23 21:31:32 +00:00
uprobe_notify_resume ( regs ) ;
2008-07-27 16:52:52 +10:00
if ( thread_info_flags & _TIF_SIGPENDING )
2012-02-22 16:48:32 +11:00
do_signal ( regs ) ;
2008-07-27 16:52:52 +10:00
if ( thread_info_flags & _TIF_NOTIFY_RESUME ) {
clear_thread_flag ( TIF_NOTIFY_RESUME ) ;
tracehook_notify_resume ( regs ) ;
}
}