2005-04-16 15:20:36 -07:00
/*
* linux / arch / m32r / kernel / signal . c
*
* Copyright ( c ) 2003 Hitoshi Yamamoto
*
* Taken from i386 version .
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*
* 1997 - 11 - 28 Modified for POSIX .1 b signals by Richard Henderson
* 2000 - 06 - 20 Pentium III FXSR , SSE support by Gareth Hughes
*/
# 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/unistd.h>
# include <linux/stddef.h>
# include <linux/personality.h>
2009-09-09 08:30:21 +01:00
# include <linux/tracehook.h>
2005-04-16 15:20:36 -07:00
# include <asm/cacheflush.h>
# include <asm/ucontext.h>
2016-12-24 11:46:01 -08:00
# include <linux/uaccess.h>
2005-04-16 15:20:36 -07:00
# define DEBUG_SIG 0
/*
* Do a signal return ; undo the signal stack .
*/
struct rt_sigframe
{
int sig ;
2006-10-11 17:24:45 +01:00
struct siginfo __user * pinfo ;
void __user * puc ;
2005-04-16 15:20:36 -07:00
struct siginfo info ;
struct ucontext uc ;
// struct _fpstate fpstate;
} ;
static int
restore_sigcontext ( struct pt_regs * regs , struct sigcontext __user * sc ,
int * r0_p )
{
unsigned int err = 0 ;
/* Always make any pending restarted system calls return -EINTR */
2015-02-12 15:01:14 -08:00
current - > restart_block . fn = do_no_restart_syscall ;
2005-04-16 15:20:36 -07:00
# define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
COPY ( r4 ) ;
COPY ( r5 ) ;
COPY ( r6 ) ;
COPY ( pt_regs ) ;
/* COPY(r0); Skip r0 */
COPY ( r1 ) ;
COPY ( r2 ) ;
COPY ( r3 ) ;
COPY ( r7 ) ;
COPY ( r8 ) ;
COPY ( r9 ) ;
COPY ( r10 ) ;
COPY ( r11 ) ;
COPY ( r12 ) ;
COPY ( acc0h ) ;
COPY ( acc0l ) ;
2007-02-10 01:43:35 -08:00
COPY ( acc1h ) ; /* ISA_DSP_LEVEL2 only */
COPY ( acc1l ) ; /* ISA_DSP_LEVEL2 only */
2005-04-16 15:20:36 -07:00
COPY ( psw ) ;
COPY ( bpc ) ;
COPY ( bbpsw ) ;
COPY ( bbpc ) ;
COPY ( spu ) ;
COPY ( fp ) ;
COPY ( lr ) ;
COPY ( spi ) ;
# undef COPY
regs - > syscall_nr = - 1 ; /* disable syscall checks */
err | = __get_user ( * r0_p , & sc - > sc_r0 ) ;
return err ;
}
asmlinkage int
sys_rt_sigreturn ( unsigned long r0 , unsigned long r1 ,
unsigned long r2 , unsigned long r3 , unsigned long r4 ,
2006-02-24 13:03:51 -08:00
unsigned long r5 , unsigned long r6 , struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2006-02-24 13:03:51 -08:00
struct rt_sigframe __user * frame = ( struct rt_sigframe __user * ) regs - > spu ;
2005-04-16 15:20:36 -07:00
sigset_t set ;
int result ;
if ( ! access_ok ( VERIFY_READ , frame , sizeof ( * frame ) ) )
goto badframe ;
if ( __copy_from_user ( & set , & frame - > uc . uc_sigmask , sizeof ( set ) ) )
goto badframe ;
2012-05-11 10:57:59 +10:00
set_current_blocked ( & set ) ;
2005-04-16 15:20:36 -07:00
2006-02-24 13:03:51 -08:00
if ( restore_sigcontext ( regs , & frame - > uc . uc_mcontext , & result ) )
2005-04-16 15:20:36 -07:00
goto badframe ;
2012-12-23 02:55:20 -05:00
if ( restore_altstack ( & frame - > uc . uc_stack ) )
2005-04-16 15:20:36 -07:00
goto badframe ;
return result ;
badframe :
force_sig ( SIGSEGV , current ) ;
return 0 ;
}
/*
* Set up a signal frame .
*/
static int
setup_sigcontext ( struct sigcontext __user * sc , struct pt_regs * regs ,
unsigned long mask )
{
int err = 0 ;
# define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
COPY ( r4 ) ;
COPY ( r5 ) ;
COPY ( r6 ) ;
COPY ( pt_regs ) ;
COPY ( r0 ) ;
COPY ( r1 ) ;
COPY ( r2 ) ;
COPY ( r3 ) ;
COPY ( r7 ) ;
COPY ( r8 ) ;
COPY ( r9 ) ;
COPY ( r10 ) ;
COPY ( r11 ) ;
COPY ( r12 ) ;
COPY ( acc0h ) ;
COPY ( acc0l ) ;
2007-02-10 01:43:35 -08:00
COPY ( acc1h ) ; /* ISA_DSP_LEVEL2 only */
COPY ( acc1l ) ; /* ISA_DSP_LEVEL2 only */
2005-04-16 15:20:36 -07:00
COPY ( psw ) ;
COPY ( bpc ) ;
COPY ( bbpsw ) ;
COPY ( bbpc ) ;
COPY ( spu ) ;
COPY ( fp ) ;
COPY ( lr ) ;
COPY ( spi ) ;
# undef COPY
err | = __put_user ( mask , & sc - > oldmask ) ;
return err ;
}
/*
* Determine which stack to use . .
*/
static inline void __user *
2014-03-05 15:27:15 +01:00
get_sigframe ( struct ksignal * ksig , unsigned long sp , size_t frame_size )
2005-04-16 15:20:36 -07:00
{
2014-03-05 15:27:15 +01:00
return ( void __user * ) ( ( sigsp ( sp , ksig ) - frame_size ) & - 8ul ) ;
2005-04-16 15:20:36 -07:00
}
2013-10-07 13:54:22 +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
{
struct rt_sigframe __user * frame ;
int err = 0 ;
2014-07-13 17:18:15 +02:00
int sig = ksig - > sig ;
2005-04-16 15:20:36 -07:00
2014-03-05 15:27:15 +01:00
frame = get_sigframe ( ksig , regs - > spu , sizeof ( * frame ) ) ;
2005-04-16 15:20:36 -07:00
if ( ! access_ok ( VERIFY_WRITE , frame , sizeof ( * frame ) ) )
2013-10-07 13:54:22 +02:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
2014-07-13 17:18:15 +02:00
err | = __put_user ( sig , & frame - > sig ) ;
2005-04-16 15:20:36 -07:00
if ( err )
2013-10-07 13:54:22 +02:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
err | = __put_user ( & frame - > info , & frame - > pinfo ) ;
err | = __put_user ( & frame - > uc , & frame - > puc ) ;
2013-10-07 13:54:22 +02:00
err | = copy_siginfo_to_user ( & frame - > info , & ksig - > info ) ;
2005-04-16 15:20:36 -07:00
if ( err )
2013-10-07 13:54:22 +02:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
/* Create the ucontext. */
err | = __put_user ( 0 , & frame - > uc . uc_flags ) ;
err | = __put_user ( 0 , & frame - > uc . uc_link ) ;
2012-12-23 02:55:20 -05:00
err | = __save_altstack ( & frame - > uc . uc_stack , regs - > spu ) ;
2005-04-16 15:20:36 -07:00
err | = setup_sigcontext ( & frame - > uc . uc_mcontext , regs , set - > sig [ 0 ] ) ;
err | = __copy_to_user ( & frame - > uc . uc_sigmask , set , sizeof ( * set ) ) ;
if ( err )
2013-10-07 13:54:22 +02:00
return - EFAULT ;
2005-04-16 15:20:36 -07:00
/* Set up to return from userspace. */
2013-10-07 13:54:22 +02:00
regs - > lr = ( unsigned long ) ksig - > ka . sa . sa_restorer ;
2005-04-16 15:20:36 -07:00
/* Set up registers for signal handler */
regs - > spu = ( unsigned long ) frame ;
2014-07-13 17:18:15 +02:00
regs - > r0 = sig ; /* Arg for signal handler */
2005-04-16 15:20:36 -07:00
regs - > r1 = ( unsigned long ) & frame - > info ;
regs - > r2 = ( unsigned long ) & frame - > uc ;
2013-10-07 13:54:22 +02:00
regs - > bpc = ( unsigned long ) ksig - > ka . sa . sa_handler ;
2005-04-16 15:20:36 -07:00
# if DEBUG_SIG
printk ( " SIG deliver (%s:%d): sp=%p pc=%p \n " ,
current - > comm , current - > pid , frame , regs - > pc ) ;
# endif
2010-09-24 06:23:57 +01:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2010-09-24 06:24:53 +01:00
static int prev_insn ( struct pt_regs * regs )
{
u16 inst ;
2010-10-15 21:17:09 -04:00
if ( get_user ( inst , ( u16 __user * ) ( regs - > bpc - 2 ) ) )
2010-09-24 06:24:53 +01:00
return - EFAULT ;
if ( ( inst & 0xfff0 ) = = 0x10f0 ) /* trap ? */
regs - > bpc - = 2 ;
else
regs - > bpc - = 4 ;
regs - > syscall_nr = - 1 ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
/*
* OK , we ' re invoking a handler
*/
2012-05-21 23:42:15 -04:00
static void
2013-10-07 13:54:22 +02:00
handle_signal ( struct ksignal * ksig , struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2013-10-07 13:54:22 +02:00
int ret ;
2005-04-16 15:20:36 -07:00
/* Are we from a system call? */
if ( regs - > syscall_nr > = 0 ) {
/* If so, check system call restarting.. */
switch ( regs - > r0 ) {
case - ERESTART_RESTARTBLOCK :
case - ERESTARTNOHAND :
regs - > r0 = - EINTR ;
break ;
case - ERESTARTSYS :
2013-10-07 13:54:22 +02:00
if ( ! ( ksig - > ka . sa . sa_flags & SA_RESTART ) ) {
2005-04-16 15:20:36 -07:00
regs - > r0 = - EINTR ;
break ;
}
/* fallthrough */
case - ERESTARTNOINTR :
regs - > r0 = regs - > orig_r0 ;
2010-09-24 06:24:53 +01:00
if ( prev_insn ( regs ) < 0 )
2012-07-17 15:47:59 -07:00
return ;
2005-04-16 15:20:36 -07:00
}
}
/* Set up the stack frame */
2013-10-07 13:54:22 +02:00
ret = setup_rt_frame ( ksig , sigmask_to_save ( ) , regs ) ;
2005-04-16 15:20:36 -07:00
2013-10-07 13:54:22 +02:00
signal_setup_done ( ret , ksig , 0 ) ;
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 .
*/
2010-09-24 06:23:57 +01:00
static void do_signal ( struct pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2013-10-07 13:54:22 +02:00
struct ksignal ksig ;
2005-04-16 15:20:36 -07:00
/*
* We want the common case to go fast , which
* is why we may in certain cases get here from
* kernel mode . Just return without doing anything
* if so .
*/
if ( ! user_mode ( regs ) )
2010-09-24 06:23:57 +01:00
return ;
2005-04-16 15:20:36 -07:00
2013-10-07 13:54:22 +02:00
if ( get_signal ( & ksig ) ) {
2007-10-20 01:14:39 +02:00
/* Re-enable any watchpoints before delivering the
2005-04-16 15:20:36 -07:00
* signal to user space . The processor register will
* have been cleared if the watchpoint triggered
* inside the kernel .
*/
/* Whee! Actually deliver the signal. */
2013-10-07 13:54:22 +02:00
handle_signal ( & ksig , regs ) ;
2010-09-24 06:23:57 +01:00
return ;
2005-04-16 15:20:36 -07:00
}
/* Did we come from a system call? */
if ( regs - > syscall_nr > = 0 ) {
/* Restart the system call - no handlers present */
if ( regs - > r0 = = - ERESTARTNOHAND | |
regs - > r0 = = - ERESTARTSYS | |
regs - > r0 = = - ERESTARTNOINTR ) {
regs - > r0 = regs - > orig_r0 ;
2010-09-24 06:24:53 +01:00
prev_insn ( regs ) ;
2010-09-24 06:22:30 +01:00
} else if ( regs - > r0 = = - ERESTART_RESTARTBLOCK ) {
2005-04-16 15:20:36 -07:00
regs - > r0 = regs - > orig_r0 ;
regs - > r7 = __NR_restart_syscall ;
2010-09-24 06:24:53 +01:00
prev_insn ( regs ) ;
2005-04-16 15:20:36 -07:00
}
}
2012-05-21 23:33:55 -04:00
restore_saved_sigmask ( ) ;
2005-04-16 15:20:36 -07:00
}
/*
* notification of userspace execution resumption
* - triggered by current - > work . notify_resume
*/
2010-09-24 06:20:35 +01:00
void do_notify_resume ( struct pt_regs * regs , __u32 thread_info_flags )
2005-04-16 15:20:36 -07:00
{
/* Pending single-step? */
if ( thread_info_flags & _TIF_SINGLESTEP )
clear_thread_flag ( TIF_SINGLESTEP ) ;
/* deal with pending signal delivery */
if ( thread_info_flags & _TIF_SIGPENDING )
2010-09-24 06:20:35 +01:00
do_signal ( regs ) ;
2005-04-16 15:20:36 -07:00
2009-09-02 09:14:16 +01:00
if ( thread_info_flags & _TIF_NOTIFY_RESUME ) {
clear_thread_flag ( TIF_NOTIFY_RESUME ) ;
tracehook_notify_resume ( regs ) ;
}
2005-04-16 15:20:36 -07:00
}