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
2006-02-18 18:21:30 +03:00
* Copyright ( C ) 1994 - 2000 , 2006 Ralf Baechle
2005-04-17 02:20:36 +04:00
* Copyright ( C ) 1999 , 2000 Silicon Graphics , Inc .
*/
2005-06-15 17:00:12 +04:00
# include <linux/cache.h>
2007-02-13 03:05:11 +03:00
# include <linux/compat.h>
2005-04-17 02:20:36 +04:00
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/smp.h>
# include <linux/kernel.h>
# include <linux/signal.h>
# include <linux/syscalls.h>
# include <linux/errno.h>
# include <linux/wait.h>
# include <linux/ptrace.h>
# include <linux/suspend.h>
# include <linux/compiler.h>
2007-04-16 18:19:44 +04:00
# include <linux/uaccess.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>
2007-02-13 03:05:11 +03:00
# include <asm/compat-signal.h>
2005-04-17 02:20:36 +04:00
# include <linux/bitops.h>
# include <asm/cacheflush.h>
# include <asm/sim.h>
# include <asm/ucontext.h>
# include <asm/system.h>
# include <asm/fpu.h>
2005-06-15 17:00:12 +04:00
# include <asm/war.h>
2005-04-17 02:20:36 +04:00
2007-02-05 17:24:22 +03:00
# include "signal-common.h"
2005-04-17 02:20:36 +04:00
/*
* Including < asm / unistd . h > would give use the 64 - bit syscall numbers . . .
*/
# define __NR_O32_sigreturn 4119
# define __NR_O32_rt_sigreturn 4193
2007-02-15 14:40:37 +03:00
# define __NR_O32_restart_syscall 4253
2005-04-17 02:20:36 +04:00
/* 32-bit compatibility types */
typedef unsigned int __sighandler32_t ;
typedef void ( * vfptr_t ) ( void ) ;
struct sigaction32 {
unsigned int sa_flags ;
__sighandler32_t sa_handler ;
compat_sigset_t sa_mask ;
} ;
/* IRIX compatible stack_t */
typedef struct sigaltstack32 {
s32 ss_sp ;
compat_size_t ss_size ;
int ss_flags ;
} stack32_t ;
struct ucontext32 {
u32 uc_flags ;
s32 uc_link ;
stack32_t uc_stack ;
struct sigcontext32 uc_mcontext ;
2007-02-11 21:22:36 +03:00
compat_sigset_t uc_sigmask ; /* mask last for extensibility */
2005-04-17 02:20:36 +04:00
} ;
2007-02-13 03:50:57 +03:00
/*
* Horribly complicated - with the bloody RM9000 workarounds enabled
* the signal trampolines is moving to the end of the structure so we can
* increase the alignment without breaking software compatibility .
*/
2007-02-05 17:24:21 +03:00
# if ICACHE_REFILLS_WORKAROUND_WAR == 0
2007-02-13 03:50:57 +03:00
struct sigframe32 {
u32 sf_ass [ 4 ] ; /* argument save space for o32 */
u32 sf_code [ 2 ] ; /* signal trampoline */
struct sigcontext32 sf_sc ;
2007-02-14 08:41:01 +03:00
compat_sigset_t sf_mask ;
2007-02-13 03:50:57 +03:00
} ;
2007-02-05 17:24:21 +03:00
struct rt_sigframe32 {
u32 rs_ass [ 4 ] ; /* argument save space for o32 */
u32 rs_code [ 2 ] ; /* signal trampoline */
compat_siginfo_t rs_info ;
struct ucontext32 rs_uc ;
} ;
# else /* ICACHE_REFILLS_WORKAROUND_WAR */
2007-02-13 03:50:57 +03:00
struct sigframe32 {
u32 sf_ass [ 4 ] ; /* argument save space for o32 */
u32 sf_pad [ 2 ] ;
struct sigcontext32 sf_sc ; /* hw context */
2007-02-14 08:41:01 +03:00
compat_sigset_t sf_mask ;
2007-02-13 03:50:57 +03:00
u32 sf_code [ 8 ] ____cacheline_aligned ; /* signal trampoline */
} ;
2007-02-05 17:24:21 +03:00
struct rt_sigframe32 {
u32 rs_ass [ 4 ] ; /* argument save space for o32 */
u32 rs_pad [ 2 ] ;
compat_siginfo_t rs_info ;
struct ucontext32 rs_uc ;
u32 rs_code [ 8 ] __attribute__ ( ( aligned ( 32 ) ) ) ; /* signal trampoline */
} ;
# endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
2007-02-05 17:24:25 +03:00
/*
* sigcontext handlers
*/
2007-04-16 18:19:44 +04:00
static int protected_save_fp_context32 ( struct sigcontext32 __user * sc )
{
int err ;
while ( 1 ) {
lock_fpu_owner ( ) ;
own_fpu_inatomic ( 1 ) ;
err = save_fp_context32 ( sc ) ; /* this might fail */
unlock_fpu_owner ( ) ;
if ( likely ( ! err ) )
break ;
/* touch the sigcontext and try again */
err = __put_user ( 0 , & sc - > sc_fpregs [ 0 ] ) |
__put_user ( 0 , & sc - > sc_fpregs [ 31 ] ) |
__put_user ( 0 , & sc - > sc_fpc_csr ) ;
if ( err )
break ; /* really bad sigcontext */
}
return err ;
}
static int protected_restore_fp_context32 ( struct sigcontext32 __user * sc )
{
int err , tmp ;
while ( 1 ) {
lock_fpu_owner ( ) ;
own_fpu_inatomic ( 0 ) ;
err = restore_fp_context32 ( sc ) ; /* this might fail */
unlock_fpu_owner ( ) ;
if ( likely ( ! err ) )
break ;
/* touch the sigcontext and try again */
err = __get_user ( tmp , & sc - > sc_fpregs [ 0 ] ) |
__get_user ( tmp , & sc - > sc_fpregs [ 31 ] ) |
__get_user ( tmp , & sc - > sc_fpc_csr ) ;
if ( err )
break ; /* really bad sigcontext */
}
return err ;
}
2007-02-05 17:24:25 +03:00
static int setup_sigcontext32 ( struct pt_regs * regs ,
struct sigcontext32 __user * sc )
{
int err = 0 ;
int i ;
2007-03-09 19:07:45 +03:00
u32 used_math ;
2007-02-05 17:24:25 +03:00
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 ] ) ;
err | = __put_user ( regs - > hi , & sc - > sc_mdhi ) ;
err | = __put_user ( regs - > lo , & sc - > sc_mdlo ) ;
if ( cpu_has_dsp ) {
err | = __put_user ( rddsp ( DSP_MASK ) , & sc - > sc_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 ) ;
}
2007-03-09 19:07:45 +03:00
used_math = ! ! used_math ( ) ;
err | = __put_user ( used_math , & sc - > sc_used_math ) ;
2007-02-05 17:24:25 +03:00
2007-03-09 19:07:45 +03:00
if ( used_math ) {
2007-02-05 17:24:25 +03:00
/*
* Save FPU state to signal context . Signal handler
* will " inherit " current FPU state .
*/
2007-04-16 18:19:44 +04:00
err | = protected_save_fp_context32 ( sc ) ;
2007-02-05 17:24:25 +03:00
}
return err ;
}
2007-03-09 19:03:48 +03:00
static int
check_and_restore_fp_context32 ( struct sigcontext32 __user * sc )
{
int err , sig ;
err = sig = fpcsr_pending ( & sc - > sc_fpc_csr ) ;
if ( err > 0 )
err = 0 ;
2007-04-16 18:19:44 +04:00
err | = protected_restore_fp_context32 ( sc ) ;
2007-03-09 19:03:48 +03:00
return err ? : sig ;
}
2007-02-05 17:24:25 +03:00
static int restore_sigcontext32 ( struct pt_regs * regs ,
struct sigcontext32 __user * sc )
{
u32 used_math ;
int err = 0 ;
s32 treg ;
int i ;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info ( ) - > restart_block . fn = do_no_restart_syscall ;
err | = __get_user ( regs - > cp0_epc , & sc - > sc_pc ) ;
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 ] ) ;
err | = __get_user ( used_math , & sc - > sc_used_math ) ;
conditional_used_math ( used_math ) ;
2007-03-09 19:07:45 +03:00
if ( used_math ) {
2007-02-05 17:24:25 +03:00
/* restore fpu context if we have used it before */
2007-03-09 19:03:48 +03:00
if ( ! err )
err = check_and_restore_fp_context32 ( sc ) ;
2007-02-05 17:24:25 +03:00
} else {
/* signal handler may have used FPU. Give it up. */
2007-03-09 19:07:45 +03:00
lose_fpu ( 0 ) ;
2007-02-05 17:24:25 +03:00
}
return err ;
}
/*
*
*/
2005-04-17 02:20:36 +04:00
extern void __put_sigset_unknown_nsig ( void ) ;
extern void __get_sigset_unknown_nsig ( void ) ;
2006-01-31 19:41:09 +03:00
static inline int put_sigset ( const sigset_t * kbuf , compat_sigset_t __user * ubuf )
2005-04-17 02:20:36 +04:00
{
int err = 0 ;
if ( ! access_ok ( VERIFY_WRITE , ubuf , sizeof ( * ubuf ) ) )
return - EFAULT ;
switch ( _NSIG_WORDS ) {
default :
__put_sigset_unknown_nsig ( ) ;
case 2 :
err | = __put_user ( kbuf - > sig [ 1 ] > > 32 , & ubuf - > sig [ 3 ] ) ;
err | = __put_user ( kbuf - > sig [ 1 ] & 0xffffffff , & ubuf - > sig [ 2 ] ) ;
case 1 :
err | = __put_user ( kbuf - > sig [ 0 ] > > 32 , & ubuf - > sig [ 1 ] ) ;
err | = __put_user ( kbuf - > sig [ 0 ] & 0xffffffff , & ubuf - > sig [ 0 ] ) ;
}
return err ;
}
2006-02-19 17:46:44 +03:00
static inline int get_sigset ( sigset_t * kbuf , const compat_sigset_t __user * ubuf )
2005-04-17 02:20:36 +04:00
{
int err = 0 ;
unsigned long sig [ 4 ] ;
if ( ! access_ok ( VERIFY_READ , ubuf , sizeof ( * ubuf ) ) )
return - EFAULT ;
switch ( _NSIG_WORDS ) {
default :
__get_sigset_unknown_nsig ( ) ;
case 2 :
err | = __get_user ( sig [ 3 ] , & ubuf - > sig [ 3 ] ) ;
err | = __get_user ( sig [ 2 ] , & ubuf - > sig [ 2 ] ) ;
kbuf - > sig [ 1 ] = sig [ 2 ] | ( sig [ 3 ] < < 32 ) ;
case 1 :
err | = __get_user ( sig [ 1 ] , & ubuf - > sig [ 1 ] ) ;
err | = __get_user ( sig [ 0 ] , & ubuf - > sig [ 0 ] ) ;
kbuf - > sig [ 0 ] = sig [ 0 ] | ( sig [ 1 ] < < 32 ) ;
}
return err ;
}
/*
* Atomically swap in the new signal mask , and wait for a signal .
*/
2007-02-05 17:24:27 +03:00
asmlinkage int sys32_sigsuspend ( nabi_no_regargs struct pt_regs regs )
2005-04-17 02:20:36 +04:00
{
2006-02-19 17:46:44 +03:00
compat_sigset_t __user * uset ;
2006-02-18 17:55:45 +03:00
sigset_t newset ;
2005-04-17 02:20:36 +04:00
2006-02-19 17:46:44 +03:00
uset = ( compat_sigset_t __user * ) regs . regs [ 4 ] ;
2005-04-17 02:20:36 +04:00
if ( get_sigset ( & newset , uset ) )
return - EFAULT ;
sigdelsetmask ( & newset , ~ _BLOCKABLE ) ;
spin_lock_irq ( & current - > sighand - > siglock ) ;
2006-02-18 17:55:45 +03:00
current - > saved_sigmask = current - > blocked ;
2005-04-17 02:20:36 +04:00
current - > blocked = newset ;
recalc_sigpending ( ) ;
spin_unlock_irq ( & current - > sighand - > siglock ) ;
2006-02-18 17:55:45 +03:00
current - > state = TASK_INTERRUPTIBLE ;
schedule ( ) ;
set_thread_flag ( TIF_RESTORE_SIGMASK ) ;
return - ERESTARTNOHAND ;
2005-04-17 02:20:36 +04:00
}
2007-02-05 17:24:27 +03:00
asmlinkage int sys32_rt_sigsuspend ( nabi_no_regargs struct pt_regs regs )
2005-04-17 02:20:36 +04:00
{
2006-02-19 17:46:44 +03:00
compat_sigset_t __user * uset ;
2006-02-18 17:55:45 +03:00
sigset_t newset ;
2006-02-18 21:20:47 +03:00
size_t sigsetsize ;
2005-04-17 02:20:36 +04:00
/* XXX Don't preclude handling different sized sigset_t's. */
sigsetsize = regs . regs [ 5 ] ;
if ( sigsetsize ! = sizeof ( compat_sigset_t ) )
return - EINVAL ;
2006-02-19 17:46:44 +03:00
uset = ( compat_sigset_t __user * ) regs . regs [ 4 ] ;
2005-04-17 02:20:36 +04:00
if ( get_sigset ( & newset , uset ) )
return - EFAULT ;
sigdelsetmask ( & newset , ~ _BLOCKABLE ) ;
spin_lock_irq ( & current - > sighand - > siglock ) ;
2006-02-18 17:55:45 +03:00
current - > saved_sigmask = current - > blocked ;
2005-04-17 02:20:36 +04:00
current - > blocked = newset ;
2006-02-18 23:06:32 +03:00
recalc_sigpending ( ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & current - > sighand - > siglock ) ;
2006-02-18 17:55:45 +03:00
current - > state = TASK_INTERRUPTIBLE ;
schedule ( ) ;
set_thread_flag ( TIF_RESTORE_SIGMASK ) ;
return - ERESTARTNOHAND ;
2005-04-17 02:20:36 +04:00
}
2006-02-19 17:46:44 +03:00
asmlinkage int sys32_sigaction ( int sig , const struct sigaction32 __user * act ,
struct sigaction32 __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 ;
2005-03-04 22:36:51 +03:00
s32 handler ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_READ , act , sizeof ( * act ) ) )
return - EFAULT ;
2005-03-04 22:36:51 +03:00
err | = __get_user ( handler , & act - > sa_handler ) ;
2006-01-31 19:41:09 +03:00
new_ka . sa . sa_handler = ( void __user * ) ( s64 ) handler ;
2005-04-17 02:20:36 +04:00
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 ) ) )
2006-02-18 23:06:32 +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 ( ( u32 ) ( u64 ) old_ka . sa . sa_handler ,
& oact - > sa_handler ) ;
err | = __put_user ( old_ka . sa . sa_mask . sig [ 0 ] , oact - > sa_mask . sig ) ;
2006-02-18 23:06:32 +03:00
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 )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
}
return ret ;
}
asmlinkage int sys32_sigaltstack ( nabi_no_regargs struct pt_regs regs )
{
2006-01-31 19:41:09 +03:00
const stack32_t __user * uss = ( const stack32_t __user * ) regs . regs [ 4 ] ;
stack32_t __user * uoss = ( stack32_t __user * ) regs . regs [ 5 ] ;
2005-04-17 02:20:36 +04:00
unsigned long usp = regs . regs [ 29 ] ;
stack_t kss , koss ;
int ret , err = 0 ;
mm_segment_t old_fs = get_fs ( ) ;
s32 sp ;
if ( uss ) {
if ( ! access_ok ( VERIFY_READ , uss , sizeof ( * uss ) ) )
return - EFAULT ;
err | = __get_user ( sp , & uss - > ss_sp ) ;
2006-02-19 17:46:44 +03:00
kss . ss_sp = ( void __user * ) ( long ) sp ;
2005-04-17 02:20:36 +04:00
err | = __get_user ( kss . ss_size , & uss - > ss_size ) ;
err | = __get_user ( kss . ss_flags , & uss - > ss_flags ) ;
if ( err )
return - EFAULT ;
}
set_fs ( KERNEL_DS ) ;
2006-01-31 19:41:09 +03:00
ret = do_sigaltstack ( uss ? ( stack_t __user * ) & kss : NULL ,
uoss ? ( stack_t __user * ) & koss : NULL , usp ) ;
2005-04-17 02:20:36 +04:00
set_fs ( old_fs ) ;
if ( ! ret & & uoss ) {
if ( ! access_ok ( VERIFY_WRITE , uoss , sizeof ( * uoss ) ) )
return - EFAULT ;
2006-02-19 17:46:44 +03:00
sp = ( int ) ( unsigned long ) koss . ss_sp ;
2005-04-17 02:20:36 +04:00
err | = __put_user ( sp , & uoss - > ss_sp ) ;
err | = __put_user ( koss . ss_size , & uoss - > ss_size ) ;
err | = __put_user ( koss . ss_flags , & uoss - > ss_flags ) ;
if ( err )
return - EFAULT ;
}
return ret ;
}
2006-01-31 19:41:09 +03:00
int copy_siginfo_to_user32 ( compat_siginfo_t __user * to , siginfo_t * from )
2005-04-17 02:20:36 +04:00
{
int err ;
if ( ! access_ok ( VERIFY_WRITE , to , sizeof ( compat_siginfo_t ) ) )
return - EFAULT ;
/* If you change siginfo_t structure, please be sure
this code is fixed accordingly .
It should never copy any pad contained in the structure
to avoid security leaks , but must copy the generic
3 ints plus the relevant union member .
This routine must convert siginfo from 64 bit to 32 bit as well
at the same time . */
err = __put_user ( from - > si_signo , & to - > si_signo ) ;
err | = __put_user ( from - > si_errno , & to - > si_errno ) ;
err | = __put_user ( ( short ) from - > si_code , & to - > si_code ) ;
if ( from - > si_code < 0 )
err | = __copy_to_user ( & to - > _sifields . _pad , & from - > _sifields . _pad , SI_PAD_SIZE ) ;
else {
switch ( from - > si_code > > 16 ) {
2005-02-17 00:24:16 +03:00
case __SI_TIMER > > 16 :
err | = __put_user ( from - > si_tid , & to - > si_tid ) ;
err | = __put_user ( from - > si_overrun , & to - > si_overrun ) ;
err | = __put_user ( from - > si_int , & to - > si_int ) ;
break ;
2005-04-17 02:20:36 +04:00
case __SI_CHLD > > 16 :
err | = __put_user ( from - > si_utime , & to - > si_utime ) ;
err | = __put_user ( from - > si_stime , & to - > si_stime ) ;
err | = __put_user ( from - > si_status , & to - > si_status ) ;
default :
err | = __put_user ( from - > si_pid , & to - > si_pid ) ;
err | = __put_user ( from - > si_uid , & to - > si_uid ) ;
break ;
case __SI_FAULT > > 16 :
2006-02-01 19:26:34 +03:00
err | = __put_user ( ( unsigned long ) from - > si_addr , & to - > si_addr ) ;
2005-04-17 02:20:36 +04:00
break ;
case __SI_POLL > > 16 :
err | = __put_user ( from - > si_band , & to - > si_band ) ;
err | = __put_user ( from - > si_fd , & to - > si_fd ) ;
break ;
case __SI_RT > > 16 : /* This is not generated by the kernel as of now. */
case __SI_MESGQ > > 16 :
err | = __put_user ( from - > si_pid , & to - > si_pid ) ;
err | = __put_user ( from - > si_uid , & to - > si_uid ) ;
err | = __put_user ( from - > si_int , & to - > si_int ) ;
break ;
}
}
return err ;
}
2007-02-05 17:24:27 +03:00
asmlinkage void sys32_sigreturn ( nabi_no_regargs struct pt_regs regs )
2005-04-17 02:20:36 +04:00
{
2007-02-13 03:50:57 +03:00
struct sigframe32 __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
2007-02-13 03:50:57 +03:00
frame = ( struct sigframe32 __user * ) regs . regs [ 29 ] ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_READ , frame , sizeof ( * frame ) ) )
goto badframe ;
2007-02-13 03:05:11 +03:00
if ( __copy_conv_sigset_from_user ( & blocked , & frame - > sf_mask ) )
2005-04-17 02:20:36 +04:00
goto badframe ;
sigdelsetmask ( & blocked , ~ _BLOCKABLE ) ;
spin_lock_irq ( & current - > sighand - > siglock ) ;
current - > blocked = blocked ;
recalc_sigpending ( ) ;
spin_unlock_irq ( & current - > sighand - > siglock ) ;
2007-03-09 19:03:48 +03:00
sig = restore_sigcontext32 ( & 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 ) ;
}
2007-02-05 17:24:27 +03:00
asmlinkage void sys32_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_sigframe32 __user * frame ;
2005-04-13 22:18:04 +04:00
mm_segment_t old_fs ;
2005-04-17 02:20:36 +04:00
sigset_t set ;
stack_t st ;
s32 sp ;
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_sigframe32 __user * ) regs . regs [ 29 ] ;
2005-04-17 02:20:36 +04:00
if ( ! access_ok ( VERIFY_READ , frame , sizeof ( * frame ) ) )
goto badframe ;
2007-02-13 03:05:11 +03:00
if ( __copy_conv_sigset_from_user ( & set , & frame - > rs_uc . uc_sigmask ) )
2005-04-17 02:20:36 +04:00
goto badframe ;
sigdelsetmask ( & set , ~ _BLOCKABLE ) ;
spin_lock_irq ( & current - > sighand - > siglock ) ;
current - > blocked = set ;
recalc_sigpending ( ) ;
spin_unlock_irq ( & current - > sighand - > siglock ) ;
2007-03-09 19:03:48 +03:00
sig = restore_sigcontext32 ( & 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
/* The ucontext contains a stack32_t, so we must convert! */
if ( __get_user ( sp , & frame - > rs_uc . uc_stack . ss_sp ) )
goto badframe ;
2006-02-19 17:46:44 +03:00
st . ss_sp = ( void __user * ) ( long ) sp ;
2005-04-17 02:20:36 +04:00
if ( __get_user ( st . ss_size , & frame - > rs_uc . uc_stack . ss_size ) )
goto badframe ;
if ( __get_user ( st . ss_flags , & frame - > rs_uc . uc_stack . ss_flags ) )
goto badframe ;
/* It is more difficult to avoid calling this function than to
call it and ignore errors . */
2005-04-13 22:18:04 +04:00
old_fs = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
2006-01-31 19:41:09 +03:00
do_sigaltstack ( ( stack_t __user * ) & st , NULL , regs . regs [ 29 ] ) ;
2005-04-13 22:18:04 +04:00
set_fs ( old_fs ) ;
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 ) ;
}
2007-02-15 14:40:37 +03:00
static int setup_frame_32 ( struct k_sigaction * ka , struct pt_regs * regs ,
2005-11-05 17:00:58 +03:00
int signr , sigset_t * set )
2005-04-17 02:20:36 +04:00
{
2007-02-13 03:50:57 +03:00
struct sigframe32 __user * frame ;
2005-04-17 02:20:36 +04:00
int err = 0 ;
frame = get_sigframe ( ka , regs , sizeof ( * frame ) ) ;
if ( ! access_ok ( VERIFY_WRITE , frame , sizeof ( * frame ) ) )
goto give_sigsegv ;
2007-02-05 17:24:22 +03:00
err | = install_sigtramp ( frame - > sf_code , __NR_O32_sigreturn ) ;
2005-04-17 02:20:36 +04:00
err | = setup_sigcontext32 ( regs , & frame - > sf_sc ) ;
2007-02-13 03:05:11 +03:00
err | = __copy_conv_sigset_to_user ( & frame - > sf_mask , set ) ;
2005-04-17 02:20:36 +04:00
if ( err )
goto give_sigsegv ;
/*
* 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 .
*/
regs - > regs [ 4 ] = signr ;
regs - > regs [ 5 ] = 0 ;
regs - > regs [ 6 ] = ( unsigned long ) & frame - > sf_sc ;
regs - > regs [ 29 ] = ( unsigned long ) frame ;
regs - > regs [ 31 ] = ( unsigned long ) frame - > sf_code ;
regs - > cp0_epc = regs - > regs [ 25 ] = ( unsigned long ) ka - > sa . sa_handler ;
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 ] ) ;
2006-02-08 15:58:41 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
give_sigsegv :
force_sigsegv ( signr , current ) ;
2006-02-08 15:58:41 +03:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
}
2007-02-15 14:40:37 +03:00
static int setup_rt_frame_32 ( struct k_sigaction * ka , struct pt_regs * regs ,
2005-11-05 17:00:58 +03:00
int signr , sigset_t * set , siginfo_t * info )
2005-04-17 02:20:36 +04:00
{
2006-01-31 19:41:09 +03:00
struct rt_sigframe32 __user * frame ;
2005-04-17 02:20:36 +04:00
int err = 0 ;
s32 sp ;
frame = get_sigframe ( ka , regs , sizeof ( * frame ) ) ;
if ( ! access_ok ( VERIFY_WRITE , frame , sizeof ( * frame ) ) )
goto give_sigsegv ;
2007-02-05 17:24:22 +03:00
err | = install_sigtramp ( frame - > rs_code , __NR_O32_rt_sigreturn ) ;
2005-04-17 02:20:36 +04:00
/* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
err | = copy_siginfo_to_user32 ( & frame - > rs_info , info ) ;
/* Create the ucontext. */
err | = __put_user ( 0 , & frame - > rs_uc . uc_flags ) ;
err | = __put_user ( 0 , & frame - > rs_uc . uc_link ) ;
sp = ( int ) ( long ) current - > sas_ss_sp ;
err | = __put_user ( sp ,
& frame - > rs_uc . uc_stack . ss_sp ) ;
err | = __put_user ( sas_ss_flags ( regs - > regs [ 29 ] ) ,
& frame - > rs_uc . uc_stack . ss_flags ) ;
err | = __put_user ( current - > sas_ss_size ,
& frame - > rs_uc . uc_stack . ss_size ) ;
err | = setup_sigcontext32 ( regs , & frame - > rs_uc . uc_mcontext ) ;
2007-02-13 03:05:11 +03:00
err | = __copy_conv_sigset_to_user ( & frame - > rs_uc . uc_sigmask , set ) ;
2005-04-17 02:20:36 +04:00
if ( err )
goto give_sigsegv ;
/*
* 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_sigframe32 .
*/
regs - > regs [ 4 ] = signr ;
regs - > regs [ 5 ] = ( unsigned long ) & frame - > rs_info ;
regs - > regs [ 6 ] = ( unsigned long ) & frame - > rs_uc ;
regs - > regs [ 29 ] = ( unsigned long ) frame ;
regs - > regs [ 31 ] = ( unsigned long ) frame - > rs_code ;
regs - > cp0_epc = regs - > regs [ 25 ] = ( unsigned long ) ka - > sa . sa_handler ;
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 ] ) ;
2006-02-08 15:58:41 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
give_sigsegv :
force_sigsegv ( signr , current ) ;
2006-02-08 15:58:41 +03:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
}
2007-02-15 14:40:37 +03:00
/*
* o32 compatibility on 64 - bit kernels , without DSP ASE
*/
struct mips_abi mips_abi_32 = {
. setup_frame = setup_frame_32 ,
. setup_rt_frame = setup_rt_frame_32 ,
. restart = __NR_O32_restart_syscall
} ;
2005-04-17 02:20:36 +04:00
2006-02-19 17:46:44 +03:00
asmlinkage int sys32_rt_sigaction ( int sig , const struct sigaction32 __user * act ,
2006-01-31 19:41:09 +03:00
struct sigaction32 __user * oact ,
2005-04-17 02:20:36 +04:00
unsigned int sigsetsize )
{
struct k_sigaction new_sa , old_sa ;
int ret = - EINVAL ;
/* XXX: Don't preclude handling different sized sigset_t's. */
if ( sigsetsize ! = sizeof ( sigset_t ) )
goto out ;
if ( act ) {
2005-03-04 22:36:51 +03:00
s32 handler ;
2005-04-17 02:20:36 +04:00
int err = 0 ;
if ( ! access_ok ( VERIFY_READ , act , sizeof ( * act ) ) )
return - EFAULT ;
2005-03-04 22:36:51 +03:00
err | = __get_user ( handler , & act - > sa_handler ) ;
2006-01-31 19:41:09 +03:00
new_sa . sa . sa_handler = ( void __user * ) ( s64 ) handler ;
2005-04-17 02:20:36 +04:00
err | = __get_user ( new_sa . sa . sa_flags , & act - > sa_flags ) ;
err | = get_sigset ( & new_sa . sa . sa_mask , & act - > sa_mask ) ;
if ( err )
return - EFAULT ;
}
ret = do_sigaction ( sig , act ? & new_sa : NULL , oact ? & old_sa : NULL ) ;
if ( ! ret & & oact ) {
int err = 0 ;
if ( ! access_ok ( VERIFY_WRITE , oact , sizeof ( * oact ) ) )
return - EFAULT ;
err | = __put_user ( ( u32 ) ( u64 ) old_sa . sa . sa_handler ,
& oact - > sa_handler ) ;
err | = __put_user ( old_sa . sa . sa_flags , & oact - > sa_flags ) ;
err | = put_sigset ( & old_sa . sa . sa_mask , & oact - > sa_mask ) ;
if ( err )
return - EFAULT ;
}
out :
return ret ;
}
2006-02-19 17:46:44 +03:00
asmlinkage int sys32_rt_sigprocmask ( int how , compat_sigset_t __user * set ,
2006-01-31 19:41:09 +03:00
compat_sigset_t __user * oset , unsigned int sigsetsize )
2005-04-17 02:20:36 +04:00
{
sigset_t old_set , new_set ;
int ret ;
mm_segment_t old_fs = get_fs ( ) ;
if ( set & & get_sigset ( & new_set , set ) )
return - EFAULT ;
set_fs ( KERNEL_DS ) ;
2006-01-31 19:41:09 +03:00
ret = sys_rt_sigprocmask ( how , set ? ( sigset_t __user * ) & new_set : NULL ,
oset ? ( sigset_t __user * ) & old_set : NULL ,
sigsetsize ) ;
2005-04-17 02:20:36 +04:00
set_fs ( old_fs ) ;
if ( ! ret & & oset & & put_sigset ( & old_set , oset ) )
return - EFAULT ;
return ret ;
}
2006-01-31 19:41:09 +03:00
asmlinkage int sys32_rt_sigpending ( compat_sigset_t __user * uset ,
2005-04-17 02:20:36 +04:00
unsigned int sigsetsize )
{
int ret ;
sigset_t set ;
mm_segment_t old_fs = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
2006-01-31 19:41:09 +03:00
ret = sys_rt_sigpending ( ( sigset_t __user * ) & set , sigsetsize ) ;
2005-04-17 02:20:36 +04:00
set_fs ( old_fs ) ;
if ( ! ret & & put_sigset ( & set , uset ) )
return - EFAULT ;
return ret ;
}
2006-01-31 19:41:09 +03:00
asmlinkage int sys32_rt_sigqueueinfo ( int pid , int sig , compat_siginfo_t __user * uinfo )
2005-04-17 02:20:36 +04:00
{
siginfo_t info ;
int ret ;
mm_segment_t old_fs = get_fs ( ) ;
if ( copy_from_user ( & info , uinfo , 3 * sizeof ( int ) ) | |
copy_from_user ( info . _sifields . _pad , uinfo - > _sifields . _pad , SI_PAD_SIZE ) )
return - EFAULT ;
set_fs ( KERNEL_DS ) ;
2006-01-31 19:41:09 +03:00
ret = sys_rt_sigqueueinfo ( pid , sig , ( siginfo_t __user * ) & info ) ;
2005-04-17 02:20:36 +04:00
set_fs ( old_fs ) ;
return ret ;
}
2005-02-17 00:21:29 +03:00
asmlinkage long
sys32_waitid ( int which , compat_pid_t pid ,
compat_siginfo_t __user * uinfo , int options ,
struct compat_rusage __user * uru )
{
siginfo_t info ;
struct rusage ru ;
long ret ;
mm_segment_t old_fs = get_fs ( ) ;
info . si_signo = 0 ;
set_fs ( KERNEL_DS ) ;
ret = sys_waitid ( which , pid , ( siginfo_t __user * ) & info , options ,
uru ? ( struct rusage __user * ) & ru : NULL ) ;
set_fs ( old_fs ) ;
if ( ret < 0 | | info . si_signo = = 0 )
return ret ;
if ( uru & & ( ret = put_compat_rusage ( & ru , uru ) ) )
return ret ;
BUG_ON ( info . si_code & __SI_MASK ) ;
info . si_code | = __SI_CHLD ;
return copy_siginfo_to_user32 ( uinfo , & info ) ;
}