2005-04-16 15:20:36 -07:00
/*
2012-07-20 11:15:04 +02:00
* Copyright IBM Corp . 1999 , 2006
2005-04-16 15:20:36 -07:00
* Author ( s ) : Denis Joseph Barrow ( djbarrow @ de . ibm . com , barrow_dj @ yahoo . com )
*
* Based on Intel version
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*
* 1997 - 11 - 28 Modified for POSIX .1 b signals by Richard Henderson
*/
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/smp.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/stddef.h>
# include <linux/tty.h>
# include <linux/personality.h>
# include <linux/binfmts.h>
2008-10-10 21:33:20 +02:00
# include <linux/tracehook.h>
2009-01-14 14:14:36 +01:00
# include <linux/syscalls.h>
2009-06-12 10:26:25 +02:00
# include <linux/compat.h>
2005-04-16 15:20:36 -07:00
# include <asm/ucontext.h>
# include <asm/uaccess.h>
# include <asm/lowcore.h>
2012-03-28 18:30:02 +01:00
# include <asm/switch_to.h>
2008-04-17 07:46:26 +02:00
# include "entry.h"
2005-04-16 15:20:36 -07:00
2014-10-06 17:53:53 +02:00
/*
* Layout of an old - style signal - frame :
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | save area ( _SIGNAL_FRAMESIZE ) |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | struct sigcontext |
* | oldmask |
* | _sigregs * |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | _sigregs with |
* | _s390_regs_common |
* | _s390_fp_regs |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | int signo |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | _sigregs_ext with |
* | gprs_high 64 byte ( opt ) |
* | vxrs_low 128 byte ( opt ) |
* | vxrs_high 256 byte ( opt ) |
* | reserved 128 byte ( opt ) |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | __u16 svc_insn |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* The svc_insn entry with the sigreturn system call opcode does not
* have a fixed position and moves if gprs_high or vxrs exist .
* Future extensions will be added to _sigregs_ext .
*/
struct sigframe
2005-04-16 15:20:36 -07:00
{
__u8 callee_used_stack [ __SIGNAL_FRAMESIZE ] ;
struct sigcontext sc ;
_sigregs sregs ;
int signo ;
2014-10-06 17:53:53 +02:00
_sigregs_ext sregs_ext ;
__u16 svc_insn ; /* Offset of svc_insn is NOT fixed! */
} ;
2005-04-16 15:20:36 -07:00
2014-10-06 17:53:53 +02:00
/*
* Layout of an rt signal - frame :
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | save area ( _SIGNAL_FRAMESIZE ) |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | svc __NR_rt_sigreturn 2 byte |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | struct siginfo |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | struct ucontext_extended with |
* | unsigned long uc_flags |
* | struct ucontext * uc_link |
* | stack_t uc_stack |
* | _sigregs uc_mcontext with |
* | _s390_regs_common |
* | _s390_fp_regs |
* | sigset_t uc_sigmask |
* | _sigregs_ext uc_mcontext_ext |
* | gprs_high 64 byte ( opt ) |
* | vxrs_low 128 byte ( opt ) |
* | vxrs_high 256 byte ( opt ) |
* | reserved 128 byte ( opt ) |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Future extensions will be added to _sigregs_ext .
*/
struct rt_sigframe
2005-04-16 15:20:36 -07:00
{
__u8 callee_used_stack [ __SIGNAL_FRAMESIZE ] ;
2014-10-06 17:53:53 +02:00
__u16 svc_insn ;
2005-04-16 15:20:36 -07:00
struct siginfo info ;
2014-10-06 17:53:53 +02:00
struct ucontext_extended uc ;
} ;
/* Store registers needed to create the signal frame */
static void store_sigregs ( void )
{
save_access_regs ( current - > thread . acrs ) ;
save_fp_ctl ( & current - > thread . fp_regs . fpc ) ;
# ifdef CONFIG_64BIT
if ( current - > thread . vxrs ) {
int i ;
save_vx_regs ( current - > thread . vxrs ) ;
for ( i = 0 ; i < __NUM_FPRS ; i + + )
current - > thread . fp_regs . fprs [ i ] =
* ( freg_t * ) ( current - > thread . vxrs + i ) ;
} else
# endif
save_fp_regs ( current - > thread . fp_regs . fprs ) ;
}
/* Load registers after signal return */
static void load_sigregs ( void )
{
restore_access_regs ( current - > thread . acrs ) ;
/* restore_fp_ctl is done in restore_sigregs */
# ifdef CONFIG_64BIT
if ( current - > thread . vxrs ) {
int i ;
for ( i = 0 ; i < __NUM_FPRS ; i + + )
* ( freg_t * ) ( current - > thread . vxrs + i ) =
current - > thread . fp_regs . fprs [ i ] ;
restore_vx_regs ( current - > thread . vxrs ) ;
} else
# endif
restore_fp_regs ( current - > thread . fp_regs . fprs ) ;
}
2005-04-16 15:20:36 -07:00
/* Returns non-zero on fault. */
static int save_sigregs ( struct pt_regs * regs , _sigregs __user * sregs )
{
2006-09-20 15:59:39 +02:00
_sigregs user_sregs ;
2005-04-16 15:20:36 -07:00
/* Copy a 'clean' PSW mask to the user to avoid leaking
information about whether PER is currently on . */
2013-09-24 09:14:56 +02:00
user_sregs . regs . psw . mask = PSW_USER_BITS |
2013-10-16 09:58:01 +02:00
( regs - > psw . mask & ( PSW_MASK_USER | PSW_MASK_RI ) ) ;
2006-10-04 20:01:58 +02:00
user_sregs . regs . psw . addr = regs - > psw . addr ;
memcpy ( & user_sregs . regs . gprs , & regs - > gprs , sizeof ( sregs - > regs . gprs ) ) ;
2006-09-20 15:59:39 +02:00
memcpy ( & user_sregs . regs . acrs , current - > thread . acrs ,
2013-10-15 16:08:34 +02:00
sizeof ( user_sregs . regs . acrs ) ) ;
2006-09-20 15:59:39 +02:00
memcpy ( & user_sregs . fpregs , & current - > thread . fp_regs ,
2013-10-15 16:08:34 +02:00
sizeof ( user_sregs . fpregs ) ) ;
2013-10-14 13:34:28 +02:00
if ( __copy_to_user ( sregs , & user_sregs , sizeof ( _sigregs ) ) )
return - EFAULT ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
static int restore_sigregs ( struct pt_regs * regs , _sigregs __user * sregs )
{
2006-09-20 15:59:39 +02:00
_sigregs user_sregs ;
2005-04-16 15:20:36 -07:00
/* Alwys make any pending restarted system call return -EINTR */
current_thread_info ( ) - > restart_block . fn = do_no_restart_syscall ;
2013-10-15 16:08:34 +02:00
if ( __copy_from_user ( & user_sregs , sregs , sizeof ( user_sregs ) ) )
2013-10-14 13:34:28 +02:00
return - EFAULT ;
2013-10-15 16:08:34 +02:00
2013-10-16 09:58:01 +02:00
if ( ! is_ri_task ( current ) & & ( user_sregs . regs . psw . mask & PSW_MASK_RI ) )
return - EINVAL ;
2013-10-15 16:08:34 +02:00
/* Loading the floating-point-control word can fail. Do that first. */
if ( restore_fp_ctl ( & user_sregs . fpregs . fpc ) )
return - EINVAL ;
2013-09-24 09:14:56 +02:00
/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
2013-11-19 12:26:09 +01:00
regs - > psw . mask = ( regs - > psw . mask & ~ ( PSW_MASK_USER | PSW_MASK_RI ) ) |
2013-10-16 09:58:01 +02:00
( user_sregs . regs . psw . mask & ( PSW_MASK_USER | PSW_MASK_RI ) ) ;
2012-11-07 10:44:08 +01:00
/* Check for invalid user address space control. */
2013-09-24 09:14:56 +02:00
if ( ( regs - > psw . mask & PSW_MASK_ASC ) = = PSW_ASC_HOME )
regs - > psw . mask = PSW_ASC_PRIMARY |
2012-11-07 10:44:08 +01:00
( regs - > psw . mask & ~ PSW_MASK_ASC ) ;
2011-10-30 15:16:51 +01:00
/* Check for invalid amode */
if ( regs - > psw . mask & PSW_MASK_EA )
regs - > psw . mask | = PSW_MASK_BA ;
regs - > psw . addr = user_sregs . regs . psw . addr ;
2006-10-04 20:01:58 +02:00
memcpy ( & regs - > gprs , & user_sregs . regs . gprs , sizeof ( sregs - > regs . gprs ) ) ;
2006-09-20 15:59:39 +02:00
memcpy ( & current - > thread . acrs , & user_sregs . regs . acrs ,
2013-10-15 16:08:34 +02:00
sizeof ( current - > thread . acrs ) ) ;
2005-04-16 15:20:36 -07:00
2006-09-20 15:59:39 +02:00
memcpy ( & current - > thread . fp_regs , & user_sregs . fpregs ,
2013-10-15 16:08:34 +02:00
sizeof ( current - > thread . fp_regs ) ) ;
2005-04-16 15:20:36 -07:00
2014-04-15 12:55:07 +02:00
clear_pt_regs_flag ( regs , PIF_SYSCALL ) ; /* No longer in a system call */
2005-04-16 15:20:36 -07:00
return 0 ;
}
2014-10-06 17:53:53 +02:00
/* Returns non-zero on fault. */
static int save_sigregs_ext ( struct pt_regs * regs ,
_sigregs_ext __user * sregs_ext )
{
# ifdef CONFIG_64BIT
__u64 vxrs [ __NUM_VXRS_LOW ] ;
int i ;
/* Save vector registers to signal stack */
if ( current - > thread . vxrs ) {
for ( i = 0 ; i < __NUM_VXRS_LOW ; i + + )
vxrs [ i ] = * ( ( __u64 * ) ( current - > thread . vxrs + i ) + 1 ) ;
if ( __copy_to_user ( & sregs_ext - > vxrs_low , vxrs ,
sizeof ( sregs_ext - > vxrs_low ) ) | |
__copy_to_user ( & sregs_ext - > vxrs_high ,
current - > thread . vxrs + __NUM_VXRS_LOW ,
sizeof ( sregs_ext - > vxrs_high ) ) )
return - EFAULT ;
}
# endif
return 0 ;
}
static int restore_sigregs_ext ( struct pt_regs * regs ,
_sigregs_ext __user * sregs_ext )
{
# ifdef CONFIG_64BIT
__u64 vxrs [ __NUM_VXRS_LOW ] ;
int i ;
/* Restore vector registers from signal stack */
if ( current - > thread . vxrs ) {
if ( __copy_from_user ( vxrs , & sregs_ext - > vxrs_low ,
sizeof ( sregs_ext - > vxrs_low ) ) | |
__copy_from_user ( current - > thread . vxrs + __NUM_VXRS_LOW ,
& sregs_ext - > vxrs_high ,
sizeof ( sregs_ext - > vxrs_high ) ) )
return - EFAULT ;
for ( i = 0 ; i < __NUM_VXRS_LOW ; i + + )
* ( ( __u64 * ) ( current - > thread . vxrs + i ) + 1 ) = vxrs [ i ] ;
}
# endif
return 0 ;
}
2009-01-14 14:14:36 +01:00
SYSCALL_DEFINE0 ( sigreturn )
2005-04-16 15:20:36 -07:00
{
2007-04-27 16:01:40 +02:00
struct pt_regs * regs = task_pt_regs ( current ) ;
2014-10-06 17:53:53 +02:00
struct sigframe __user * frame =
( struct sigframe __user * ) regs - > gprs [ 15 ] ;
2005-04-16 15:20:36 -07:00
sigset_t set ;
if ( __copy_from_user ( & set . sig , & frame - > sc . oldmask , _SIGMASK_COPY_SIZE ) )
goto badframe ;
2011-08-03 16:44:26 +02:00
set_current_blocked ( & set ) ;
2005-04-16 15:20:36 -07:00
if ( restore_sigregs ( regs , & frame - > sregs ) )
goto badframe ;
2014-10-06 17:53:53 +02:00
if ( restore_sigregs_ext ( regs , & frame - > sregs_ext ) )
goto badframe ;
load_sigregs ( ) ;
2005-04-16 15:20:36 -07:00
return regs - > gprs [ 2 ] ;
badframe :
force_sig ( SIGSEGV , current ) ;
return 0 ;
}
2009-01-14 14:14:36 +01:00
SYSCALL_DEFINE0 ( rt_sigreturn )
2005-04-16 15:20:36 -07:00
{
2007-04-27 16:01:40 +02:00
struct pt_regs * regs = task_pt_regs ( current ) ;
2014-10-06 17:53:53 +02:00
struct rt_sigframe __user * frame =
( struct rt_sigframe __user * ) regs - > gprs [ 15 ] ;
2005-04-16 15:20:36 -07:00
sigset_t set ;
if ( __copy_from_user ( & set . sig , & frame - > uc . uc_sigmask , sizeof ( set ) ) )
goto badframe ;
2011-08-03 16:44:26 +02:00
set_current_blocked ( & set ) ;
2014-10-06 17:53:53 +02:00
if ( restore_altstack ( & frame - > uc . uc_stack ) )
goto badframe ;
2005-04-16 15:20:36 -07:00
if ( restore_sigregs ( regs , & frame - > uc . uc_mcontext ) )
goto badframe ;
2014-10-06 17:53:53 +02:00
if ( restore_sigregs_ext ( regs , & frame - > uc . uc_mcontext_ext ) )
2006-01-06 00:19:10 -08:00
goto badframe ;
2014-10-06 17:53:53 +02:00
load_sigregs ( ) ;
2005-04-16 15:20:36 -07:00
return regs - > gprs [ 2 ] ;
badframe :
force_sig ( SIGSEGV , current ) ;
return 0 ;
}
/*
* Determine which stack to use . .
*/
static inline void __user *
get_sigframe ( struct k_sigaction * ka , struct pt_regs * regs , size_t frame_size )
{
unsigned long sp ;
/* Default to using normal stack */
sp = regs - > gprs [ 15 ] ;
2008-04-17 07:45:57 +02:00
/* Overflow on alternate signal stack gives SIGSEGV. */
if ( on_sig_stack ( sp ) & & ! on_sig_stack ( ( sp - frame_size ) & - 8UL ) )
return ( void __user * ) - 1UL ;
2005-04-16 15:20:36 -07:00
/* This is the X/Open sanctioned signal stack switching. */
if ( ka - > sa . sa_flags & SA_ONSTACK ) {
if ( ! sas_ss_flags ( sp ) )
sp = current - > sas_ss_sp + current - > sas_ss_size ;
}
return ( void __user * ) ( ( sp - frame_size ) & - 8ul ) ;
}
static inline int map_signal ( int sig )
{
if ( current_thread_info ( ) - > exec_domain
& & current_thread_info ( ) - > exec_domain - > signal_invmap
& & sig < 32 )
return current_thread_info ( ) - > exec_domain - > signal_invmap [ sig ] ;
else
return sig ;
}
2006-02-01 03:06:38 -08:00
static int setup_frame ( int sig , struct k_sigaction * ka ,
sigset_t * set , struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2014-10-06 17:53:53 +02:00
struct sigframe __user * frame ;
struct sigcontext sc ;
unsigned long restorer ;
size_t frame_size ;
/*
* gprs_high are only present for a 31 - bit task running on
* a 64 - bit kernel ( see compat_signal . c ) but the space for
* gprs_high need to be allocated if vector registers are
* included in the signal frame on a 31 - bit system .
*/
frame_size = sizeof ( * frame ) - sizeof ( frame - > sregs_ext ) ;
if ( MACHINE_HAS_VX )
frame_size + = sizeof ( frame - > sregs_ext ) ;
frame = get_sigframe ( ka , regs , frame_size ) ;
2008-04-17 07:45:57 +02:00
if ( frame = = ( void __user * ) - 1UL )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2008-04-17 07:45:57 +02:00
2014-10-06 17:53:53 +02:00
/* Set up backchain. */
if ( __put_user ( regs - > gprs [ 15 ] , ( addr_t __user * ) frame ) )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
2014-10-06 17:53:53 +02:00
/* Create struct sigcontext on the signal stack */
memcpy ( & sc . oldmask , & set - > sig , _SIGMASK_COPY_SIZE ) ;
sc . sregs = ( _sigregs __user __force * ) & frame - > sregs ;
if ( __copy_to_user ( & frame - > sc , & sc , sizeof ( frame - > sc ) ) )
return - EFAULT ;
/* Store registers needed to create the signal frame */
store_sigregs ( ) ;
/* Create _sigregs on the signal stack */
2005-04-16 15:20:36 -07:00
if ( save_sigregs ( regs , & frame - > sregs ) )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2014-10-06 17:53:53 +02:00
/* Place signal number on stack to allow backtrace from handler. */
if ( __put_user ( regs - > gprs [ 2 ] , ( int __user * ) & frame - > signo ) )
return - EFAULT ;
/* Create _sigregs_ext on the signal stack */
if ( save_sigregs_ext ( regs , & frame - > sregs_ext ) )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
/* Set up to return from userspace. If provided, use a stub
already in userspace . */
if ( ka - > sa . sa_flags & SA_RESTORER ) {
2014-10-06 17:53:53 +02:00
restorer = ( unsigned long ) ka - > sa . sa_restorer | PSW_ADDR_AMODE ;
2005-04-16 15:20:36 -07:00
} else {
2014-10-06 17:53:53 +02:00
/* Signal frame without vector registers are short ! */
__u16 __user * svc = ( void * ) frame + frame_size - 2 ;
if ( __put_user ( S390_SYSCALL_OPCODE | __NR_sigreturn , svc ) )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2014-10-06 17:53:53 +02:00
restorer = ( unsigned long ) svc | PSW_ADDR_AMODE ;
2005-04-16 15:20:36 -07:00
}
/* Set up registers for signal handler */
2014-10-06 17:53:53 +02:00
regs - > gprs [ 14 ] = restorer ;
2005-04-16 15:20:36 -07:00
regs - > gprs [ 15 ] = ( unsigned long ) frame ;
2012-11-07 10:44:08 +01:00
/* Force default amode and default user address space control. */
regs - > psw . mask = PSW_MASK_EA | PSW_MASK_BA |
2013-09-24 09:14:56 +02:00
( PSW_USER_BITS & PSW_MASK_ASC ) |
2012-11-07 10:44:08 +01:00
( regs - > psw . mask & ~ PSW_MASK_ASC ) ;
2005-04-16 15:20:36 -07:00
regs - > psw . addr = ( unsigned long ) ka - > sa . sa_handler | PSW_ADDR_AMODE ;
regs - > gprs [ 2 ] = map_signal ( sig ) ;
regs - > gprs [ 3 ] = ( unsigned long ) & frame - > sc ;
/* We forgot to include these in the sigcontext.
To avoid breaking binary compatibility , they are passed as args . */
2011-12-27 11:27:18 +01:00
if ( sig = = SIGSEGV | | sig = = SIGBUS | | sig = = SIGILL | |
sig = = SIGTRAP | | sig = = SIGFPE ) {
/* set extra registers only for synchronous signals */
regs - > gprs [ 4 ] = regs - > int_code & 127 ;
regs - > gprs [ 5 ] = regs - > int_parm_long ;
regs - > gprs [ 6 ] = task_thread_info ( current ) - > last_break ;
}
2006-02-01 03:06:38 -08:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2014-07-13 22:21:03 +02:00
static int setup_rt_frame ( struct ksignal * ksig , sigset_t * set ,
struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2014-10-06 17:53:53 +02:00
struct rt_sigframe __user * frame ;
unsigned long uc_flags , restorer ;
size_t frame_size ;
frame_size = sizeof ( struct rt_sigframe ) - sizeof ( _sigregs_ext ) ;
/*
* gprs_high are only present for a 31 - bit task running on
* a 64 - bit kernel ( see compat_signal . c ) but the space for
* gprs_high need to be allocated if vector registers are
* included in the signal frame on a 31 - bit system .
*/
uc_flags = 0 ;
# ifdef CONFIG_64BIT
if ( MACHINE_HAS_VX ) {
frame_size + = sizeof ( _sigregs_ext ) ;
if ( current - > thread . vxrs )
uc_flags | = UC_VXRS ;
}
# endif
frame = get_sigframe ( & ksig - > ka , regs , frame_size ) ;
2008-04-17 07:45:57 +02:00
if ( frame = = ( void __user * ) - 1UL )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2008-04-17 07:45:57 +02:00
2014-10-06 17:53:53 +02:00
/* Set up backchain. */
if ( __put_user ( regs - > gprs [ 15 ] , ( addr_t __user * ) frame ) )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
/* Set up to return from userspace. If provided, use a stub
already in userspace . */
2014-07-13 22:21:03 +02:00
if ( ksig - > ka . sa . sa_flags & SA_RESTORER ) {
2014-10-06 17:53:53 +02:00
restorer = ( unsigned long )
2014-07-13 22:21:03 +02:00
ksig - > ka . sa . sa_restorer | PSW_ADDR_AMODE ;
2005-04-16 15:20:36 -07:00
} else {
2014-10-06 17:53:53 +02:00
__u16 __user * svc = & frame - > svc_insn ;
if ( __put_user ( S390_SYSCALL_OPCODE | __NR_rt_sigreturn , svc ) )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2014-10-06 17:53:53 +02:00
restorer = ( unsigned long ) svc | PSW_ADDR_AMODE ;
2005-04-16 15:20:36 -07:00
}
2014-10-06 17:53:53 +02:00
/* Create siginfo on the signal stack */
if ( copy_siginfo_to_user ( & frame - > info , & ksig - > info ) )
return - EFAULT ;
/* Store registers needed to create the signal frame */
store_sigregs ( ) ;
/* Create ucontext on the signal stack. */
if ( __put_user ( uc_flags , & frame - > uc . uc_flags ) | |
__put_user ( NULL , & frame - > uc . uc_link ) | |
__save_altstack ( & frame - > uc . uc_stack , regs - > gprs [ 15 ] ) | |
save_sigregs ( regs , & frame - > uc . uc_mcontext ) | |
__copy_to_user ( & frame - > uc . uc_sigmask , set , sizeof ( * set ) ) | |
save_sigregs_ext ( regs , & frame - > uc . uc_mcontext_ext ) )
2014-07-13 22:21:03 +02:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
/* Set up registers for signal handler */
2014-10-06 17:53:53 +02:00
regs - > gprs [ 14 ] = restorer ;
2005-04-16 15:20:36 -07:00
regs - > gprs [ 15 ] = ( unsigned long ) frame ;
2012-11-07 10:44:08 +01:00
/* Force default amode and default user address space control. */
regs - > psw . mask = PSW_MASK_EA | PSW_MASK_BA |
2013-09-24 09:14:56 +02:00
( PSW_USER_BITS & PSW_MASK_ASC ) |
2012-11-07 10:44:08 +01:00
( regs - > psw . mask & ~ PSW_MASK_ASC ) ;
2014-07-13 22:21:03 +02:00
regs - > psw . addr = ( unsigned long ) ksig - > ka . sa . sa_handler | PSW_ADDR_AMODE ;
2005-04-16 15:20:36 -07:00
2014-07-13 22:21:03 +02:00
regs - > gprs [ 2 ] = map_signal ( ksig - > sig ) ;
2005-04-16 15:20:36 -07:00
regs - > gprs [ 3 ] = ( unsigned long ) & frame - > info ;
regs - > gprs [ 4 ] = ( unsigned long ) & frame - > uc ;
2010-05-17 10:00:05 +02:00
regs - > gprs [ 5 ] = task_thread_info ( current ) - > last_break ;
2006-02-01 03:06:38 -08:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2014-07-13 22:21:03 +02:00
static void handle_signal ( struct ksignal * ksig , sigset_t * oldset ,
struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2006-02-01 03:06:38 -08:00
int ret ;
2005-04-16 15:20:36 -07:00
/* Set up the stack frame */
2014-07-13 22:21:03 +02:00
if ( ksig - > ka . sa . sa_flags & SA_SIGINFO )
ret = setup_rt_frame ( ksig , oldset , regs ) ;
2005-04-16 15:20:36 -07:00
else
2014-07-13 22:21:03 +02:00
ret = setup_frame ( ksig - > sig , & ksig - > ka , oldset , regs ) ;
signal_setup_done ( ret , ksig , test_thread_flag ( TIF_SINGLE_STEP ) ) ;
2005-04-16 15:20:36 -07:00
}
/*
* 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 .
*/
2006-02-01 03:06:38 -08:00
void do_signal ( struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2014-07-13 22:21:03 +02:00
struct ksignal ksig ;
2012-05-02 09:59:21 -04:00
sigset_t * oldset = sigmask_to_save ( ) ;
2005-04-16 15:20:36 -07:00
2011-10-30 15:16:47 +01:00
/*
* Get signal to deliver . When running under ptrace , at this point
* the debugger may change all our registers , including the system
* call information .
*/
2011-10-30 15:16:49 +01:00
current_thread_info ( ) - > system_call =
2014-04-15 12:55:07 +02:00
test_pt_regs_flag ( regs , PIF_SYSCALL ) ? regs - > int_code : 0 ;
2005-04-16 15:20:36 -07:00
2014-07-13 22:21:03 +02:00
if ( get_signal ( & ksig ) ) {
2005-04-16 15:20:36 -07:00
/* Whee! Actually deliver the signal. */
2011-10-30 15:16:49 +01:00
if ( current_thread_info ( ) - > system_call ) {
2011-12-27 11:27:18 +01:00
regs - > int_code = current_thread_info ( ) - > system_call ;
2011-10-30 15:16:47 +01:00
/* Check for system call restarting. */
switch ( regs - > gprs [ 2 ] ) {
case - ERESTART_RESTARTBLOCK :
case - ERESTARTNOHAND :
regs - > gprs [ 2 ] = - EINTR ;
break ;
case - ERESTARTSYS :
2014-07-13 22:21:03 +02:00
if ( ! ( ksig . ka . sa . sa_flags & SA_RESTART ) ) {
2011-10-30 15:16:47 +01:00
regs - > gprs [ 2 ] = - EINTR ;
break ;
}
/* fallthrough */
case - ERESTARTNOINTR :
regs - > gprs [ 2 ] = regs - > orig_gpr2 ;
2011-10-30 15:16:48 +01:00
regs - > psw . addr =
__rewind_psw ( regs - > psw ,
2011-12-27 11:27:18 +01:00
regs - > int_code > > 16 ) ;
2011-10-30 15:16:47 +01:00
break ;
}
}
2011-12-01 13:32:15 +01:00
/* No longer in a system call */
2014-04-15 12:55:07 +02:00
clear_pt_regs_flag ( regs , PIF_SYSCALL ) ;
2011-10-30 15:16:47 +01:00
2012-05-21 23:42:15 -04:00
if ( is_compat_task ( ) )
2014-07-13 22:21:03 +02:00
handle_signal32 ( & ksig , oldset , regs ) ;
2012-05-21 23:42:15 -04:00
else
2014-07-13 22:21:03 +02:00
handle_signal ( & ksig , oldset , regs ) ;
2006-02-01 03:06:38 -08:00
return ;
}
2011-10-30 15:16:47 +01:00
/* No handlers present - check for system call restart */
2014-04-15 12:55:07 +02:00
clear_pt_regs_flag ( regs , PIF_SYSCALL ) ;
2011-10-30 15:16:49 +01:00
if ( current_thread_info ( ) - > system_call ) {
2011-12-27 11:27:18 +01:00
regs - > int_code = current_thread_info ( ) - > system_call ;
2011-10-30 15:16:47 +01:00
switch ( regs - > gprs [ 2 ] ) {
case - ERESTART_RESTARTBLOCK :
/* Restart with sys_restart_syscall */
2011-12-27 11:27:18 +01:00
regs - > int_code = __NR_restart_syscall ;
2011-10-30 15:16:47 +01:00
/* fallthrough */
case - ERESTARTNOHAND :
case - ERESTARTSYS :
case - ERESTARTNOINTR :
/* Restart system call with magic TIF bit. */
regs - > gprs [ 2 ] = regs - > orig_gpr2 ;
2014-04-15 12:55:07 +02:00
set_pt_regs_flag ( regs , PIF_SYSCALL ) ;
2012-11-21 16:36:27 +01:00
if ( test_thread_flag ( TIF_SINGLE_STEP ) )
2014-04-15 12:55:07 +02:00
clear_pt_regs_flag ( regs , PIF_PER_TRAP ) ;
2011-10-30 15:16:49 +01:00
break ;
2011-10-30 15:16:47 +01:00
}
}
2006-02-01 03:06:38 -08:00
/*
* If there ' s no signal to deliver , we just put the saved sigmask back .
*/
2012-05-21 23:33:55 -04:00
restore_saved_sigmask ( ) ;
2005-04-16 15:20:36 -07:00
}
2008-10-10 21:33:20 +02:00
void do_notify_resume ( struct pt_regs * regs )
{
clear_thread_flag ( TIF_NOTIFY_RESUME ) ;
tracehook_notify_resume ( regs ) ;
}