1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 3*1da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 4*1da177e4SLinus Torvalds * for more details. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 7*1da177e4SLinus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle 8*1da177e4SLinus Torvalds * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 9*1da177e4SLinus Torvalds */ 10*1da177e4SLinus Torvalds #include <linux/sched.h> 11*1da177e4SLinus Torvalds #include <linux/mm.h> 12*1da177e4SLinus Torvalds #include <linux/smp.h> 13*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 14*1da177e4SLinus Torvalds #include <linux/kernel.h> 15*1da177e4SLinus Torvalds #include <linux/signal.h> 16*1da177e4SLinus Torvalds #include <linux/syscalls.h> 17*1da177e4SLinus Torvalds #include <linux/errno.h> 18*1da177e4SLinus Torvalds #include <linux/wait.h> 19*1da177e4SLinus Torvalds #include <linux/ptrace.h> 20*1da177e4SLinus Torvalds #include <linux/compat.h> 21*1da177e4SLinus Torvalds #include <linux/suspend.h> 22*1da177e4SLinus Torvalds #include <linux/compiler.h> 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds #include <asm/asm.h> 25*1da177e4SLinus Torvalds #include <linux/bitops.h> 26*1da177e4SLinus Torvalds #include <asm/cacheflush.h> 27*1da177e4SLinus Torvalds #include <asm/sim.h> 28*1da177e4SLinus Torvalds #include <asm/uaccess.h> 29*1da177e4SLinus Torvalds #include <asm/ucontext.h> 30*1da177e4SLinus Torvalds #include <asm/system.h> 31*1da177e4SLinus Torvalds #include <asm/fpu.h> 32*1da177e4SLinus Torvalds 33*1da177e4SLinus Torvalds #define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) 34*1da177e4SLinus Torvalds 35*1da177e4SLinus Torvalds typedef struct compat_siginfo { 36*1da177e4SLinus Torvalds int si_signo; 37*1da177e4SLinus Torvalds int si_code; 38*1da177e4SLinus Torvalds int si_errno; 39*1da177e4SLinus Torvalds 40*1da177e4SLinus Torvalds union { 41*1da177e4SLinus Torvalds int _pad[SI_PAD_SIZE32]; 42*1da177e4SLinus Torvalds 43*1da177e4SLinus Torvalds /* kill() */ 44*1da177e4SLinus Torvalds struct { 45*1da177e4SLinus Torvalds compat_pid_t _pid; /* sender's pid */ 46*1da177e4SLinus Torvalds compat_uid_t _uid; /* sender's uid */ 47*1da177e4SLinus Torvalds } _kill; 48*1da177e4SLinus Torvalds 49*1da177e4SLinus Torvalds /* SIGCHLD */ 50*1da177e4SLinus Torvalds struct { 51*1da177e4SLinus Torvalds compat_pid_t _pid; /* which child */ 52*1da177e4SLinus Torvalds compat_uid_t _uid; /* sender's uid */ 53*1da177e4SLinus Torvalds int _status; /* exit code */ 54*1da177e4SLinus Torvalds compat_clock_t _utime; 55*1da177e4SLinus Torvalds compat_clock_t _stime; 56*1da177e4SLinus Torvalds } _sigchld; 57*1da177e4SLinus Torvalds 58*1da177e4SLinus Torvalds /* IRIX SIGCHLD */ 59*1da177e4SLinus Torvalds struct { 60*1da177e4SLinus Torvalds compat_pid_t _pid; /* which child */ 61*1da177e4SLinus Torvalds compat_clock_t _utime; 62*1da177e4SLinus Torvalds int _status; /* exit code */ 63*1da177e4SLinus Torvalds compat_clock_t _stime; 64*1da177e4SLinus Torvalds } _irix_sigchld; 65*1da177e4SLinus Torvalds 66*1da177e4SLinus Torvalds /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ 67*1da177e4SLinus Torvalds struct { 68*1da177e4SLinus Torvalds s32 _addr; /* faulting insn/memory ref. */ 69*1da177e4SLinus Torvalds } _sigfault; 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds /* SIGPOLL, SIGXFSZ (To do ...) */ 72*1da177e4SLinus Torvalds struct { 73*1da177e4SLinus Torvalds int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ 74*1da177e4SLinus Torvalds int _fd; 75*1da177e4SLinus Torvalds } _sigpoll; 76*1da177e4SLinus Torvalds 77*1da177e4SLinus Torvalds /* POSIX.1b timers */ 78*1da177e4SLinus Torvalds struct { 79*1da177e4SLinus Torvalds unsigned int _timer1; 80*1da177e4SLinus Torvalds unsigned int _timer2; 81*1da177e4SLinus Torvalds } _timer; 82*1da177e4SLinus Torvalds 83*1da177e4SLinus Torvalds /* POSIX.1b signals */ 84*1da177e4SLinus Torvalds struct { 85*1da177e4SLinus Torvalds compat_pid_t _pid; /* sender's pid */ 86*1da177e4SLinus Torvalds compat_uid_t _uid; /* sender's uid */ 87*1da177e4SLinus Torvalds compat_sigval_t _sigval; 88*1da177e4SLinus Torvalds } _rt; 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds } _sifields; 91*1da177e4SLinus Torvalds } compat_siginfo_t; 92*1da177e4SLinus Torvalds 93*1da177e4SLinus Torvalds /* 94*1da177e4SLinus Torvalds * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 95*1da177e4SLinus Torvalds */ 96*1da177e4SLinus Torvalds #define __NR_O32_sigreturn 4119 97*1da177e4SLinus Torvalds #define __NR_O32_rt_sigreturn 4193 98*1da177e4SLinus Torvalds #define __NR_O32_restart_syscall 4253 99*1da177e4SLinus Torvalds 100*1da177e4SLinus Torvalds #define DEBUG_SIG 0 101*1da177e4SLinus Torvalds 102*1da177e4SLinus Torvalds #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); 105*1da177e4SLinus Torvalds 106*1da177e4SLinus Torvalds /* 32-bit compatibility types */ 107*1da177e4SLinus Torvalds 108*1da177e4SLinus Torvalds #define _NSIG_BPW32 32 109*1da177e4SLinus Torvalds #define _NSIG_WORDS32 (_NSIG / _NSIG_BPW32) 110*1da177e4SLinus Torvalds 111*1da177e4SLinus Torvalds typedef struct { 112*1da177e4SLinus Torvalds unsigned int sig[_NSIG_WORDS32]; 113*1da177e4SLinus Torvalds } sigset_t32; 114*1da177e4SLinus Torvalds 115*1da177e4SLinus Torvalds typedef unsigned int __sighandler32_t; 116*1da177e4SLinus Torvalds typedef void (*vfptr_t)(void); 117*1da177e4SLinus Torvalds 118*1da177e4SLinus Torvalds struct sigaction32 { 119*1da177e4SLinus Torvalds unsigned int sa_flags; 120*1da177e4SLinus Torvalds __sighandler32_t sa_handler; 121*1da177e4SLinus Torvalds compat_sigset_t sa_mask; 122*1da177e4SLinus Torvalds }; 123*1da177e4SLinus Torvalds 124*1da177e4SLinus Torvalds /* IRIX compatible stack_t */ 125*1da177e4SLinus Torvalds typedef struct sigaltstack32 { 126*1da177e4SLinus Torvalds s32 ss_sp; 127*1da177e4SLinus Torvalds compat_size_t ss_size; 128*1da177e4SLinus Torvalds int ss_flags; 129*1da177e4SLinus Torvalds } stack32_t; 130*1da177e4SLinus Torvalds 131*1da177e4SLinus Torvalds struct ucontext32 { 132*1da177e4SLinus Torvalds u32 uc_flags; 133*1da177e4SLinus Torvalds s32 uc_link; 134*1da177e4SLinus Torvalds stack32_t uc_stack; 135*1da177e4SLinus Torvalds struct sigcontext32 uc_mcontext; 136*1da177e4SLinus Torvalds sigset_t32 uc_sigmask; /* mask last for extensibility */ 137*1da177e4SLinus Torvalds }; 138*1da177e4SLinus Torvalds 139*1da177e4SLinus Torvalds extern void __put_sigset_unknown_nsig(void); 140*1da177e4SLinus Torvalds extern void __get_sigset_unknown_nsig(void); 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t *ubuf) 143*1da177e4SLinus Torvalds { 144*1da177e4SLinus Torvalds int err = 0; 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) 147*1da177e4SLinus Torvalds return -EFAULT; 148*1da177e4SLinus Torvalds 149*1da177e4SLinus Torvalds switch (_NSIG_WORDS) { 150*1da177e4SLinus Torvalds default: 151*1da177e4SLinus Torvalds __put_sigset_unknown_nsig(); 152*1da177e4SLinus Torvalds case 2: 153*1da177e4SLinus Torvalds err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]); 154*1da177e4SLinus Torvalds err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); 155*1da177e4SLinus Torvalds case 1: 156*1da177e4SLinus Torvalds err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]); 157*1da177e4SLinus Torvalds err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); 158*1da177e4SLinus Torvalds } 159*1da177e4SLinus Torvalds 160*1da177e4SLinus Torvalds return err; 161*1da177e4SLinus Torvalds } 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t *ubuf) 164*1da177e4SLinus Torvalds { 165*1da177e4SLinus Torvalds int err = 0; 166*1da177e4SLinus Torvalds unsigned long sig[4]; 167*1da177e4SLinus Torvalds 168*1da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) 169*1da177e4SLinus Torvalds return -EFAULT; 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds switch (_NSIG_WORDS) { 172*1da177e4SLinus Torvalds default: 173*1da177e4SLinus Torvalds __get_sigset_unknown_nsig(); 174*1da177e4SLinus Torvalds case 2: 175*1da177e4SLinus Torvalds err |= __get_user (sig[3], &ubuf->sig[3]); 176*1da177e4SLinus Torvalds err |= __get_user (sig[2], &ubuf->sig[2]); 177*1da177e4SLinus Torvalds kbuf->sig[1] = sig[2] | (sig[3] << 32); 178*1da177e4SLinus Torvalds case 1: 179*1da177e4SLinus Torvalds err |= __get_user (sig[1], &ubuf->sig[1]); 180*1da177e4SLinus Torvalds err |= __get_user (sig[0], &ubuf->sig[0]); 181*1da177e4SLinus Torvalds kbuf->sig[0] = sig[0] | (sig[1] << 32); 182*1da177e4SLinus Torvalds } 183*1da177e4SLinus Torvalds 184*1da177e4SLinus Torvalds return err; 185*1da177e4SLinus Torvalds } 186*1da177e4SLinus Torvalds 187*1da177e4SLinus Torvalds /* 188*1da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 189*1da177e4SLinus Torvalds */ 190*1da177e4SLinus Torvalds 191*1da177e4SLinus Torvalds save_static_function(sys32_sigsuspend); 192*1da177e4SLinus Torvalds __attribute_used__ noinline static int 193*1da177e4SLinus Torvalds _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) 194*1da177e4SLinus Torvalds { 195*1da177e4SLinus Torvalds compat_sigset_t *uset; 196*1da177e4SLinus Torvalds sigset_t newset, saveset; 197*1da177e4SLinus Torvalds 198*1da177e4SLinus Torvalds uset = (compat_sigset_t *) regs.regs[4]; 199*1da177e4SLinus Torvalds if (get_sigset(&newset, uset)) 200*1da177e4SLinus Torvalds return -EFAULT; 201*1da177e4SLinus Torvalds sigdelsetmask(&newset, ~_BLOCKABLE); 202*1da177e4SLinus Torvalds 203*1da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 204*1da177e4SLinus Torvalds saveset = current->blocked; 205*1da177e4SLinus Torvalds current->blocked = newset; 206*1da177e4SLinus Torvalds recalc_sigpending(); 207*1da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 208*1da177e4SLinus Torvalds 209*1da177e4SLinus Torvalds regs.regs[2] = EINTR; 210*1da177e4SLinus Torvalds regs.regs[7] = 1; 211*1da177e4SLinus Torvalds while (1) { 212*1da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 213*1da177e4SLinus Torvalds schedule(); 214*1da177e4SLinus Torvalds if (do_signal32(&saveset, ®s)) 215*1da177e4SLinus Torvalds return -EINTR; 216*1da177e4SLinus Torvalds } 217*1da177e4SLinus Torvalds } 218*1da177e4SLinus Torvalds 219*1da177e4SLinus Torvalds save_static_function(sys32_rt_sigsuspend); 220*1da177e4SLinus Torvalds __attribute_used__ noinline static int 221*1da177e4SLinus Torvalds _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) 222*1da177e4SLinus Torvalds { 223*1da177e4SLinus Torvalds compat_sigset_t *uset; 224*1da177e4SLinus Torvalds sigset_t newset, saveset; 225*1da177e4SLinus Torvalds size_t sigsetsize; 226*1da177e4SLinus Torvalds 227*1da177e4SLinus Torvalds /* XXX Don't preclude handling different sized sigset_t's. */ 228*1da177e4SLinus Torvalds sigsetsize = regs.regs[5]; 229*1da177e4SLinus Torvalds if (sigsetsize != sizeof(compat_sigset_t)) 230*1da177e4SLinus Torvalds return -EINVAL; 231*1da177e4SLinus Torvalds 232*1da177e4SLinus Torvalds uset = (compat_sigset_t *) regs.regs[4]; 233*1da177e4SLinus Torvalds if (get_sigset(&newset, uset)) 234*1da177e4SLinus Torvalds return -EFAULT; 235*1da177e4SLinus Torvalds sigdelsetmask(&newset, ~_BLOCKABLE); 236*1da177e4SLinus Torvalds 237*1da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 238*1da177e4SLinus Torvalds saveset = current->blocked; 239*1da177e4SLinus Torvalds current->blocked = newset; 240*1da177e4SLinus Torvalds recalc_sigpending(); 241*1da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 242*1da177e4SLinus Torvalds 243*1da177e4SLinus Torvalds regs.regs[2] = EINTR; 244*1da177e4SLinus Torvalds regs.regs[7] = 1; 245*1da177e4SLinus Torvalds while (1) { 246*1da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 247*1da177e4SLinus Torvalds schedule(); 248*1da177e4SLinus Torvalds if (do_signal32(&saveset, ®s)) 249*1da177e4SLinus Torvalds return -EINTR; 250*1da177e4SLinus Torvalds } 251*1da177e4SLinus Torvalds } 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, 254*1da177e4SLinus Torvalds struct sigaction32 *oact) 255*1da177e4SLinus Torvalds { 256*1da177e4SLinus Torvalds struct k_sigaction new_ka, old_ka; 257*1da177e4SLinus Torvalds int ret; 258*1da177e4SLinus Torvalds int err = 0; 259*1da177e4SLinus Torvalds 260*1da177e4SLinus Torvalds if (act) { 261*1da177e4SLinus Torvalds old_sigset_t mask; 262*1da177e4SLinus Torvalds 263*1da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, act, sizeof(*act))) 264*1da177e4SLinus Torvalds return -EFAULT; 265*1da177e4SLinus Torvalds err |= __get_user((u32)(u64)new_ka.sa.sa_handler, 266*1da177e4SLinus Torvalds &act->sa_handler); 267*1da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 268*1da177e4SLinus Torvalds err |= __get_user(mask, &act->sa_mask.sig[0]); 269*1da177e4SLinus Torvalds if (err) 270*1da177e4SLinus Torvalds return -EFAULT; 271*1da177e4SLinus Torvalds 272*1da177e4SLinus Torvalds siginitset(&new_ka.sa.sa_mask, mask); 273*1da177e4SLinus Torvalds } 274*1da177e4SLinus Torvalds 275*1da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 276*1da177e4SLinus Torvalds 277*1da177e4SLinus Torvalds if (!ret && oact) { 278*1da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 279*1da177e4SLinus Torvalds return -EFAULT; 280*1da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 281*1da177e4SLinus Torvalds err |= __put_user((u32)(u64)old_ka.sa.sa_handler, 282*1da177e4SLinus Torvalds &oact->sa_handler); 283*1da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 284*1da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[1]); 285*1da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[2]); 286*1da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[3]); 287*1da177e4SLinus Torvalds if (err) 288*1da177e4SLinus Torvalds return -EFAULT; 289*1da177e4SLinus Torvalds } 290*1da177e4SLinus Torvalds 291*1da177e4SLinus Torvalds return ret; 292*1da177e4SLinus Torvalds } 293*1da177e4SLinus Torvalds 294*1da177e4SLinus Torvalds asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) 295*1da177e4SLinus Torvalds { 296*1da177e4SLinus Torvalds const stack32_t *uss = (const stack32_t *) regs.regs[4]; 297*1da177e4SLinus Torvalds stack32_t *uoss = (stack32_t *) regs.regs[5]; 298*1da177e4SLinus Torvalds unsigned long usp = regs.regs[29]; 299*1da177e4SLinus Torvalds stack_t kss, koss; 300*1da177e4SLinus Torvalds int ret, err = 0; 301*1da177e4SLinus Torvalds mm_segment_t old_fs = get_fs(); 302*1da177e4SLinus Torvalds s32 sp; 303*1da177e4SLinus Torvalds 304*1da177e4SLinus Torvalds if (uss) { 305*1da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) 306*1da177e4SLinus Torvalds return -EFAULT; 307*1da177e4SLinus Torvalds err |= __get_user(sp, &uss->ss_sp); 308*1da177e4SLinus Torvalds kss.ss_sp = (void *) (long) sp; 309*1da177e4SLinus Torvalds err |= __get_user(kss.ss_size, &uss->ss_size); 310*1da177e4SLinus Torvalds err |= __get_user(kss.ss_flags, &uss->ss_flags); 311*1da177e4SLinus Torvalds if (err) 312*1da177e4SLinus Torvalds return -EFAULT; 313*1da177e4SLinus Torvalds } 314*1da177e4SLinus Torvalds 315*1da177e4SLinus Torvalds set_fs (KERNEL_DS); 316*1da177e4SLinus Torvalds ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, usp); 317*1da177e4SLinus Torvalds set_fs (old_fs); 318*1da177e4SLinus Torvalds 319*1da177e4SLinus Torvalds if (!ret && uoss) { 320*1da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) 321*1da177e4SLinus Torvalds return -EFAULT; 322*1da177e4SLinus Torvalds sp = (int) (long) koss.ss_sp; 323*1da177e4SLinus Torvalds err |= __put_user(sp, &uoss->ss_sp); 324*1da177e4SLinus Torvalds err |= __put_user(koss.ss_size, &uoss->ss_size); 325*1da177e4SLinus Torvalds err |= __put_user(koss.ss_flags, &uoss->ss_flags); 326*1da177e4SLinus Torvalds if (err) 327*1da177e4SLinus Torvalds return -EFAULT; 328*1da177e4SLinus Torvalds } 329*1da177e4SLinus Torvalds return ret; 330*1da177e4SLinus Torvalds } 331*1da177e4SLinus Torvalds 332*1da177e4SLinus Torvalds static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) 333*1da177e4SLinus Torvalds { 334*1da177e4SLinus Torvalds int err = 0; 335*1da177e4SLinus Torvalds __u32 used_math; 336*1da177e4SLinus Torvalds 337*1da177e4SLinus Torvalds /* Always make any pending restarted system calls return -EINTR */ 338*1da177e4SLinus Torvalds current_thread_info()->restart_block.fn = do_no_restart_syscall; 339*1da177e4SLinus Torvalds 340*1da177e4SLinus Torvalds err |= __get_user(regs->cp0_epc, &sc->sc_pc); 341*1da177e4SLinus Torvalds err |= __get_user(regs->hi, &sc->sc_mdhi); 342*1da177e4SLinus Torvalds err |= __get_user(regs->lo, &sc->sc_mdlo); 343*1da177e4SLinus Torvalds 344*1da177e4SLinus Torvalds #define restore_gp_reg(i) do { \ 345*1da177e4SLinus Torvalds err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ 346*1da177e4SLinus Torvalds } while(0) 347*1da177e4SLinus Torvalds restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); 348*1da177e4SLinus Torvalds restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); 349*1da177e4SLinus Torvalds restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); 350*1da177e4SLinus Torvalds restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); 351*1da177e4SLinus Torvalds restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); 352*1da177e4SLinus Torvalds restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); 353*1da177e4SLinus Torvalds restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); 354*1da177e4SLinus Torvalds restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); 355*1da177e4SLinus Torvalds restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); 356*1da177e4SLinus Torvalds restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); 357*1da177e4SLinus Torvalds restore_gp_reg(31); 358*1da177e4SLinus Torvalds #undef restore_gp_reg 359*1da177e4SLinus Torvalds 360*1da177e4SLinus Torvalds err |= __get_user(used_math, &sc->sc_used_math); 361*1da177e4SLinus Torvalds conditional_used_math(used_math); 362*1da177e4SLinus Torvalds 363*1da177e4SLinus Torvalds preempt_disable(); 364*1da177e4SLinus Torvalds 365*1da177e4SLinus Torvalds if (used_math()) { 366*1da177e4SLinus Torvalds /* restore fpu context if we have used it before */ 367*1da177e4SLinus Torvalds own_fpu(); 368*1da177e4SLinus Torvalds err |= restore_fp_context32(sc); 369*1da177e4SLinus Torvalds } else { 370*1da177e4SLinus Torvalds /* signal handler may have used FPU. Give it up. */ 371*1da177e4SLinus Torvalds lose_fpu(); 372*1da177e4SLinus Torvalds } 373*1da177e4SLinus Torvalds 374*1da177e4SLinus Torvalds preempt_enable(); 375*1da177e4SLinus Torvalds 376*1da177e4SLinus Torvalds return err; 377*1da177e4SLinus Torvalds } 378*1da177e4SLinus Torvalds 379*1da177e4SLinus Torvalds struct sigframe { 380*1da177e4SLinus Torvalds u32 sf_ass[4]; /* argument save space for o32 */ 381*1da177e4SLinus Torvalds u32 sf_code[2]; /* signal trampoline */ 382*1da177e4SLinus Torvalds struct sigcontext32 sf_sc; 383*1da177e4SLinus Torvalds sigset_t sf_mask; 384*1da177e4SLinus Torvalds }; 385*1da177e4SLinus Torvalds 386*1da177e4SLinus Torvalds struct rt_sigframe32 { 387*1da177e4SLinus Torvalds u32 rs_ass[4]; /* argument save space for o32 */ 388*1da177e4SLinus Torvalds u32 rs_code[2]; /* signal trampoline */ 389*1da177e4SLinus Torvalds compat_siginfo_t rs_info; 390*1da177e4SLinus Torvalds struct ucontext32 rs_uc; 391*1da177e4SLinus Torvalds }; 392*1da177e4SLinus Torvalds 393*1da177e4SLinus Torvalds int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from) 394*1da177e4SLinus Torvalds { 395*1da177e4SLinus Torvalds int err; 396*1da177e4SLinus Torvalds 397*1da177e4SLinus Torvalds if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) 398*1da177e4SLinus Torvalds return -EFAULT; 399*1da177e4SLinus Torvalds 400*1da177e4SLinus Torvalds /* If you change siginfo_t structure, please be sure 401*1da177e4SLinus Torvalds this code is fixed accordingly. 402*1da177e4SLinus Torvalds It should never copy any pad contained in the structure 403*1da177e4SLinus Torvalds to avoid security leaks, but must copy the generic 404*1da177e4SLinus Torvalds 3 ints plus the relevant union member. 405*1da177e4SLinus Torvalds This routine must convert siginfo from 64bit to 32bit as well 406*1da177e4SLinus Torvalds at the same time. */ 407*1da177e4SLinus Torvalds err = __put_user(from->si_signo, &to->si_signo); 408*1da177e4SLinus Torvalds err |= __put_user(from->si_errno, &to->si_errno); 409*1da177e4SLinus Torvalds err |= __put_user((short)from->si_code, &to->si_code); 410*1da177e4SLinus Torvalds if (from->si_code < 0) 411*1da177e4SLinus Torvalds err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); 412*1da177e4SLinus Torvalds else { 413*1da177e4SLinus Torvalds switch (from->si_code >> 16) { 414*1da177e4SLinus Torvalds case __SI_CHLD >> 16: 415*1da177e4SLinus Torvalds err |= __put_user(from->si_utime, &to->si_utime); 416*1da177e4SLinus Torvalds err |= __put_user(from->si_stime, &to->si_stime); 417*1da177e4SLinus Torvalds err |= __put_user(from->si_status, &to->si_status); 418*1da177e4SLinus Torvalds default: 419*1da177e4SLinus Torvalds err |= __put_user(from->si_pid, &to->si_pid); 420*1da177e4SLinus Torvalds err |= __put_user(from->si_uid, &to->si_uid); 421*1da177e4SLinus Torvalds break; 422*1da177e4SLinus Torvalds case __SI_FAULT >> 16: 423*1da177e4SLinus Torvalds err |= __put_user((long)from->si_addr, &to->si_addr); 424*1da177e4SLinus Torvalds break; 425*1da177e4SLinus Torvalds case __SI_POLL >> 16: 426*1da177e4SLinus Torvalds err |= __put_user(from->si_band, &to->si_band); 427*1da177e4SLinus Torvalds err |= __put_user(from->si_fd, &to->si_fd); 428*1da177e4SLinus Torvalds break; 429*1da177e4SLinus Torvalds case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ 430*1da177e4SLinus Torvalds case __SI_MESGQ >> 16: 431*1da177e4SLinus Torvalds err |= __put_user(from->si_pid, &to->si_pid); 432*1da177e4SLinus Torvalds err |= __put_user(from->si_uid, &to->si_uid); 433*1da177e4SLinus Torvalds err |= __put_user(from->si_int, &to->si_int); 434*1da177e4SLinus Torvalds break; 435*1da177e4SLinus Torvalds } 436*1da177e4SLinus Torvalds } 437*1da177e4SLinus Torvalds return err; 438*1da177e4SLinus Torvalds } 439*1da177e4SLinus Torvalds 440*1da177e4SLinus Torvalds save_static_function(sys32_sigreturn); 441*1da177e4SLinus Torvalds __attribute_used__ noinline static void 442*1da177e4SLinus Torvalds _sys32_sigreturn(nabi_no_regargs struct pt_regs regs) 443*1da177e4SLinus Torvalds { 444*1da177e4SLinus Torvalds struct sigframe *frame; 445*1da177e4SLinus Torvalds sigset_t blocked; 446*1da177e4SLinus Torvalds 447*1da177e4SLinus Torvalds frame = (struct sigframe *) regs.regs[29]; 448*1da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 449*1da177e4SLinus Torvalds goto badframe; 450*1da177e4SLinus Torvalds if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) 451*1da177e4SLinus Torvalds goto badframe; 452*1da177e4SLinus Torvalds 453*1da177e4SLinus Torvalds sigdelsetmask(&blocked, ~_BLOCKABLE); 454*1da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 455*1da177e4SLinus Torvalds current->blocked = blocked; 456*1da177e4SLinus Torvalds recalc_sigpending(); 457*1da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 458*1da177e4SLinus Torvalds 459*1da177e4SLinus Torvalds if (restore_sigcontext32(®s, &frame->sf_sc)) 460*1da177e4SLinus Torvalds goto badframe; 461*1da177e4SLinus Torvalds 462*1da177e4SLinus Torvalds /* 463*1da177e4SLinus Torvalds * Don't let your children do this ... 464*1da177e4SLinus Torvalds */ 465*1da177e4SLinus Torvalds if (current_thread_info()->flags & TIF_SYSCALL_TRACE) 466*1da177e4SLinus Torvalds do_syscall_trace(®s, 1); 467*1da177e4SLinus Torvalds __asm__ __volatile__( 468*1da177e4SLinus Torvalds "move\t$29, %0\n\t" 469*1da177e4SLinus Torvalds "j\tsyscall_exit" 470*1da177e4SLinus Torvalds :/* no outputs */ 471*1da177e4SLinus Torvalds :"r" (®s)); 472*1da177e4SLinus Torvalds /* Unreached */ 473*1da177e4SLinus Torvalds 474*1da177e4SLinus Torvalds badframe: 475*1da177e4SLinus Torvalds force_sig(SIGSEGV, current); 476*1da177e4SLinus Torvalds } 477*1da177e4SLinus Torvalds 478*1da177e4SLinus Torvalds save_static_function(sys32_rt_sigreturn); 479*1da177e4SLinus Torvalds __attribute_used__ noinline static void 480*1da177e4SLinus Torvalds _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) 481*1da177e4SLinus Torvalds { 482*1da177e4SLinus Torvalds struct rt_sigframe32 *frame; 483*1da177e4SLinus Torvalds sigset_t set; 484*1da177e4SLinus Torvalds stack_t st; 485*1da177e4SLinus Torvalds s32 sp; 486*1da177e4SLinus Torvalds 487*1da177e4SLinus Torvalds frame = (struct rt_sigframe32 *) regs.regs[29]; 488*1da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 489*1da177e4SLinus Torvalds goto badframe; 490*1da177e4SLinus Torvalds if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 491*1da177e4SLinus Torvalds goto badframe; 492*1da177e4SLinus Torvalds 493*1da177e4SLinus Torvalds sigdelsetmask(&set, ~_BLOCKABLE); 494*1da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 495*1da177e4SLinus Torvalds current->blocked = set; 496*1da177e4SLinus Torvalds recalc_sigpending(); 497*1da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 498*1da177e4SLinus Torvalds 499*1da177e4SLinus Torvalds if (restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext)) 500*1da177e4SLinus Torvalds goto badframe; 501*1da177e4SLinus Torvalds 502*1da177e4SLinus Torvalds /* The ucontext contains a stack32_t, so we must convert! */ 503*1da177e4SLinus Torvalds if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) 504*1da177e4SLinus Torvalds goto badframe; 505*1da177e4SLinus Torvalds st.ss_size = (long) sp; 506*1da177e4SLinus Torvalds if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size)) 507*1da177e4SLinus Torvalds goto badframe; 508*1da177e4SLinus Torvalds if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags)) 509*1da177e4SLinus Torvalds goto badframe; 510*1da177e4SLinus Torvalds 511*1da177e4SLinus Torvalds /* It is more difficult to avoid calling this function than to 512*1da177e4SLinus Torvalds call it and ignore errors. */ 513*1da177e4SLinus Torvalds do_sigaltstack(&st, NULL, regs.regs[29]); 514*1da177e4SLinus Torvalds 515*1da177e4SLinus Torvalds /* 516*1da177e4SLinus Torvalds * Don't let your children do this ... 517*1da177e4SLinus Torvalds */ 518*1da177e4SLinus Torvalds __asm__ __volatile__( 519*1da177e4SLinus Torvalds "move\t$29, %0\n\t" 520*1da177e4SLinus Torvalds "j\tsyscall_exit" 521*1da177e4SLinus Torvalds :/* no outputs */ 522*1da177e4SLinus Torvalds :"r" (®s)); 523*1da177e4SLinus Torvalds /* Unreached */ 524*1da177e4SLinus Torvalds 525*1da177e4SLinus Torvalds badframe: 526*1da177e4SLinus Torvalds force_sig(SIGSEGV, current); 527*1da177e4SLinus Torvalds } 528*1da177e4SLinus Torvalds 529*1da177e4SLinus Torvalds static inline int setup_sigcontext32(struct pt_regs *regs, 530*1da177e4SLinus Torvalds struct sigcontext32 *sc) 531*1da177e4SLinus Torvalds { 532*1da177e4SLinus Torvalds int err = 0; 533*1da177e4SLinus Torvalds 534*1da177e4SLinus Torvalds err |= __put_user(regs->cp0_epc, &sc->sc_pc); 535*1da177e4SLinus Torvalds err |= __put_user(regs->cp0_status, &sc->sc_status); 536*1da177e4SLinus Torvalds 537*1da177e4SLinus Torvalds #define save_gp_reg(i) { \ 538*1da177e4SLinus Torvalds err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ 539*1da177e4SLinus Torvalds } while(0) 540*1da177e4SLinus Torvalds __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); 541*1da177e4SLinus Torvalds save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); 542*1da177e4SLinus Torvalds save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); 543*1da177e4SLinus Torvalds save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); 544*1da177e4SLinus Torvalds save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); 545*1da177e4SLinus Torvalds save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); 546*1da177e4SLinus Torvalds save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); 547*1da177e4SLinus Torvalds save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); 548*1da177e4SLinus Torvalds save_gp_reg(31); 549*1da177e4SLinus Torvalds #undef save_gp_reg 550*1da177e4SLinus Torvalds 551*1da177e4SLinus Torvalds err |= __put_user(regs->hi, &sc->sc_mdhi); 552*1da177e4SLinus Torvalds err |= __put_user(regs->lo, &sc->sc_mdlo); 553*1da177e4SLinus Torvalds err |= __put_user(regs->cp0_cause, &sc->sc_cause); 554*1da177e4SLinus Torvalds err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); 555*1da177e4SLinus Torvalds 556*1da177e4SLinus Torvalds err |= __put_user(!!used_math(), &sc->sc_used_math); 557*1da177e4SLinus Torvalds 558*1da177e4SLinus Torvalds if (!used_math()) 559*1da177e4SLinus Torvalds goto out; 560*1da177e4SLinus Torvalds 561*1da177e4SLinus Torvalds /* 562*1da177e4SLinus Torvalds * Save FPU state to signal context. Signal handler will "inherit" 563*1da177e4SLinus Torvalds * current FPU state. 564*1da177e4SLinus Torvalds */ 565*1da177e4SLinus Torvalds preempt_disable(); 566*1da177e4SLinus Torvalds 567*1da177e4SLinus Torvalds if (!is_fpu_owner()) { 568*1da177e4SLinus Torvalds own_fpu(); 569*1da177e4SLinus Torvalds restore_fp(current); 570*1da177e4SLinus Torvalds } 571*1da177e4SLinus Torvalds err |= save_fp_context32(sc); 572*1da177e4SLinus Torvalds 573*1da177e4SLinus Torvalds preempt_enable(); 574*1da177e4SLinus Torvalds 575*1da177e4SLinus Torvalds out: 576*1da177e4SLinus Torvalds return err; 577*1da177e4SLinus Torvalds } 578*1da177e4SLinus Torvalds 579*1da177e4SLinus Torvalds /* 580*1da177e4SLinus Torvalds * Determine which stack to use.. 581*1da177e4SLinus Torvalds */ 582*1da177e4SLinus Torvalds static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 583*1da177e4SLinus Torvalds size_t frame_size) 584*1da177e4SLinus Torvalds { 585*1da177e4SLinus Torvalds unsigned long sp; 586*1da177e4SLinus Torvalds 587*1da177e4SLinus Torvalds /* Default to using normal stack */ 588*1da177e4SLinus Torvalds sp = regs->regs[29]; 589*1da177e4SLinus Torvalds 590*1da177e4SLinus Torvalds /* 591*1da177e4SLinus Torvalds * FPU emulator may have it's own trampoline active just 592*1da177e4SLinus Torvalds * above the user stack, 16-bytes before the next lowest 593*1da177e4SLinus Torvalds * 16 byte boundary. Try to avoid trashing it. 594*1da177e4SLinus Torvalds */ 595*1da177e4SLinus Torvalds sp -= 32; 596*1da177e4SLinus Torvalds 597*1da177e4SLinus Torvalds /* This is the X/Open sanctioned signal stack switching. */ 598*1da177e4SLinus Torvalds if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) 599*1da177e4SLinus Torvalds sp = current->sas_ss_sp + current->sas_ss_size; 600*1da177e4SLinus Torvalds 601*1da177e4SLinus Torvalds return (void *)((sp - frame_size) & ALMASK); 602*1da177e4SLinus Torvalds } 603*1da177e4SLinus Torvalds 604*1da177e4SLinus Torvalds static inline void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, 605*1da177e4SLinus Torvalds int signr, sigset_t *set) 606*1da177e4SLinus Torvalds { 607*1da177e4SLinus Torvalds struct sigframe *frame; 608*1da177e4SLinus Torvalds int err = 0; 609*1da177e4SLinus Torvalds 610*1da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 611*1da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 612*1da177e4SLinus Torvalds goto give_sigsegv; 613*1da177e4SLinus Torvalds 614*1da177e4SLinus Torvalds /* 615*1da177e4SLinus Torvalds * Set up the return code ... 616*1da177e4SLinus Torvalds * 617*1da177e4SLinus Torvalds * li v0, __NR_O32_sigreturn 618*1da177e4SLinus Torvalds * syscall 619*1da177e4SLinus Torvalds */ 620*1da177e4SLinus Torvalds err |= __put_user(0x24020000 + __NR_O32_sigreturn, frame->sf_code + 0); 621*1da177e4SLinus Torvalds err |= __put_user(0x0000000c , frame->sf_code + 1); 622*1da177e4SLinus Torvalds flush_cache_sigtramp((unsigned long) frame->sf_code); 623*1da177e4SLinus Torvalds 624*1da177e4SLinus Torvalds err |= setup_sigcontext32(regs, &frame->sf_sc); 625*1da177e4SLinus Torvalds err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 626*1da177e4SLinus Torvalds if (err) 627*1da177e4SLinus Torvalds goto give_sigsegv; 628*1da177e4SLinus Torvalds 629*1da177e4SLinus Torvalds /* 630*1da177e4SLinus Torvalds * Arguments to signal handler: 631*1da177e4SLinus Torvalds * 632*1da177e4SLinus Torvalds * a0 = signal number 633*1da177e4SLinus Torvalds * a1 = 0 (should be cause) 634*1da177e4SLinus Torvalds * a2 = pointer to struct sigcontext 635*1da177e4SLinus Torvalds * 636*1da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to the 637*1da177e4SLinus Torvalds * struct sigframe. 638*1da177e4SLinus Torvalds */ 639*1da177e4SLinus Torvalds regs->regs[ 4] = signr; 640*1da177e4SLinus Torvalds regs->regs[ 5] = 0; 641*1da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->sf_sc; 642*1da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 643*1da177e4SLinus Torvalds regs->regs[31] = (unsigned long) frame->sf_code; 644*1da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 645*1da177e4SLinus Torvalds 646*1da177e4SLinus Torvalds #if DEBUG_SIG 647*1da177e4SLinus Torvalds printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", 648*1da177e4SLinus Torvalds current->comm, current->pid, 649*1da177e4SLinus Torvalds frame, regs->cp0_epc, frame->sf_code); 650*1da177e4SLinus Torvalds #endif 651*1da177e4SLinus Torvalds return; 652*1da177e4SLinus Torvalds 653*1da177e4SLinus Torvalds give_sigsegv: 654*1da177e4SLinus Torvalds force_sigsegv(signr, current); 655*1da177e4SLinus Torvalds } 656*1da177e4SLinus Torvalds 657*1da177e4SLinus Torvalds static inline void setup_rt_frame(struct k_sigaction * ka, 658*1da177e4SLinus Torvalds struct pt_regs *regs, int signr, 659*1da177e4SLinus Torvalds sigset_t *set, siginfo_t *info) 660*1da177e4SLinus Torvalds { 661*1da177e4SLinus Torvalds struct rt_sigframe32 *frame; 662*1da177e4SLinus Torvalds int err = 0; 663*1da177e4SLinus Torvalds s32 sp; 664*1da177e4SLinus Torvalds 665*1da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 666*1da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 667*1da177e4SLinus Torvalds goto give_sigsegv; 668*1da177e4SLinus Torvalds 669*1da177e4SLinus Torvalds /* Set up to return from userspace. If provided, use a stub already 670*1da177e4SLinus Torvalds in userspace. */ 671*1da177e4SLinus Torvalds /* 672*1da177e4SLinus Torvalds * Set up the return code ... 673*1da177e4SLinus Torvalds * 674*1da177e4SLinus Torvalds * li v0, __NR_O32_rt_sigreturn 675*1da177e4SLinus Torvalds * syscall 676*1da177e4SLinus Torvalds */ 677*1da177e4SLinus Torvalds err |= __put_user(0x24020000 + __NR_O32_rt_sigreturn, frame->rs_code + 0); 678*1da177e4SLinus Torvalds err |= __put_user(0x0000000c , frame->rs_code + 1); 679*1da177e4SLinus Torvalds flush_cache_sigtramp((unsigned long) frame->rs_code); 680*1da177e4SLinus Torvalds 681*1da177e4SLinus Torvalds /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ 682*1da177e4SLinus Torvalds err |= copy_siginfo_to_user32(&frame->rs_info, info); 683*1da177e4SLinus Torvalds 684*1da177e4SLinus Torvalds /* Create the ucontext. */ 685*1da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 686*1da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_link); 687*1da177e4SLinus Torvalds sp = (int) (long) current->sas_ss_sp; 688*1da177e4SLinus Torvalds err |= __put_user(sp, 689*1da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_sp); 690*1da177e4SLinus Torvalds err |= __put_user(sas_ss_flags(regs->regs[29]), 691*1da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_flags); 692*1da177e4SLinus Torvalds err |= __put_user(current->sas_ss_size, 693*1da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_size); 694*1da177e4SLinus Torvalds err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); 695*1da177e4SLinus Torvalds err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 696*1da177e4SLinus Torvalds 697*1da177e4SLinus Torvalds if (err) 698*1da177e4SLinus Torvalds goto give_sigsegv; 699*1da177e4SLinus Torvalds 700*1da177e4SLinus Torvalds /* 701*1da177e4SLinus Torvalds * Arguments to signal handler: 702*1da177e4SLinus Torvalds * 703*1da177e4SLinus Torvalds * a0 = signal number 704*1da177e4SLinus Torvalds * a1 = 0 (should be cause) 705*1da177e4SLinus Torvalds * a2 = pointer to ucontext 706*1da177e4SLinus Torvalds * 707*1da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 708*1da177e4SLinus Torvalds * the struct rt_sigframe32. 709*1da177e4SLinus Torvalds */ 710*1da177e4SLinus Torvalds regs->regs[ 4] = signr; 711*1da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 712*1da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 713*1da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 714*1da177e4SLinus Torvalds regs->regs[31] = (unsigned long) frame->rs_code; 715*1da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 716*1da177e4SLinus Torvalds 717*1da177e4SLinus Torvalds #if DEBUG_SIG 718*1da177e4SLinus Torvalds printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", 719*1da177e4SLinus Torvalds current->comm, current->pid, 720*1da177e4SLinus Torvalds frame, regs->cp0_epc, frame->rs_code); 721*1da177e4SLinus Torvalds #endif 722*1da177e4SLinus Torvalds return; 723*1da177e4SLinus Torvalds 724*1da177e4SLinus Torvalds give_sigsegv: 725*1da177e4SLinus Torvalds force_sigsegv(signr, current); 726*1da177e4SLinus Torvalds } 727*1da177e4SLinus Torvalds 728*1da177e4SLinus Torvalds static inline void handle_signal(unsigned long sig, siginfo_t *info, 729*1da177e4SLinus Torvalds struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) 730*1da177e4SLinus Torvalds { 731*1da177e4SLinus Torvalds switch (regs->regs[0]) { 732*1da177e4SLinus Torvalds case ERESTART_RESTARTBLOCK: 733*1da177e4SLinus Torvalds case ERESTARTNOHAND: 734*1da177e4SLinus Torvalds regs->regs[2] = EINTR; 735*1da177e4SLinus Torvalds break; 736*1da177e4SLinus Torvalds case ERESTARTSYS: 737*1da177e4SLinus Torvalds if(!(ka->sa.sa_flags & SA_RESTART)) { 738*1da177e4SLinus Torvalds regs->regs[2] = EINTR; 739*1da177e4SLinus Torvalds break; 740*1da177e4SLinus Torvalds } 741*1da177e4SLinus Torvalds /* fallthrough */ 742*1da177e4SLinus Torvalds case ERESTARTNOINTR: /* Userland will reload $v0. */ 743*1da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 744*1da177e4SLinus Torvalds regs->cp0_epc -= 8; 745*1da177e4SLinus Torvalds } 746*1da177e4SLinus Torvalds 747*1da177e4SLinus Torvalds regs->regs[0] = 0; /* Don't deal with this again. */ 748*1da177e4SLinus Torvalds 749*1da177e4SLinus Torvalds if (ka->sa.sa_flags & SA_SIGINFO) 750*1da177e4SLinus Torvalds setup_rt_frame(ka, regs, sig, oldset, info); 751*1da177e4SLinus Torvalds else 752*1da177e4SLinus Torvalds setup_frame(ka, regs, sig, oldset); 753*1da177e4SLinus Torvalds 754*1da177e4SLinus Torvalds if (!(ka->sa.sa_flags & SA_NODEFER)) { 755*1da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 756*1da177e4SLinus Torvalds sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); 757*1da177e4SLinus Torvalds sigaddset(¤t->blocked,sig); 758*1da177e4SLinus Torvalds recalc_sigpending(); 759*1da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 760*1da177e4SLinus Torvalds } 761*1da177e4SLinus Torvalds } 762*1da177e4SLinus Torvalds 763*1da177e4SLinus Torvalds int do_signal32(sigset_t *oldset, struct pt_regs *regs) 764*1da177e4SLinus Torvalds { 765*1da177e4SLinus Torvalds struct k_sigaction ka; 766*1da177e4SLinus Torvalds siginfo_t info; 767*1da177e4SLinus Torvalds int signr; 768*1da177e4SLinus Torvalds 769*1da177e4SLinus Torvalds /* 770*1da177e4SLinus Torvalds * We want the common case to go fast, which is why we may in certain 771*1da177e4SLinus Torvalds * cases get here from kernel mode. Just return without doing anything 772*1da177e4SLinus Torvalds * if so. 773*1da177e4SLinus Torvalds */ 774*1da177e4SLinus Torvalds if (!user_mode(regs)) 775*1da177e4SLinus Torvalds return 1; 776*1da177e4SLinus Torvalds 777*1da177e4SLinus Torvalds if (try_to_freeze(0)) 778*1da177e4SLinus Torvalds goto no_signal; 779*1da177e4SLinus Torvalds 780*1da177e4SLinus Torvalds if (!oldset) 781*1da177e4SLinus Torvalds oldset = ¤t->blocked; 782*1da177e4SLinus Torvalds 783*1da177e4SLinus Torvalds signr = get_signal_to_deliver(&info, &ka, regs, NULL); 784*1da177e4SLinus Torvalds if (signr > 0) { 785*1da177e4SLinus Torvalds handle_signal(signr, &info, &ka, oldset, regs); 786*1da177e4SLinus Torvalds return 1; 787*1da177e4SLinus Torvalds } 788*1da177e4SLinus Torvalds 789*1da177e4SLinus Torvalds no_signal: 790*1da177e4SLinus Torvalds /* 791*1da177e4SLinus Torvalds * Who's code doesn't conform to the restartable syscall convention 792*1da177e4SLinus Torvalds * dies here!!! The li instruction, a single machine instruction, 793*1da177e4SLinus Torvalds * must directly be followed by the syscall instruction. 794*1da177e4SLinus Torvalds */ 795*1da177e4SLinus Torvalds if (regs->regs[0]) { 796*1da177e4SLinus Torvalds if (regs->regs[2] == ERESTARTNOHAND || 797*1da177e4SLinus Torvalds regs->regs[2] == ERESTARTSYS || 798*1da177e4SLinus Torvalds regs->regs[2] == ERESTARTNOINTR) { 799*1da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 800*1da177e4SLinus Torvalds regs->cp0_epc -= 8; 801*1da177e4SLinus Torvalds } 802*1da177e4SLinus Torvalds if (regs->regs[2] == ERESTART_RESTARTBLOCK) { 803*1da177e4SLinus Torvalds regs->regs[2] = __NR_O32_restart_syscall; 804*1da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 805*1da177e4SLinus Torvalds regs->cp0_epc -= 4; 806*1da177e4SLinus Torvalds } 807*1da177e4SLinus Torvalds } 808*1da177e4SLinus Torvalds return 0; 809*1da177e4SLinus Torvalds } 810*1da177e4SLinus Torvalds 811*1da177e4SLinus Torvalds asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act, 812*1da177e4SLinus Torvalds struct sigaction32 *oact, 813*1da177e4SLinus Torvalds unsigned int sigsetsize) 814*1da177e4SLinus Torvalds { 815*1da177e4SLinus Torvalds struct k_sigaction new_sa, old_sa; 816*1da177e4SLinus Torvalds int ret = -EINVAL; 817*1da177e4SLinus Torvalds 818*1da177e4SLinus Torvalds /* XXX: Don't preclude handling different sized sigset_t's. */ 819*1da177e4SLinus Torvalds if (sigsetsize != sizeof(sigset_t)) 820*1da177e4SLinus Torvalds goto out; 821*1da177e4SLinus Torvalds 822*1da177e4SLinus Torvalds if (act) { 823*1da177e4SLinus Torvalds int err = 0; 824*1da177e4SLinus Torvalds 825*1da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, act, sizeof(*act))) 826*1da177e4SLinus Torvalds return -EFAULT; 827*1da177e4SLinus Torvalds err |= __get_user((u32)(u64)new_sa.sa.sa_handler, 828*1da177e4SLinus Torvalds &act->sa_handler); 829*1da177e4SLinus Torvalds err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags); 830*1da177e4SLinus Torvalds err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); 831*1da177e4SLinus Torvalds if (err) 832*1da177e4SLinus Torvalds return -EFAULT; 833*1da177e4SLinus Torvalds } 834*1da177e4SLinus Torvalds 835*1da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); 836*1da177e4SLinus Torvalds 837*1da177e4SLinus Torvalds if (!ret && oact) { 838*1da177e4SLinus Torvalds int err = 0; 839*1da177e4SLinus Torvalds 840*1da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 841*1da177e4SLinus Torvalds return -EFAULT; 842*1da177e4SLinus Torvalds 843*1da177e4SLinus Torvalds err |= __put_user((u32)(u64)old_sa.sa.sa_handler, 844*1da177e4SLinus Torvalds &oact->sa_handler); 845*1da177e4SLinus Torvalds err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags); 846*1da177e4SLinus Torvalds err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask); 847*1da177e4SLinus Torvalds if (err) 848*1da177e4SLinus Torvalds return -EFAULT; 849*1da177e4SLinus Torvalds } 850*1da177e4SLinus Torvalds out: 851*1da177e4SLinus Torvalds return ret; 852*1da177e4SLinus Torvalds } 853*1da177e4SLinus Torvalds 854*1da177e4SLinus Torvalds asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set, 855*1da177e4SLinus Torvalds compat_sigset_t *oset, unsigned int sigsetsize) 856*1da177e4SLinus Torvalds { 857*1da177e4SLinus Torvalds sigset_t old_set, new_set; 858*1da177e4SLinus Torvalds int ret; 859*1da177e4SLinus Torvalds mm_segment_t old_fs = get_fs(); 860*1da177e4SLinus Torvalds 861*1da177e4SLinus Torvalds if (set && get_sigset(&new_set, set)) 862*1da177e4SLinus Torvalds return -EFAULT; 863*1da177e4SLinus Torvalds 864*1da177e4SLinus Torvalds set_fs (KERNEL_DS); 865*1da177e4SLinus Torvalds ret = sys_rt_sigprocmask(how, set ? &new_set : NULL, 866*1da177e4SLinus Torvalds oset ? &old_set : NULL, sigsetsize); 867*1da177e4SLinus Torvalds set_fs (old_fs); 868*1da177e4SLinus Torvalds 869*1da177e4SLinus Torvalds if (!ret && oset && put_sigset(&old_set, oset)) 870*1da177e4SLinus Torvalds return -EFAULT; 871*1da177e4SLinus Torvalds 872*1da177e4SLinus Torvalds return ret; 873*1da177e4SLinus Torvalds } 874*1da177e4SLinus Torvalds 875*1da177e4SLinus Torvalds asmlinkage int sys32_rt_sigpending(compat_sigset_t *uset, 876*1da177e4SLinus Torvalds unsigned int sigsetsize) 877*1da177e4SLinus Torvalds { 878*1da177e4SLinus Torvalds int ret; 879*1da177e4SLinus Torvalds sigset_t set; 880*1da177e4SLinus Torvalds mm_segment_t old_fs = get_fs(); 881*1da177e4SLinus Torvalds 882*1da177e4SLinus Torvalds set_fs (KERNEL_DS); 883*1da177e4SLinus Torvalds ret = sys_rt_sigpending(&set, sigsetsize); 884*1da177e4SLinus Torvalds set_fs (old_fs); 885*1da177e4SLinus Torvalds 886*1da177e4SLinus Torvalds if (!ret && put_sigset(&set, uset)) 887*1da177e4SLinus Torvalds return -EFAULT; 888*1da177e4SLinus Torvalds 889*1da177e4SLinus Torvalds return ret; 890*1da177e4SLinus Torvalds } 891*1da177e4SLinus Torvalds 892*1da177e4SLinus Torvalds asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t *uinfo) 893*1da177e4SLinus Torvalds { 894*1da177e4SLinus Torvalds siginfo_t info; 895*1da177e4SLinus Torvalds int ret; 896*1da177e4SLinus Torvalds mm_segment_t old_fs = get_fs(); 897*1da177e4SLinus Torvalds 898*1da177e4SLinus Torvalds if (copy_from_user (&info, uinfo, 3*sizeof(int)) || 899*1da177e4SLinus Torvalds copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) 900*1da177e4SLinus Torvalds return -EFAULT; 901*1da177e4SLinus Torvalds set_fs (KERNEL_DS); 902*1da177e4SLinus Torvalds ret = sys_rt_sigqueueinfo(pid, sig, &info); 903*1da177e4SLinus Torvalds set_fs (old_fs); 904*1da177e4SLinus Torvalds return ret; 905*1da177e4SLinus Torvalds } 906