2005-04-17 02:20:36 +04:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
* Copyright ( C ) 1994 - 2000 Ralf Baechle
* Copyright ( C ) 1999 , 2000 Silicon Graphics , Inc .
2013-12-12 20:57:19 +04:00
* Copyright ( C ) 2014 , Imagination Technologies Ltd .
2005-04-17 02:20:36 +04:00
*/
2005-06-15 17:00:12 +04:00
# include <linux/cache.h>
2013-05-29 03:07:19 +04:00
# include <linux/context_tracking.h>
2011-07-27 14:44:47 +04:00
# include <linux/irqflags.h>
2005-04-17 02:20:36 +04:00
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/personality.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/compiler.h>
2009-02-08 19:00:26 +03:00
# include <linux/syscalls.h>
2007-04-16 18:19:44 +04:00
# include <linux/uaccess.h>
2009-09-09 11:30:21 +04:00
# include <linux/tracehook.h>
2005-04-17 02:20:36 +04:00
2005-05-31 15:49:19 +04:00
# include <asm/abi.h>
2005-04-17 02:20:36 +04:00
# include <asm/asm.h>
# include <linux/bitops.h>
# include <asm/cacheflush.h>
# include <asm/fpu.h>
# include <asm/sim.h>
# include <asm/ucontext.h>
# include <asm/cpu-features.h>
2005-06-15 17:00:12 +04:00
# include <asm/war.h>
2010-02-19 03:13:05 +03:00
# include <asm/vdso.h>
2012-03-28 21:30:02 +04:00
# include <asm/dsp.h>
2013-03-25 22:21:11 +04:00
# include <asm/inst.h>
2005-04-17 02:20:36 +04:00
# include "signal-common.h"
2015-07-27 22:58:15 +03:00
static int ( * save_fp_context ) ( void __user * sc ) ;
static int ( * restore_fp_context ) ( void __user * sc ) ;
2009-11-24 22:35:41 +03:00
2007-02-13 04:31:48 +03:00
struct sigframe {
u32 sf_ass [ 4 ] ; /* argument save space for o32 */
2010-02-19 03:13:05 +03:00
u32 sf_pad [ 2 ] ; /* Was: signal trampoline */
2007-02-13 04:31:48 +03:00
struct sigcontext sf_sc ;
sigset_t sf_mask ;
} ;
2007-02-05 17:24:21 +03:00
struct rt_sigframe {
u32 rs_ass [ 4 ] ; /* argument save space for o32 */
2010-02-19 03:13:05 +03:00
u32 rs_pad [ 2 ] ; /* Was: signal trampoline */
2007-02-05 17:24:21 +03:00
struct siginfo rs_info ;
struct ucontext rs_uc ;
} ;
2014-01-27 19:23:02 +04:00
/*
* Thread saved context copy to / from a signal context presumed to be on the
* user stack , and therefore accessed with appropriate macros from uaccess . h .
*/
2015-07-27 22:58:15 +03:00
static int copy_fp_to_sigcontext ( void __user * sc )
2014-01-27 19:23:02 +04:00
{
2015-07-27 22:58:15 +03:00
struct mips_abi * abi = current - > thread . abi ;
uint64_t __user * fpregs = sc + abi - > off_sc_fpregs ;
uint32_t __user * csr = sc + abi - > off_sc_fpc_csr ;
2014-01-27 19:23:02 +04:00
int i ;
int err = 0 ;
2014-01-27 19:23:04 +04:00
for ( i = 0 ; i < NUM_FPU_REGS ; i + + ) {
2014-01-27 19:23:02 +04:00
err | =
__put_user ( get_fpr64 ( & current - > thread . fpu . fpr [ i ] , 0 ) ,
2015-07-27 22:58:15 +03:00
& fpregs [ i ] ) ;
2014-01-27 19:23:02 +04:00
}
2015-07-27 22:58:15 +03:00
err | = __put_user ( current - > thread . fpu . fcr31 , csr ) ;
2014-01-27 19:23:02 +04:00
return err ;
}
2015-07-27 22:58:15 +03:00
static int copy_fp_from_sigcontext ( void __user * sc )
2014-01-27 19:23:02 +04:00
{
2015-07-27 22:58:15 +03:00
struct mips_abi * abi = current - > thread . abi ;
uint64_t __user * fpregs = sc + abi - > off_sc_fpregs ;
uint32_t __user * csr = sc + abi - > off_sc_fpc_csr ;
2014-01-27 19:23:02 +04:00
int i ;
int err = 0 ;
u64 fpr_val ;
2014-01-27 19:23:04 +04:00
for ( i = 0 ; i < NUM_FPU_REGS ; i + + ) {
2015-07-27 22:58:15 +03:00
err | = __get_user ( fpr_val , & fpregs [ i ] ) ;
2014-01-27 19:23:02 +04:00
set_fpr64 ( & current - > thread . fpu . fpr [ i ] , 0 , fpr_val ) ;
}
2015-07-27 22:58:15 +03:00
err | = __get_user ( current - > thread . fpu . fcr31 , csr ) ;
2014-01-27 19:23:02 +04:00
return err ;
}
2015-07-27 22:58:15 +03:00
/*
* Wrappers for the assembly _ { save , restore } _fp_context functions .
*/
static int save_hw_fp_context ( void __user * sc )
{
struct mips_abi * abi = current - > thread . abi ;
uint64_t __user * fpregs = sc + abi - > off_sc_fpregs ;
uint32_t __user * csr = sc + abi - > off_sc_fpc_csr ;
return _save_fp_context ( fpregs , csr ) ;
}
static int restore_hw_fp_context ( void __user * sc )
{
struct mips_abi * abi = current - > thread . abi ;
uint64_t __user * fpregs = sc + abi - > off_sc_fpregs ;
uint32_t __user * csr = sc + abi - > off_sc_fpc_csr ;
return _restore_fp_context ( fpregs , csr ) ;
}
2007-02-05 17:24:20 +03:00
/*
* Helper routines
*/
2015-07-27 22:58:15 +03:00
static int protected_save_fp_context ( void __user * sc )
2007-04-16 18:19:44 +04:00
{
2015-07-27 22:58:15 +03:00
struct mips_abi * abi = current - > thread . abi ;
uint64_t __user * fpregs = sc + abi - > off_sc_fpregs ;
uint32_t __user * csr = sc + abi - > off_sc_fpc_csr ;
2015-07-27 22:58:16 +03:00
uint32_t __user * used_math = sc + abi - > off_sc_used_math ;
unsigned int used ;
2007-04-16 18:19:44 +04:00
int err ;
2015-07-27 22:58:13 +03:00
2015-07-27 22:58:16 +03:00
used = ! ! used_math ( ) ;
err = __put_user ( used , used_math ) ;
if ( err | | ! used )
return err ;
2015-07-27 22:58:13 +03:00
/*
* EVA does not have userland equivalents of ldc1 or sdc1 , so
* save to the kernel FP context & copy that to userland below .
*/
if ( config_enabled ( CONFIG_EVA ) )
lose_fpu ( 1 ) ;
2007-04-16 18:19:44 +04:00
while ( 1 ) {
lock_fpu_owner ( ) ;
2014-01-27 19:23:03 +04:00
if ( is_fpu_owner ( ) ) {
err = save_fp_context ( sc ) ;
unlock_fpu_owner ( ) ;
} else {
unlock_fpu_owner ( ) ;
err = copy_fp_to_sigcontext ( sc ) ;
}
2007-04-16 18:19:44 +04:00
if ( likely ( ! err ) )
break ;
/* touch the sigcontext and try again */
2015-07-27 22:58:15 +03:00
err = __put_user ( 0 , & fpregs [ 0 ] ) |
__put_user ( 0 , & fpregs [ 31 ] ) |
__put_user ( 0 , csr ) ;
2007-04-16 18:19:44 +04:00
if ( err )
break ; /* really bad sigcontext */
}
2015-07-27 22:58:13 +03:00
2007-04-16 18:19:44 +04:00
return err ;
}
2015-07-27 22:58:15 +03:00
static int protected_restore_fp_context ( void __user * sc )
2007-04-16 18:19:44 +04:00
{
2015-07-27 22:58:15 +03:00
struct mips_abi * abi = current - > thread . abi ;
uint64_t __user * fpregs = sc + abi - > off_sc_fpregs ;
uint32_t __user * csr = sc + abi - > off_sc_fpc_csr ;
2015-07-27 22:58:16 +03:00
uint32_t __user * used_math = sc + abi - > off_sc_used_math ;
unsigned int used ;
int err , sig , tmp __maybe_unused ;
err = __get_user ( used , used_math ) ;
conditional_used_math ( used ) ;
/*
* The signal handler may have used FPU ; give it up if the program
* doesn ' t want it following sigreturn .
*/
if ( err | | ! used ) {
lose_fpu ( 0 ) ;
return err ;
}
err = sig = fpcsr_pending ( csr ) ;
if ( err < 0 )
return err ;
2015-07-27 22:58:13 +03:00
/*
* EVA does not have userland equivalents of ldc1 or sdc1 , so we
* disable the FPU here such that the code below simply copies to
* the kernel FP context .
*/
if ( config_enabled ( CONFIG_EVA ) )
lose_fpu ( 0 ) ;
2007-04-16 18:19:44 +04:00
while ( 1 ) {
lock_fpu_owner ( ) ;
2014-01-27 19:23:03 +04:00
if ( is_fpu_owner ( ) ) {
err = restore_fp_context ( sc ) ;
unlock_fpu_owner ( ) ;
} else {
unlock_fpu_owner ( ) ;
err = copy_fp_from_sigcontext ( sc ) ;
}
2007-04-16 18:19:44 +04:00
if ( likely ( ! err ) )
break ;
/* touch the sigcontext and try again */
2015-07-27 22:58:15 +03:00
err = __get_user ( tmp , & fpregs [ 0 ] ) |
__get_user ( tmp , & fpregs [ 31 ] ) |
__get_user ( tmp , csr ) ;
2007-04-16 18:19:44 +04:00
if ( err )
break ; /* really bad sigcontext */
}
2015-07-27 22:58:13 +03:00
2015-07-27 22:58:16 +03:00
return err ? : sig ;
2007-04-16 18:19:44 +04:00
}
2007-02-05 17:24:20 +03:00
int setup_sigcontext ( struct pt_regs * regs , struct sigcontext __user * sc )
{
int err = 0 ;
int i ;
err | = __put_user ( regs - > cp0_epc , & sc - > sc_pc ) ;
err | = __put_user ( 0 , & sc - > sc_regs [ 0 ] ) ;
for ( i = 1 ; i < 32 ; i + + )
err | = __put_user ( regs - > regs [ i ] , & sc - > sc_regs [ i ] ) ;
2007-02-02 19:41:47 +03:00
# ifdef CONFIG_CPU_HAS_SMARTMIPS
err | = __put_user ( regs - > acx , & sc - > sc_acx ) ;
# endif
2007-02-05 17:24:20 +03:00
err | = __put_user ( regs - > hi , & sc - > sc_mdhi ) ;
err | = __put_user ( regs - > lo , & sc - > sc_mdlo ) ;
if ( cpu_has_dsp ) {
err | = __put_user ( mfhi1 ( ) , & sc - > sc_hi1 ) ;
err | = __put_user ( mflo1 ( ) , & sc - > sc_lo1 ) ;
err | = __put_user ( mfhi2 ( ) , & sc - > sc_hi2 ) ;
err | = __put_user ( mflo2 ( ) , & sc - > sc_lo2 ) ;
err | = __put_user ( mfhi3 ( ) , & sc - > sc_hi3 ) ;
err | = __put_user ( mflo3 ( ) , & sc - > sc_lo3 ) ;
err | = __put_user ( rddsp ( DSP_MASK ) , & sc - > sc_dsp ) ;
}
2015-07-27 22:58:16 +03:00
/*
* Save FPU state to signal context . Signal handler
* will " inherit " current FPU state .
*/
err | = protected_save_fp_context ( sc ) ;
2007-02-05 17:24:20 +03:00
return err ;
}
2007-03-09 19:03:48 +03:00
int fpcsr_pending ( unsigned int __user * fpcsr )
{
int err , sig = 0 ;
unsigned int csr , enabled ;
err = __get_user ( csr , fpcsr ) ;
enabled = FPU_CSR_UNI_X | ( ( csr & FPU_CSR_ALL_E ) < < 5 ) ;
/*
* If the signal handler set some FPU exceptions , clear it and
* send SIGFPE .
*/
if ( csr & enabled ) {
csr & = ~ enabled ;
err | = __put_user ( csr , fpcsr ) ;
sig = SIGFPE ;
}
return err ? : sig ;
}
2007-02-05 17:24:20 +03:00
int restore_sigcontext ( struct pt_regs * regs , struct sigcontext __user * sc )
{
unsigned long treg ;
int err = 0 ;
int i ;
/* Always make any pending restarted system calls return -EINTR */
2015-02-13 02:01:14 +03:00
current - > restart_block . fn = do_no_restart_syscall ;
2007-02-05 17:24:20 +03:00
err | = __get_user ( regs - > cp0_epc , & sc - > sc_pc ) ;
2007-02-02 19:41:47 +03:00
# ifdef CONFIG_CPU_HAS_SMARTMIPS
err | = __get_user ( regs - > acx , & sc - > sc_acx ) ;
# endif
2007-02-05 17:24:20 +03:00
err | = __get_user ( regs - > hi , & sc - > sc_mdhi ) ;
err | = __get_user ( regs - > lo , & sc - > sc_mdlo ) ;
if ( cpu_has_dsp ) {
err | = __get_user ( treg , & sc - > sc_hi1 ) ; mthi1 ( treg ) ;
err | = __get_user ( treg , & sc - > sc_lo1 ) ; mtlo1 ( treg ) ;
err | = __get_user ( treg , & sc - > sc_hi2 ) ; mthi2 ( treg ) ;
err | = __get_user ( treg , & sc - > sc_lo2 ) ; mtlo2 ( treg ) ;
err | = __get_user ( treg , & sc - > sc_hi3 ) ; mthi3 ( treg ) ;
err | = __get_user ( treg , & sc - > sc_lo3 ) ; mtlo3 ( treg ) ;
err | = __get_user ( treg , & sc - > sc_dsp ) ; wrdsp ( treg , DSP_MASK ) ;
}
for ( i = 1 ; i < 32 ; i + + )
err | = __get_user ( regs - > regs [ i ] , & sc - > sc_regs [ i ] ) ;
2015-07-27 22:58:16 +03:00
return err ? : protected_restore_fp_context ( sc ) ;
2007-02-05 17:24:20 +03:00
}
2014-03-05 18:35:41 +04:00
void __user * get_sigframe ( struct ksignal * ksig , struct pt_regs * regs ,
2007-02-05 17:24:20 +03:00
size_t frame_size )
{
unsigned long sp ;
/* Default to using normal stack */
sp = regs - > regs [ 29 ] ;
/*
* FPU emulator may have it ' s own trampoline active just
* above the user stack , 16 - bytes before the next lowest
* 16 byte boundary . Try to avoid trashing it .
*/
sp - = 32 ;
2014-03-05 18:35:41 +04:00
sp = sigsp ( sp , ksig ) ;
2007-02-05 17:24:20 +03:00
return ( void __user * ) ( ( sp - frame_size ) & ( ICACHE_REFILLS_WORKAROUND_WAR ? ~ ( cpu_icache_line_size ( ) - 1 ) : ALMASK ) ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Atomically swap in the new signal mask , and wait for a signal .
*/
# ifdef CONFIG_TRAD_SIGNALS
2012-12-26 01:25:18 +04:00
SYSCALL_DEFINE1 ( sigsuspend , sigset_t __user * , uset )
2005-04-17 02:20:36 +04:00
{
2012-12-26 01:25:18 +04:00
return sys_rt_sigsuspend ( uset , sizeof ( sigset_t ) ) ;
2005-04-17 02:20:36 +04:00
}
# endif
# ifdef CONFIG_TRAD_SIGNALS
2009-02-08 19:00:26 +03:00
SYSCALL_DEFINE3 ( sigaction , int , sig , const struct sigaction __user * , act ,
struct sigaction __user * , oact )
2005-04-17 02:20:36 +04:00
{
struct k_sigaction new_ka , old_ka ;
int ret ;
int err = 0 ;
if ( act ) {
old_sigset_t mask ;
if ( ! access_ok ( VERIFY_READ , act , sizeof ( * act ) ) )
return - EFAULT ;
err | = __get_user ( new_ka . sa . sa_handler , & act - > sa_handler ) ;
err | = __get_user ( new_ka . sa . sa_flags , & act - > sa_flags ) ;
err | = __get_user ( mask , & act - > sa_mask . sig [ 0 ] ) ;
if ( err )
return - EFAULT ;
siginitset ( & new_ka . sa . sa_mask , mask ) ;
}
ret = do_sigaction ( sig , act ? & new_ka : NULL , oact ? & old_ka : NULL ) ;
if ( ! ret & & oact ) {
if ( ! access_ok ( VERIFY_WRITE , oact , sizeof ( * oact ) ) )
2007-02-05 03:10:11 +03:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
err | = __put_user ( old_ka . sa . sa_flags , & oact - > sa_flags ) ;
err | = __put_user ( old_ka . sa . sa_handler , & oact - > sa_handler ) ;
err | = __put_user ( old_ka . sa . sa_mask . sig [ 0 ] , oact - > sa_mask . sig ) ;
err | = __put_user ( 0 , & oact - > sa_mask . sig [ 1 ] ) ;
err | = __put_user ( 0 , & oact - > sa_mask . sig [ 2 ] ) ;
err | = __put_user ( 0 , & oact - > sa_mask . sig [ 3 ] ) ;
if ( err )
return - EFAULT ;
}
return ret ;
}
# endif
# ifdef CONFIG_TRAD_SIGNALS
2007-02-05 17:24:27 +03:00
asmlinkage void sys_sigreturn ( nabi_no_regargs struct pt_regs regs )
2005-04-17 02:20:36 +04:00
{
2006-01-31 19:41:09 +03:00
struct sigframe __user * frame ;
2005-04-17 02:20:36 +04:00
sigset_t blocked ;
2007-03-09 19:03:48 +03:00
int sig ;
2005-04-17 02:20:36 +04:00
2006-01-31 19:41:09 +03:00
frame = ( struct sigframe __user * ) regs . regs [ 29 ] ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_READ , frame , sizeof ( * frame ) ) )
goto badframe ;
if ( __copy_from_user ( & blocked , & frame - > sf_mask , sizeof ( blocked ) ) )
goto badframe ;
2012-02-14 15:40:52 +04:00
set_current_blocked ( & blocked ) ;
2005-04-17 02:20:36 +04:00
2007-03-09 19:03:48 +03:00
sig = restore_sigcontext ( & regs , & frame - > sf_sc ) ;
if ( sig < 0 )
2005-04-17 02:20:36 +04:00
goto badframe ;
2007-03-09 19:03:48 +03:00
else if ( sig )
force_sig ( sig , current ) ;
2005-04-17 02:20:36 +04:00
/*
* Don ' t let your children do this . . .
*/
__asm__ __volatile__ (
" move \t $29, %0 \n \t "
" j \t syscall_exit "
: /* no outputs */
: " r " ( & regs ) ) ;
/* Unreached */
badframe :
force_sig ( SIGSEGV , current ) ;
}
2005-05-31 15:49:19 +04:00
# endif /* CONFIG_TRAD_SIGNALS */
2005-04-17 02:20:36 +04:00
2007-02-05 17:24:27 +03:00
asmlinkage void sys_rt_sigreturn ( nabi_no_regargs struct pt_regs regs )
2005-04-17 02:20:36 +04:00
{
2006-01-31 19:41:09 +03:00
struct rt_sigframe __user * frame ;
2005-04-17 02:20:36 +04:00
sigset_t set ;
2007-03-09 19:03:48 +03:00
int sig ;
2005-04-17 02:20:36 +04:00
2006-01-31 19:41:09 +03:00
frame = ( struct rt_sigframe __user * ) regs . regs [ 29 ] ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_READ , frame , sizeof ( * frame ) ) )
goto badframe ;
if ( __copy_from_user ( & set , & frame - > rs_uc . uc_sigmask , sizeof ( set ) ) )
goto badframe ;
2012-02-14 15:40:52 +04:00
set_current_blocked ( & set ) ;
2005-04-17 02:20:36 +04:00
2007-03-09 19:03:48 +03:00
sig = restore_sigcontext ( & regs , & frame - > rs_uc . uc_mcontext ) ;
if ( sig < 0 )
2005-04-17 02:20:36 +04:00
goto badframe ;
2007-03-09 19:03:48 +03:00
else if ( sig )
force_sig ( sig , current ) ;
2005-04-17 02:20:36 +04:00
2012-12-23 12:13:40 +04:00
if ( restore_altstack ( & frame - > rs_uc . uc_stack ) )
goto badframe ;
2005-04-17 02:20:36 +04:00
/*
* Don ' t let your children do this . . .
*/
__asm__ __volatile__ (
" move \t $29, %0 \n \t "
" j \t syscall_exit "
: /* no outputs */
: " r " ( & regs ) ) ;
/* Unreached */
badframe :
force_sig ( SIGSEGV , current ) ;
}
# ifdef CONFIG_TRAD_SIGNALS
2013-10-07 00:25:42 +04:00
static int setup_frame ( void * sig_return , struct ksignal * ksig ,
struct pt_regs * regs , sigset_t * set )
2005-04-17 02:20:36 +04:00
{
2006-01-31 19:41:09 +03:00
struct sigframe __user * frame ;
2005-04-17 02:20:36 +04:00
int err = 0 ;
2014-03-05 18:35:41 +04:00
frame = get_sigframe ( ksig , regs , sizeof ( * frame ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_WRITE , frame , sizeof ( * frame ) ) )
2013-10-07 00:25:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
err | = setup_sigcontext ( regs , & frame - > sf_sc ) ;
err | = __copy_to_user ( & frame - > sf_mask , set , sizeof ( * set ) ) ;
if ( err )
2013-10-07 00:25:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
/*
* Arguments to signal handler :
*
* a0 = signal number
* a1 = 0 ( should be cause )
* a2 = pointer to struct sigcontext
*
* $ 25 and c0_epc point to the signal handler , $ 29 points to the
* struct sigframe .
*/
2013-10-07 00:25:42 +04:00
regs - > regs [ 4 ] = ksig - > sig ;
2005-04-17 02:20:36 +04:00
regs - > regs [ 5 ] = 0 ;
regs - > regs [ 6 ] = ( unsigned long ) & frame - > sf_sc ;
regs - > regs [ 29 ] = ( unsigned long ) frame ;
2010-02-19 03:13:05 +03:00
regs - > regs [ 31 ] = ( unsigned long ) sig_return ;
2013-10-07 00:25:42 +04:00
regs - > cp0_epc = regs - > regs [ 25 ] = ( unsigned long ) ksig - > ka . sa . sa_handler ;
2005-04-17 02:20:36 +04:00
2007-02-05 17:24:24 +03:00
DEBUGP ( " SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx \n " ,
2005-04-17 02:20:36 +04:00
current - > comm , current - > pid ,
2007-02-05 17:24:24 +03:00
frame , regs - > cp0_epc , regs - > regs [ 31 ] ) ;
2007-02-05 03:10:11 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
# endif
2013-10-07 00:25:42 +04:00
static int setup_rt_frame ( void * sig_return , struct ksignal * ksig ,
struct pt_regs * regs , sigset_t * set )
2005-04-17 02:20:36 +04:00
{
2006-01-31 19:41:09 +03:00
struct rt_sigframe __user * frame ;
2005-04-17 02:20:36 +04:00
int err = 0 ;
2014-03-05 18:35:41 +04:00
frame = get_sigframe ( ksig , regs , sizeof ( * frame ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_WRITE , frame , sizeof ( * frame ) ) )
2013-10-07 00:25:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
/* Create siginfo. */
2013-10-07 00:25:42 +04:00
err | = copy_siginfo_to_user ( & frame - > rs_info , & ksig - > info ) ;
2005-04-17 02:20:36 +04:00
2013-01-22 15:59:30 +04:00
/* Create the ucontext. */
2005-04-17 02:20:36 +04:00
err | = __put_user ( 0 , & frame - > rs_uc . uc_flags ) ;
2006-02-01 19:26:34 +03:00
err | = __put_user ( NULL , & frame - > rs_uc . uc_link ) ;
2012-12-23 12:13:40 +04:00
err | = __save_altstack ( & frame - > rs_uc . uc_stack , regs - > regs [ 29 ] ) ;
2005-04-17 02:20:36 +04:00
err | = setup_sigcontext ( regs , & frame - > rs_uc . uc_mcontext ) ;
err | = __copy_to_user ( & frame - > rs_uc . uc_sigmask , set , sizeof ( * set ) ) ;
if ( err )
2013-10-07 00:25:42 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
/*
* Arguments to signal handler :
*
* a0 = signal number
* a1 = 0 ( should be cause )
* a2 = pointer to ucontext
*
* $ 25 and c0_epc point to the signal handler , $ 29 points to
* the struct rt_sigframe .
*/
2013-10-07 00:25:42 +04:00
regs - > regs [ 4 ] = ksig - > sig ;
2005-04-17 02:20:36 +04:00
regs - > regs [ 5 ] = ( unsigned long ) & frame - > rs_info ;
regs - > regs [ 6 ] = ( unsigned long ) & frame - > rs_uc ;
regs - > regs [ 29 ] = ( unsigned long ) frame ;
2010-02-19 03:13:05 +03:00
regs - > regs [ 31 ] = ( unsigned long ) sig_return ;
2013-10-07 00:25:42 +04:00
regs - > cp0_epc = regs - > regs [ 25 ] = ( unsigned long ) ksig - > ka . sa . sa_handler ;
2005-04-17 02:20:36 +04:00
2007-02-05 17:24:24 +03:00
DEBUGP ( " SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx \n " ,
2005-04-17 02:20:36 +04:00
current - > comm , current - > pid ,
frame , regs - > cp0_epc , regs - > regs [ 31 ] ) ;
2007-02-05 17:24:24 +03:00
2006-02-08 15:58:41 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-02-15 14:40:37 +03:00
struct mips_abi mips_abi = {
# ifdef CONFIG_TRAD_SIGNALS
. setup_frame = setup_frame ,
2010-02-19 03:13:05 +03:00
. signal_return_offset = offsetof ( struct mips_vdso , signal_trampoline ) ,
2007-02-15 14:40:37 +03:00
# endif
2013-01-22 15:59:30 +04:00
. setup_rt_frame = setup_rt_frame ,
2010-02-19 03:13:05 +03:00
. rt_signal_return_offset =
offsetof ( struct mips_vdso , rt_signal_trampoline ) ,
2015-07-27 22:58:14 +03:00
. restart = __NR_restart_syscall ,
. off_sc_fpregs = offsetof ( struct sigcontext , sc_fpregs ) ,
. off_sc_fpc_csr = offsetof ( struct sigcontext , sc_fpc_csr ) ,
. off_sc_used_math = offsetof ( struct sigcontext , sc_used_math ) ,
2007-02-15 14:40:37 +03:00
} ;
2013-10-07 00:25:42 +04:00
static void 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 ( ) ;
2005-07-12 00:45:51 +04:00
int ret ;
2010-02-19 03:13:05 +03:00
struct mips_abi * abi = current - > thread . abi ;
2013-03-25 22:21:11 +04:00
# ifdef CONFIG_CPU_MICROMIPS
void * vdso ;
2014-11-16 01:08:09 +03:00
unsigned long tmp = ( unsigned long ) current - > mm - > context . vdso ;
2013-03-25 22:21:11 +04:00
set_isa16_mode ( tmp ) ;
vdso = ( void * ) tmp ;
# else
2010-02-19 03:13:05 +03:00
void * vdso = current - > mm - > context . vdso ;
2013-03-25 22:21:11 +04:00
# endif
2005-07-12 00:45:51 +04:00
2010-09-28 21:50:37 +04:00
if ( regs - > regs [ 0 ] ) {
switch ( regs - > regs [ 2 ] ) {
case ERESTART_RESTARTBLOCK :
case ERESTARTNOHAND :
2005-04-17 02:20:36 +04:00
regs - > regs [ 2 ] = EINTR ;
break ;
2010-09-28 21:50:37 +04:00
case ERESTARTSYS :
2013-10-07 00:25:42 +04:00
if ( ! ( ksig - > ka . sa . sa_flags & SA_RESTART ) ) {
2010-09-28 21:50:37 +04:00
regs - > regs [ 2 ] = EINTR ;
break ;
}
/* fallthrough */
case ERESTARTNOINTR :
regs - > regs [ 7 ] = regs - > regs [ 26 ] ;
regs - > regs [ 2 ] = regs - > regs [ 0 ] ;
regs - > cp0_epc - = 4 ;
2005-04-17 02:20:36 +04:00
}
2013-01-22 15:59:30 +04:00
regs - > regs [ 0 ] = 0 ; /* Don't deal with this again. */
2010-09-28 21:50:37 +04:00
}
2005-04-17 02:20:36 +04:00
2013-10-07 00:25:42 +04:00
if ( sig_uses_siginfo ( & ksig - > ka ) )
2010-02-19 03:13:05 +03:00
ret = abi - > setup_rt_frame ( vdso + abi - > rt_signal_return_offset ,
2013-10-07 00:25:42 +04:00
ksig , regs , oldset ) ;
2005-04-17 02:20:36 +04:00
else
2013-10-07 00:25:42 +04:00
ret = abi - > setup_frame ( vdso + abi - > signal_return_offset , ksig ,
regs , oldset ) ;
2010-09-28 21:50:17 +04:00
2013-10-07 00:25:42 +04:00
signal_setup_done ( ret , ksig , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-15 14:40:37 +03:00
static void do_signal ( struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
2013-10-07 00:25:42 +04:00
struct ksignal ksig ;
2005-04-17 02:20:36 +04:00
2013-10-07 00:25:42 +04:00
if ( get_signal ( & ksig ) ) {
2013-01-22 15:59:30 +04:00
/* Whee! Actually deliver the signal. */
2013-10-07 00:25:42 +04:00
handle_signal ( & ksig , regs ) ;
2006-08-04 00:54:13 +04:00
return ;
2006-02-08 15:58:41 +03:00
}
2005-04-17 02:20:36 +04:00
if ( regs - > regs [ 0 ] ) {
2012-11-06 17:27:19 +04:00
switch ( regs - > regs [ 2 ] ) {
case ERESTARTNOHAND :
case ERESTARTSYS :
case ERESTARTNOINTR :
2010-09-28 21:50:37 +04:00
regs - > regs [ 2 ] = regs - > regs [ 0 ] ;
2005-04-17 02:20:36 +04:00
regs - > regs [ 7 ] = regs - > regs [ 26 ] ;
2010-09-28 21:50:37 +04:00
regs - > cp0_epc - = 4 ;
2012-11-06 17:27:19 +04:00
break ;
case ERESTART_RESTARTBLOCK :
2007-02-15 14:40:37 +03:00
regs - > regs [ 2 ] = current - > thread . abi - > restart ;
2005-04-17 02:20:36 +04:00
regs - > regs [ 7 ] = regs - > regs [ 26 ] ;
regs - > cp0_epc - = 4 ;
2012-11-06 17:27:19 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2013-01-22 15:59:30 +04:00
regs - > regs [ 0 ] = 0 ; /* Don't deal with this again. */
2005-04-17 02:20:36 +04:00
}
2006-02-08 15:58:41 +03:00
/*
* If there ' s no signal to deliver , we just put the saved sigmask
* back
*/
2012-05-22 07:33:55 +04:00
restore_saved_sigmask ( ) ;
2005-04-17 02:20:36 +04:00
}
/*
* notification of userspace execution resumption
2006-02-08 15:58:41 +03:00
* - triggered by the TIF_WORK_MASK flags
2005-04-17 02:20:36 +04:00
*/
2006-02-08 15:58:41 +03:00
asmlinkage void do_notify_resume ( struct pt_regs * regs , void * unused ,
2005-04-17 02:20:36 +04:00
__u32 thread_info_flags )
{
2011-07-27 14:44:47 +04:00
local_irq_enable ( ) ;
2013-05-29 03:07:19 +04:00
user_exit ( ) ;
2005-04-17 02:20:36 +04:00
/* deal with pending signal delivery */
2012-05-23 23:28:58 +04:00
if ( thread_info_flags & _TIF_SIGPENDING )
2007-02-15 14:40:37 +03:00
do_signal ( regs ) ;
2009-09-02 12:14:16 +04:00
if ( thread_info_flags & _TIF_NOTIFY_RESUME ) {
clear_thread_flag ( TIF_NOTIFY_RESUME ) ;
tracehook_notify_resume ( regs ) ;
}
2013-05-29 03:07:19 +04:00
user_enter ( ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-24 22:35:41 +03:00
# ifdef CONFIG_SMP
2015-07-27 22:58:15 +03:00
static int smp_save_fp_context ( void __user * sc )
2009-11-24 22:35:41 +03:00
{
return raw_cpu_has_fpu
2015-07-27 22:58:15 +03:00
? save_hw_fp_context ( sc )
2014-01-27 19:23:02 +04:00
: copy_fp_to_sigcontext ( sc ) ;
2009-11-24 22:35:41 +03:00
}
2015-07-27 22:58:15 +03:00
static int smp_restore_fp_context ( void __user * sc )
2009-11-24 22:35:41 +03:00
{
return raw_cpu_has_fpu
2015-07-27 22:58:15 +03:00
? restore_hw_fp_context ( sc )
2014-01-27 19:23:02 +04:00
: copy_fp_from_sigcontext ( sc ) ;
2009-11-24 22:35:41 +03:00
}
# endif
static int signal_setup ( void )
{
# ifdef CONFIG_SMP
/* For now just do the cpu_has_fpu check when the functions are invoked */
save_fp_context = smp_save_fp_context ;
restore_fp_context = smp_restore_fp_context ;
# else
if ( cpu_has_fpu ) {
2015-07-27 22:58:15 +03:00
save_fp_context = save_hw_fp_context ;
restore_fp_context = restore_hw_fp_context ;
2009-11-24 22:35:41 +03:00
} else {
2014-10-28 14:25:51 +03:00
save_fp_context = copy_fp_to_sigcontext ;
restore_fp_context = copy_fp_from_sigcontext ;
2009-11-24 22:35:41 +03:00
}
2013-12-12 20:57:19 +04:00
# endif /* CONFIG_SMP */
2009-11-24 22:35:41 +03:00
return 0 ;
}
arch_initcall ( signal_setup ) ;