2005-04-17 02:20:36 +04:00
/*
* linux / arch / alpha / kernel / signal . c
*
* Copyright ( C ) 1995 Linus Torvalds
*
* 1997 - 11 - 02 Modified for POSIX .1 b signals by Richard Henderson
*/
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/signal.h>
# include <linux/errno.h>
# include <linux/wait.h>
# include <linux/ptrace.h>
# include <linux/unistd.h>
# include <linux/mm.h>
# include <linux/smp.h>
# include <linux/stddef.h>
# include <linux/tty.h>
# include <linux/binfmts.h>
# include <linux/bitops.h>
2009-01-30 01:25:18 +03:00
# include <linux/syscalls.h>
2009-09-09 11:30:21 +04:00
# include <linux/tracehook.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/sigcontext.h>
# include <asm/ucontext.h>
# include "proto.h"
# define DEBUG_SIG 0
# define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage void ret_from_sys_call ( void ) ;
/*
* The OSF / 1 sigprocmask calling sequence is different from the
* C sigprocmask ( ) sequence . .
*/
2010-09-26 22:28:12 +04:00
SYSCALL_DEFINE2 ( osf_sigprocmask , int , how , unsigned long , newmask )
2005-04-17 02:20:36 +04:00
{
2010-09-26 22:28:12 +04:00
sigset_t oldmask ;
sigset_t mask ;
unsigned long res ;
2005-04-17 02:20:36 +04:00
2010-09-30 19:37:38 +04:00
siginitset ( & mask , newmask & _BLOCKABLE ) ;
2010-09-29 00:26:57 +04:00
res = sigprocmask ( how , & mask , & oldmask ) ;
2010-09-26 22:28:12 +04:00
if ( ! res ) {
force_successful_syscall_return ( ) ;
2010-09-29 00:26:57 +04:00
res = oldmask . sig [ 0 ] ;
2005-04-17 02:20:36 +04:00
}
2010-09-26 22:28:12 +04:00
return res ;
2005-04-17 02:20:36 +04:00
}
2009-01-30 01:25:18 +03:00
SYSCALL_DEFINE3 ( osf_sigaction , int , sig ,
const struct osf_sigaction __user * , act ,
struct osf_sigaction __user * , oact )
2005-04-17 02:20:36 +04:00
{
struct k_sigaction new_ka , old_ka ;
int ret ;
if ( act ) {
old_sigset_t mask ;
if ( ! access_ok ( VERIFY_READ , act , sizeof ( * act ) ) | |
__get_user ( new_ka . sa . sa_handler , & act - > sa_handler ) | |
2010-09-26 22:28:22 +04:00
__get_user ( new_ka . sa . sa_flags , & act - > sa_flags ) | |
__get_user ( mask , & act - > sa_mask ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
siginitset ( & new_ka . sa . sa_mask , mask ) ;
new_ka . ka_restorer = NULL ;
}
ret = do_sigaction ( sig , act ? & new_ka : NULL , oact ? & old_ka : NULL ) ;
if ( ! ret & & oact ) {
if ( ! access_ok ( VERIFY_WRITE , oact , sizeof ( * oact ) ) | |
__put_user ( old_ka . sa . sa_handler , & oact - > sa_handler ) | |
2010-09-26 22:28:22 +04:00
__put_user ( old_ka . sa . sa_flags , & oact - > sa_flags ) | |
__put_user ( old_ka . sa . sa_mask . sig [ 0 ] , & oact - > sa_mask ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
}
return ret ;
}
2009-01-30 01:25:18 +03:00
SYSCALL_DEFINE5 ( rt_sigaction , int , sig , const struct sigaction __user * , act ,
struct sigaction __user * , oact ,
size_t , sigsetsize , void __user * , restorer )
2005-04-17 02:20:36 +04:00
{
struct k_sigaction new_ka , old_ka ;
int ret ;
/* XXX: Don't preclude handling different sized sigset_t's. */
if ( sigsetsize ! = sizeof ( sigset_t ) )
return - EINVAL ;
if ( act ) {
new_ka . ka_restorer = restorer ;
if ( copy_from_user ( & new_ka . sa , act , sizeof ( * act ) ) )
return - EFAULT ;
}
ret = do_sigaction ( sig , act ? & new_ka : NULL , oact ? & old_ka : NULL ) ;
if ( ! ret & & oact ) {
if ( copy_to_user ( oact , & old_ka . sa , sizeof ( * oact ) ) )
return - EFAULT ;
}
return ret ;
}
/*
* Do a signal return ; undo the signal stack .
*/
# if _NSIG_WORDS > 1
# error "Non SA_SIGINFO frame needs rearranging"
# endif
struct sigframe
{
struct sigcontext sc ;
unsigned int retcode [ 3 ] ;
} ;
struct rt_sigframe
{
struct siginfo info ;
struct ucontext uc ;
unsigned int retcode [ 3 ] ;
} ;
/* If this changes, userland unwinders that Know Things about our signal
frame will break . Do not undertake lightly . It also implies an ABI
change wrt the size of siginfo_t , which may cause some pain . */
extern char compile_time_assert
[ offsetof ( struct rt_sigframe , uc . uc_mcontext ) = = 176 ? 1 : - 1 ] ;
# define INSN_MOV_R30_R16 0x47fe0410
# define INSN_LDI_R0 0x201f0000
# define INSN_CALLSYS 0x00000083
static long
2012-10-18 09:43:27 +04:00
restore_sigcontext ( struct sigcontext __user * sc , struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
unsigned long usp ;
2012-10-18 09:43:27 +04:00
struct switch_stack * sw = ( struct switch_stack * ) regs - 1 ;
2005-04-17 02:20:36 +04:00
long i , err = __get_user ( regs - > pc , & sc - > sc_pc ) ;
2015-02-13 02:01:14 +03:00
current - > restart_block . fn = do_no_restart_syscall ;
2010-09-18 16:38:47 +04:00
2005-04-17 02:20:36 +04:00
sw - > r26 = ( unsigned long ) ret_from_sys_call ;
err | = __get_user ( regs - > r0 , sc - > sc_regs + 0 ) ;
err | = __get_user ( regs - > r1 , sc - > sc_regs + 1 ) ;
err | = __get_user ( regs - > r2 , sc - > sc_regs + 2 ) ;
err | = __get_user ( regs - > r3 , sc - > sc_regs + 3 ) ;
err | = __get_user ( regs - > r4 , sc - > sc_regs + 4 ) ;
err | = __get_user ( regs - > r5 , sc - > sc_regs + 5 ) ;
err | = __get_user ( regs - > r6 , sc - > sc_regs + 6 ) ;
err | = __get_user ( regs - > r7 , sc - > sc_regs + 7 ) ;
err | = __get_user ( regs - > r8 , sc - > sc_regs + 8 ) ;
err | = __get_user ( sw - > r9 , sc - > sc_regs + 9 ) ;
err | = __get_user ( sw - > r10 , sc - > sc_regs + 10 ) ;
err | = __get_user ( sw - > r11 , sc - > sc_regs + 11 ) ;
err | = __get_user ( sw - > r12 , sc - > sc_regs + 12 ) ;
err | = __get_user ( sw - > r13 , sc - > sc_regs + 13 ) ;
err | = __get_user ( sw - > r14 , sc - > sc_regs + 14 ) ;
err | = __get_user ( sw - > r15 , sc - > sc_regs + 15 ) ;
err | = __get_user ( regs - > r16 , sc - > sc_regs + 16 ) ;
err | = __get_user ( regs - > r17 , sc - > sc_regs + 17 ) ;
err | = __get_user ( regs - > r18 , sc - > sc_regs + 18 ) ;
err | = __get_user ( regs - > r19 , sc - > sc_regs + 19 ) ;
err | = __get_user ( regs - > r20 , sc - > sc_regs + 20 ) ;
err | = __get_user ( regs - > r21 , sc - > sc_regs + 21 ) ;
err | = __get_user ( regs - > r22 , sc - > sc_regs + 22 ) ;
err | = __get_user ( regs - > r23 , sc - > sc_regs + 23 ) ;
err | = __get_user ( regs - > r24 , sc - > sc_regs + 24 ) ;
err | = __get_user ( regs - > r25 , sc - > sc_regs + 25 ) ;
err | = __get_user ( regs - > r26 , sc - > sc_regs + 26 ) ;
err | = __get_user ( regs - > r27 , sc - > sc_regs + 27 ) ;
err | = __get_user ( regs - > r28 , sc - > sc_regs + 28 ) ;
err | = __get_user ( regs - > gp , sc - > sc_regs + 29 ) ;
err | = __get_user ( usp , sc - > sc_regs + 30 ) ;
wrusp ( usp ) ;
for ( i = 0 ; i < 31 ; i + + )
err | = __get_user ( sw - > fp [ i ] , sc - > sc_fpregs + i ) ;
err | = __get_user ( sw - > fp [ 31 ] , & sc - > sc_fpcr ) ;
return err ;
}
/* Note that this syscall is also used by setcontext(3) to install
a given sigcontext . This because it ' s impossible to set * all *
registers and transfer control from userland . */
asmlinkage void
2012-10-18 09:43:27 +04:00
do_sigreturn ( struct sigcontext __user * sc )
2005-04-17 02:20:36 +04:00
{
2012-10-18 09:43:27 +04:00
struct pt_regs * regs = current_pt_regs ( ) ;
2005-04-17 02:20:36 +04:00
sigset_t set ;
/* Verify that it's a good sigcontext before using it */
if ( ! access_ok ( VERIFY_READ , sc , sizeof ( * sc ) ) )
goto give_sigsegv ;
if ( __get_user ( set . sig [ 0 ] , & sc - > sc_mask ) )
goto give_sigsegv ;
2012-04-06 01:25:12 +04:00
set_current_blocked ( & set ) ;
2005-04-17 02:20:36 +04:00
2012-10-18 09:43:27 +04:00
if ( restore_sigcontext ( sc , regs ) )
2005-04-17 02:20:36 +04:00
goto give_sigsegv ;
/* Send SIGTRAP if we're single-stepping: */
if ( ptrace_cancel_bpt ( current ) ) {
siginfo_t info ;
info . si_signo = SIGTRAP ;
info . si_errno = 0 ;
info . si_code = TRAP_BRKPT ;
info . si_addr = ( void __user * ) regs - > pc ;
info . si_trapno = 0 ;
send_sig_info ( SIGTRAP , & info , current ) ;
}
return ;
give_sigsegv :
force_sig ( SIGSEGV , current ) ;
}
asmlinkage void
2012-10-18 09:43:27 +04:00
do_rt_sigreturn ( struct rt_sigframe __user * frame )
2005-04-17 02:20:36 +04:00
{
2012-10-18 09:43:27 +04:00
struct pt_regs * regs = current_pt_regs ( ) ;
2005-04-17 02:20:36 +04:00
sigset_t set ;
/* Verify that it's a good ucontext_t before using it */
if ( ! access_ok ( VERIFY_READ , & frame - > uc , sizeof ( frame - > uc ) ) )
goto give_sigsegv ;
if ( __copy_from_user ( & set , & frame - > uc . uc_sigmask , sizeof ( set ) ) )
goto give_sigsegv ;
2012-04-06 01:25:12 +04:00
set_current_blocked ( & set ) ;
2005-04-17 02:20:36 +04:00
2012-10-18 09:43:27 +04:00
if ( restore_sigcontext ( & frame - > uc . uc_mcontext , regs ) )
2005-04-17 02:20:36 +04:00
goto give_sigsegv ;
/* Send SIGTRAP if we're single-stepping: */
if ( ptrace_cancel_bpt ( current ) ) {
siginfo_t info ;
info . si_signo = SIGTRAP ;
info . si_errno = 0 ;
info . si_code = TRAP_BRKPT ;
info . si_addr = ( void __user * ) regs - > pc ;
info . si_trapno = 0 ;
send_sig_info ( SIGTRAP , & info , current ) ;
}
return ;
give_sigsegv :
force_sig ( SIGSEGV , current ) ;
}
/*
* Set up a signal frame .
*/
static inline void __user *
2012-11-08 02:38:51 +04:00
get_sigframe ( struct ksignal * ksig , unsigned long sp , size_t frame_size )
2005-04-17 02:20:36 +04:00
{
2012-11-08 02:38:51 +04:00
return ( void __user * ) ( ( sigsp ( sp , ksig ) - frame_size ) & - 32ul ) ;
2005-04-17 02:20:36 +04:00
}
static long
setup_sigcontext ( struct sigcontext __user * sc , struct pt_regs * regs ,
2012-09-06 02:53:18 +04:00
unsigned long mask , unsigned long sp )
2005-04-17 02:20:36 +04:00
{
2012-09-06 02:53:18 +04:00
struct switch_stack * sw = ( struct switch_stack * ) regs - 1 ;
2005-04-17 02:20:36 +04:00
long i , err = 0 ;
err | = __put_user ( on_sig_stack ( ( unsigned long ) sc ) , & sc - > sc_onstack ) ;
err | = __put_user ( mask , & sc - > sc_mask ) ;
err | = __put_user ( regs - > pc , & sc - > sc_pc ) ;
err | = __put_user ( 8 , & sc - > sc_ps ) ;
err | = __put_user ( regs - > r0 , sc - > sc_regs + 0 ) ;
err | = __put_user ( regs - > r1 , sc - > sc_regs + 1 ) ;
err | = __put_user ( regs - > r2 , sc - > sc_regs + 2 ) ;
err | = __put_user ( regs - > r3 , sc - > sc_regs + 3 ) ;
err | = __put_user ( regs - > r4 , sc - > sc_regs + 4 ) ;
err | = __put_user ( regs - > r5 , sc - > sc_regs + 5 ) ;
err | = __put_user ( regs - > r6 , sc - > sc_regs + 6 ) ;
err | = __put_user ( regs - > r7 , sc - > sc_regs + 7 ) ;
err | = __put_user ( regs - > r8 , sc - > sc_regs + 8 ) ;
err | = __put_user ( sw - > r9 , sc - > sc_regs + 9 ) ;
err | = __put_user ( sw - > r10 , sc - > sc_regs + 10 ) ;
err | = __put_user ( sw - > r11 , sc - > sc_regs + 11 ) ;
err | = __put_user ( sw - > r12 , sc - > sc_regs + 12 ) ;
err | = __put_user ( sw - > r13 , sc - > sc_regs + 13 ) ;
err | = __put_user ( sw - > r14 , sc - > sc_regs + 14 ) ;
err | = __put_user ( sw - > r15 , sc - > sc_regs + 15 ) ;
err | = __put_user ( regs - > r16 , sc - > sc_regs + 16 ) ;
err | = __put_user ( regs - > r17 , sc - > sc_regs + 17 ) ;
err | = __put_user ( regs - > r18 , sc - > sc_regs + 18 ) ;
err | = __put_user ( regs - > r19 , sc - > sc_regs + 19 ) ;
err | = __put_user ( regs - > r20 , sc - > sc_regs + 20 ) ;
err | = __put_user ( regs - > r21 , sc - > sc_regs + 21 ) ;
err | = __put_user ( regs - > r22 , sc - > sc_regs + 22 ) ;
err | = __put_user ( regs - > r23 , sc - > sc_regs + 23 ) ;
err | = __put_user ( regs - > r24 , sc - > sc_regs + 24 ) ;
err | = __put_user ( regs - > r25 , sc - > sc_regs + 25 ) ;
err | = __put_user ( regs - > r26 , sc - > sc_regs + 26 ) ;
err | = __put_user ( regs - > r27 , sc - > sc_regs + 27 ) ;
err | = __put_user ( regs - > r28 , sc - > sc_regs + 28 ) ;
err | = __put_user ( regs - > gp , sc - > sc_regs + 29 ) ;
err | = __put_user ( sp , sc - > sc_regs + 30 ) ;
err | = __put_user ( 0 , sc - > sc_regs + 31 ) ;
for ( i = 0 ; i < 31 ; i + + )
err | = __put_user ( sw - > fp [ i ] , sc - > sc_fpregs + i ) ;
err | = __put_user ( 0 , sc - > sc_fpregs + 31 ) ;
err | = __put_user ( sw - > fp [ 31 ] , & sc - > sc_fpcr ) ;
err | = __put_user ( regs - > trap_a0 , & sc - > sc_traparg_a0 ) ;
err | = __put_user ( regs - > trap_a1 , & sc - > sc_traparg_a1 ) ;
err | = __put_user ( regs - > trap_a2 , & sc - > sc_traparg_a2 ) ;
return err ;
}
2007-05-30 03:03:28 +04:00
static int
2012-11-08 02:38:51 +04:00
setup_frame ( struct ksignal * ksig , sigset_t * set , struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
unsigned long oldsp , r26 , err = 0 ;
struct sigframe __user * frame ;
oldsp = rdusp ( ) ;
2012-11-08 02:38:51 +04:00
frame = get_sigframe ( ksig , oldsp , sizeof ( * frame ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_WRITE , frame , sizeof ( * frame ) ) )
2012-04-22 10:34:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
2012-09-06 02:53:18 +04:00
err | = setup_sigcontext ( & frame - > sc , regs , set - > sig [ 0 ] , oldsp ) ;
2005-04-17 02:20:36 +04:00
if ( err )
2012-04-22 10:34:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
/* Set up to return from userspace. If provided, use a stub
already in userspace . */
2012-11-08 02:38:51 +04:00
r26 = ( unsigned long ) ksig - > ka . ka_restorer ;
if ( ! r26 ) {
2005-04-17 02:20:36 +04:00
err | = __put_user ( INSN_MOV_R30_R16 , frame - > retcode + 0 ) ;
err | = __put_user ( INSN_LDI_R0 + __NR_sigreturn , frame - > retcode + 1 ) ;
err | = __put_user ( INSN_CALLSYS , frame - > retcode + 2 ) ;
imb ( ) ;
r26 = ( unsigned long ) frame - > retcode ;
}
/* Check that everything was written properly. */
if ( err )
2012-04-22 10:34:42 +04:00
return err ;
2005-04-17 02:20:36 +04:00
/* "Return" to the handler */
regs - > r26 = r26 ;
2012-11-08 02:38:51 +04:00
regs - > r27 = regs - > pc = ( unsigned long ) ksig - > ka . sa . sa_handler ;
regs - > r16 = ksig - > sig ; /* a0: signal number */
2005-04-17 02:20:36 +04:00
regs - > r17 = 0 ; /* a1: exception code */
regs - > r18 = ( unsigned long ) & frame - > sc ; /* a2: sigcontext pointer */
wrusp ( ( unsigned long ) frame ) ;
# if DEBUG_SIG
printk ( " SIG deliver (%s:%d): sp=%p pc=%p ra=%p \n " ,
current - > comm , current - > pid , frame , regs - > pc , regs - > r26 ) ;
# endif
2007-05-30 03:03:28 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-30 03:03:28 +04:00
static int
2012-11-08 02:38:51 +04:00
setup_rt_frame ( struct ksignal * ksig , sigset_t * set , struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
unsigned long oldsp , r26 , err = 0 ;
struct rt_sigframe __user * frame ;
oldsp = rdusp ( ) ;
2012-11-08 02:38:51 +04:00
frame = get_sigframe ( ksig , oldsp , sizeof ( * frame ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_WRITE , frame , sizeof ( * frame ) ) )
2012-04-22 10:34:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
2012-11-08 02:38:51 +04:00
err | = copy_siginfo_to_user ( & frame - > info , & ksig - > info ) ;
2005-04-17 02:20:36 +04:00
/* Create the ucontext. */
err | = __put_user ( 0 , & frame - > uc . uc_flags ) ;
err | = __put_user ( 0 , & frame - > uc . uc_link ) ;
err | = __put_user ( set - > sig [ 0 ] , & frame - > uc . uc_osf_sigmask ) ;
2012-12-15 00:25:43 +04:00
err | = __save_altstack ( & frame - > uc . uc_stack , oldsp ) ;
2012-09-06 02:53:18 +04:00
err | = setup_sigcontext ( & frame - > uc . uc_mcontext , regs ,
2005-04-17 02:20:36 +04:00
set - > sig [ 0 ] , oldsp ) ;
err | = __copy_to_user ( & frame - > uc . uc_sigmask , set , sizeof ( * set ) ) ;
if ( err )
2012-04-22 10:34:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
/* Set up to return from userspace. If provided, use a stub
already in userspace . */
2012-11-08 02:38:51 +04:00
r26 = ( unsigned long ) ksig - > ka . ka_restorer ;
if ( ! r26 ) {
2005-04-17 02:20:36 +04:00
err | = __put_user ( INSN_MOV_R30_R16 , frame - > retcode + 0 ) ;
err | = __put_user ( INSN_LDI_R0 + __NR_rt_sigreturn ,
frame - > retcode + 1 ) ;
err | = __put_user ( INSN_CALLSYS , frame - > retcode + 2 ) ;
imb ( ) ;
r26 = ( unsigned long ) frame - > retcode ;
}
if ( err )
2012-04-22 10:34:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
/* "Return" to the handler */
regs - > r26 = r26 ;
2012-11-08 02:38:51 +04:00
regs - > r27 = regs - > pc = ( unsigned long ) ksig - > ka . sa . sa_handler ;
regs - > r16 = ksig - > sig ; /* a0: signal number */
2005-04-17 02:20:36 +04:00
regs - > r17 = ( unsigned long ) & frame - > info ; /* a1: siginfo pointer */
regs - > r18 = ( unsigned long ) & frame - > uc ; /* a2: ucontext pointer */
wrusp ( ( unsigned long ) frame ) ;
# if DEBUG_SIG
printk ( " SIG deliver (%s:%d): sp=%p pc=%p ra=%p \n " ,
current - > comm , current - > pid , frame , regs - > pc , regs - > r26 ) ;
# endif
2007-05-30 03:03:28 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* OK , we ' re invoking a handler .
*/
2012-04-22 10:34:42 +04:00
static inline void
2012-11-08 02:38:51 +04:00
handle_signal ( struct ksignal * ksig , struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
2012-05-02 17:59:21 +04:00
sigset_t * oldset = sigmask_to_save ( ) ;
2007-05-30 03:03:28 +04:00
int ret ;
2012-11-08 02:38:51 +04:00
if ( ksig - > ka . sa . sa_flags & SA_SIGINFO )
ret = setup_rt_frame ( ksig , oldset , regs ) ;
2005-04-17 02:20:36 +04:00
else
2012-11-08 02:38:51 +04:00
ret = setup_frame ( ksig , oldset , regs ) ;
2005-04-17 02:20:36 +04:00
2012-11-08 02:38:51 +04:00
signal_setup_done ( ret , ksig , 0 ) ;
2005-04-17 02:20:36 +04:00
}
static inline void
syscall_restart ( unsigned long r0 , unsigned long r19 ,
struct pt_regs * regs , struct k_sigaction * ka )
{
switch ( regs - > r0 ) {
case ERESTARTSYS :
if ( ! ( ka - > sa . sa_flags & SA_RESTART ) ) {
case ERESTARTNOHAND :
regs - > r0 = EINTR ;
break ;
}
/* fallthrough */
case ERESTARTNOINTR :
regs - > r0 = r0 ; /* reset v0 and a3 and replay syscall */
regs - > r19 = r19 ;
regs - > pc - = 4 ;
break ;
case ERESTART_RESTARTBLOCK :
regs - > r0 = EINTR ;
break ;
}
}
/*
* Note that ' init ' is a special process : it doesn ' t get signals it doesn ' t
* want to handle . Thus you cannot kill init even with a SIGKILL even by
* mistake .
*
* Note that we go through the signals twice : once to check the signals that
* the kernel can handle , and then we build all the user - level signal handling
* stack - frames in one go after that .
*
* " r0 " and " r19 " are the registers we need to restore for system call
* restart . " r0 " is also used as an indicator whether we can restart at
* all ( if we get here from anything but a syscall return , it will be 0 )
*/
2007-05-30 03:03:28 +04:00
static void
2012-09-06 02:53:18 +04:00
do_signal ( struct pt_regs * regs , unsigned long r0 , unsigned long r19 )
2005-04-17 02:20:36 +04:00
{
unsigned long single_stepping = ptrace_cancel_bpt ( current ) ;
2012-11-08 02:38:51 +04:00
struct ksignal ksig ;
2005-04-17 02:20:36 +04:00
/* This lets the debugger run, ... */
2012-11-08 02:38:51 +04:00
if ( get_signal ( & ksig ) ) {
/* ... so re-check the single stepping. */
single_stepping | = ptrace_cancel_bpt ( current ) ;
2005-04-17 02:20:36 +04:00
/* Whee! Actually deliver the signal. */
2007-05-30 03:03:28 +04:00
if ( r0 )
2012-11-08 02:38:51 +04:00
syscall_restart ( r0 , r19 , regs , & ksig . ka ) ;
handle_signal ( & ksig , regs ) ;
} else {
single_stepping | = ptrace_cancel_bpt ( current ) ;
if ( r0 ) {
switch ( regs - > r0 ) {
case ERESTARTNOHAND :
case ERESTARTSYS :
case ERESTARTNOINTR :
/* Reset v0 and a3 and replay syscall. */
regs - > r0 = r0 ;
regs - > r19 = r19 ;
regs - > pc - = 4 ;
break ;
case ERESTART_RESTARTBLOCK :
/* Set v0 to the restart_syscall and replay */
regs - > r0 = __NR_restart_syscall ;
regs - > pc - = 4 ;
break ;
}
2005-04-17 02:20:36 +04:00
}
2012-11-08 02:38:51 +04:00
restore_saved_sigmask ( ) ;
2005-04-17 02:20:36 +04:00
}
if ( single_stepping )
ptrace_set_bpt ( current ) ; /* re-set breakpoint */
}
void
2012-10-11 07:50:59 +04:00
do_work_pending ( struct pt_regs * regs , unsigned long thread_flags ,
2007-05-30 03:03:28 +04:00
unsigned long r0 , unsigned long r19 )
2005-04-17 02:20:36 +04:00
{
2012-09-06 02:30:34 +04:00
do {
if ( thread_flags & _TIF_NEED_RESCHED ) {
schedule ( ) ;
} else {
local_irq_enable ( ) ;
if ( thread_flags & _TIF_SIGPENDING ) {
2012-09-06 02:53:18 +04:00
do_signal ( regs , r0 , r19 ) ;
2012-09-06 02:30:34 +04:00
r0 = 0 ;
} else {
clear_thread_flag ( TIF_NOTIFY_RESUME ) ;
tracehook_notify_resume ( regs ) ;
}
}
local_irq_disable ( ) ;
thread_flags = current_thread_info ( ) - > flags ;
} while ( thread_flags & _TIF_WORK_MASK ) ;
2005-04-17 02:20:36 +04:00
}