11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 31da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 41da177e4SLinus Torvalds * for more details. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 7dda73d0bSMartin Michlmayr * Copyright (C) 1994 - 2000, 2006 Ralf Baechle 81da177e4SLinus Torvalds * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 91da177e4SLinus Torvalds */ 1002416dcfSRalf Baechle #include <linux/cache.h> 11431dc804SRalf Baechle #include <linux/compat.h> 121da177e4SLinus Torvalds #include <linux/sched.h> 131da177e4SLinus Torvalds #include <linux/mm.h> 141da177e4SLinus Torvalds #include <linux/smp.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/signal.h> 171da177e4SLinus Torvalds #include <linux/syscalls.h> 181da177e4SLinus Torvalds #include <linux/errno.h> 191da177e4SLinus Torvalds #include <linux/wait.h> 201da177e4SLinus Torvalds #include <linux/ptrace.h> 211da177e4SLinus Torvalds #include <linux/suspend.h> 221da177e4SLinus Torvalds #include <linux/compiler.h> 23faea6234SAtsushi Nemoto #include <linux/uaccess.h> 241da177e4SLinus Torvalds 25e50c0a8fSRalf Baechle #include <asm/abi.h> 261da177e4SLinus Torvalds #include <asm/asm.h> 27431dc804SRalf Baechle #include <asm/compat-signal.h> 281da177e4SLinus Torvalds #include <linux/bitops.h> 291da177e4SLinus Torvalds #include <asm/cacheflush.h> 301da177e4SLinus Torvalds #include <asm/sim.h> 311da177e4SLinus Torvalds #include <asm/ucontext.h> 321da177e4SLinus Torvalds #include <asm/system.h> 331da177e4SLinus Torvalds #include <asm/fpu.h> 3402416dcfSRalf Baechle #include <asm/war.h> 351da177e4SLinus Torvalds 3636a1f2c2SFranck Bui-Huu #include "signal-common.h" 3736a1f2c2SFranck Bui-Huu 381da177e4SLinus Torvalds /* 391da177e4SLinus Torvalds * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 401da177e4SLinus Torvalds */ 411da177e4SLinus Torvalds #define __NR_O32_sigreturn 4119 421da177e4SLinus Torvalds #define __NR_O32_rt_sigreturn 4193 431da177e4SLinus Torvalds #define __NR_O32_restart_syscall 4253 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds /* 32-bit compatibility types */ 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds typedef unsigned int __sighandler32_t; 481da177e4SLinus Torvalds typedef void (*vfptr_t)(void); 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds struct sigaction32 { 511da177e4SLinus Torvalds unsigned int sa_flags; 521da177e4SLinus Torvalds __sighandler32_t sa_handler; 531da177e4SLinus Torvalds compat_sigset_t sa_mask; 541da177e4SLinus Torvalds }; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* IRIX compatible stack_t */ 571da177e4SLinus Torvalds typedef struct sigaltstack32 { 581da177e4SLinus Torvalds s32 ss_sp; 591da177e4SLinus Torvalds compat_size_t ss_size; 601da177e4SLinus Torvalds int ss_flags; 611da177e4SLinus Torvalds } stack32_t; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds struct ucontext32 { 641da177e4SLinus Torvalds u32 uc_flags; 651da177e4SLinus Torvalds s32 uc_link; 661da177e4SLinus Torvalds stack32_t uc_stack; 671da177e4SLinus Torvalds struct sigcontext32 uc_mcontext; 6801ee6037SRalf Baechle compat_sigset_t uc_sigmask; /* mask last for extensibility */ 691da177e4SLinus Torvalds }; 701da177e4SLinus Torvalds 71dd02f06aSRalf Baechle /* 72dd02f06aSRalf Baechle * Horribly complicated - with the bloody RM9000 workarounds enabled 73dd02f06aSRalf Baechle * the signal trampolines is moving to the end of the structure so we can 74dd02f06aSRalf Baechle * increase the alignment without breaking software compatibility. 75dd02f06aSRalf Baechle */ 76c0b9bae9SFranck Bui-Huu #if ICACHE_REFILLS_WORKAROUND_WAR == 0 77c0b9bae9SFranck Bui-Huu 78dd02f06aSRalf Baechle struct sigframe32 { 79dd02f06aSRalf Baechle u32 sf_ass[4]; /* argument save space for o32 */ 80dd02f06aSRalf Baechle u32 sf_code[2]; /* signal trampoline */ 81dd02f06aSRalf Baechle struct sigcontext32 sf_sc; 82755f21bbSAtsushi Nemoto compat_sigset_t sf_mask; 83dd02f06aSRalf Baechle }; 84dd02f06aSRalf Baechle 85c0b9bae9SFranck Bui-Huu struct rt_sigframe32 { 86c0b9bae9SFranck Bui-Huu u32 rs_ass[4]; /* argument save space for o32 */ 87c0b9bae9SFranck Bui-Huu u32 rs_code[2]; /* signal trampoline */ 88c0b9bae9SFranck Bui-Huu compat_siginfo_t rs_info; 89c0b9bae9SFranck Bui-Huu struct ucontext32 rs_uc; 90c0b9bae9SFranck Bui-Huu }; 91c0b9bae9SFranck Bui-Huu 92c0b9bae9SFranck Bui-Huu #else /* ICACHE_REFILLS_WORKAROUND_WAR */ 93c0b9bae9SFranck Bui-Huu 94dd02f06aSRalf Baechle struct sigframe32 { 95dd02f06aSRalf Baechle u32 sf_ass[4]; /* argument save space for o32 */ 96dd02f06aSRalf Baechle u32 sf_pad[2]; 97dd02f06aSRalf Baechle struct sigcontext32 sf_sc; /* hw context */ 98755f21bbSAtsushi Nemoto compat_sigset_t sf_mask; 99dd02f06aSRalf Baechle u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ 100dd02f06aSRalf Baechle }; 101dd02f06aSRalf Baechle 102c0b9bae9SFranck Bui-Huu struct rt_sigframe32 { 103c0b9bae9SFranck Bui-Huu u32 rs_ass[4]; /* argument save space for o32 */ 104c0b9bae9SFranck Bui-Huu u32 rs_pad[2]; 105c0b9bae9SFranck Bui-Huu compat_siginfo_t rs_info; 106c0b9bae9SFranck Bui-Huu struct ucontext32 rs_uc; 107c0b9bae9SFranck Bui-Huu u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ 108c0b9bae9SFranck Bui-Huu }; 109c0b9bae9SFranck Bui-Huu 110c0b9bae9SFranck Bui-Huu #endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ 111c0b9bae9SFranck Bui-Huu 1129432a9baSFranck Bui-Huu /* 1139432a9baSFranck Bui-Huu * sigcontext handlers 1149432a9baSFranck Bui-Huu */ 115faea6234SAtsushi Nemoto static int protected_save_fp_context32(struct sigcontext32 __user *sc) 116faea6234SAtsushi Nemoto { 117faea6234SAtsushi Nemoto int err; 118faea6234SAtsushi Nemoto while (1) { 119faea6234SAtsushi Nemoto lock_fpu_owner(); 120faea6234SAtsushi Nemoto own_fpu_inatomic(1); 121faea6234SAtsushi Nemoto err = save_fp_context32(sc); /* this might fail */ 122faea6234SAtsushi Nemoto unlock_fpu_owner(); 123faea6234SAtsushi Nemoto if (likely(!err)) 124faea6234SAtsushi Nemoto break; 125faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 126faea6234SAtsushi Nemoto err = __put_user(0, &sc->sc_fpregs[0]) | 127faea6234SAtsushi Nemoto __put_user(0, &sc->sc_fpregs[31]) | 128faea6234SAtsushi Nemoto __put_user(0, &sc->sc_fpc_csr); 129faea6234SAtsushi Nemoto if (err) 130faea6234SAtsushi Nemoto break; /* really bad sigcontext */ 131faea6234SAtsushi Nemoto } 132faea6234SAtsushi Nemoto return err; 133faea6234SAtsushi Nemoto } 134faea6234SAtsushi Nemoto 135faea6234SAtsushi Nemoto static int protected_restore_fp_context32(struct sigcontext32 __user *sc) 136faea6234SAtsushi Nemoto { 137faea6234SAtsushi Nemoto int err, tmp; 138faea6234SAtsushi Nemoto while (1) { 139faea6234SAtsushi Nemoto lock_fpu_owner(); 140faea6234SAtsushi Nemoto own_fpu_inatomic(0); 141faea6234SAtsushi Nemoto err = restore_fp_context32(sc); /* this might fail */ 142faea6234SAtsushi Nemoto unlock_fpu_owner(); 143faea6234SAtsushi Nemoto if (likely(!err)) 144faea6234SAtsushi Nemoto break; 145faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 146faea6234SAtsushi Nemoto err = __get_user(tmp, &sc->sc_fpregs[0]) | 147faea6234SAtsushi Nemoto __get_user(tmp, &sc->sc_fpregs[31]) | 148faea6234SAtsushi Nemoto __get_user(tmp, &sc->sc_fpc_csr); 149faea6234SAtsushi Nemoto if (err) 150faea6234SAtsushi Nemoto break; /* really bad sigcontext */ 151faea6234SAtsushi Nemoto } 152faea6234SAtsushi Nemoto return err; 153faea6234SAtsushi Nemoto } 154faea6234SAtsushi Nemoto 1559432a9baSFranck Bui-Huu static int setup_sigcontext32(struct pt_regs *regs, 1569432a9baSFranck Bui-Huu struct sigcontext32 __user *sc) 1579432a9baSFranck Bui-Huu { 1589432a9baSFranck Bui-Huu int err = 0; 1599432a9baSFranck Bui-Huu int i; 16053dc8028SAtsushi Nemoto u32 used_math; 1619432a9baSFranck Bui-Huu 1629432a9baSFranck Bui-Huu err |= __put_user(regs->cp0_epc, &sc->sc_pc); 1639432a9baSFranck Bui-Huu 1649432a9baSFranck Bui-Huu err |= __put_user(0, &sc->sc_regs[0]); 1659432a9baSFranck Bui-Huu for (i = 1; i < 32; i++) 1669432a9baSFranck Bui-Huu err |= __put_user(regs->regs[i], &sc->sc_regs[i]); 1679432a9baSFranck Bui-Huu 1689432a9baSFranck Bui-Huu err |= __put_user(regs->hi, &sc->sc_mdhi); 1699432a9baSFranck Bui-Huu err |= __put_user(regs->lo, &sc->sc_mdlo); 1709432a9baSFranck Bui-Huu if (cpu_has_dsp) { 1719432a9baSFranck Bui-Huu err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 1729432a9baSFranck Bui-Huu err |= __put_user(mfhi1(), &sc->sc_hi1); 1739432a9baSFranck Bui-Huu err |= __put_user(mflo1(), &sc->sc_lo1); 1749432a9baSFranck Bui-Huu err |= __put_user(mfhi2(), &sc->sc_hi2); 1759432a9baSFranck Bui-Huu err |= __put_user(mflo2(), &sc->sc_lo2); 1769432a9baSFranck Bui-Huu err |= __put_user(mfhi3(), &sc->sc_hi3); 1779432a9baSFranck Bui-Huu err |= __put_user(mflo3(), &sc->sc_lo3); 1789432a9baSFranck Bui-Huu } 1799432a9baSFranck Bui-Huu 18053dc8028SAtsushi Nemoto used_math = !!used_math(); 18153dc8028SAtsushi Nemoto err |= __put_user(used_math, &sc->sc_used_math); 1829432a9baSFranck Bui-Huu 18353dc8028SAtsushi Nemoto if (used_math) { 1849432a9baSFranck Bui-Huu /* 1859432a9baSFranck Bui-Huu * Save FPU state to signal context. Signal handler 1869432a9baSFranck Bui-Huu * will "inherit" current FPU state. 1879432a9baSFranck Bui-Huu */ 188faea6234SAtsushi Nemoto err |= protected_save_fp_context32(sc); 1899432a9baSFranck Bui-Huu } 1909432a9baSFranck Bui-Huu return err; 1919432a9baSFranck Bui-Huu } 1929432a9baSFranck Bui-Huu 193c6a2f467SAtsushi Nemoto static int 194c6a2f467SAtsushi Nemoto check_and_restore_fp_context32(struct sigcontext32 __user *sc) 195c6a2f467SAtsushi Nemoto { 196c6a2f467SAtsushi Nemoto int err, sig; 197c6a2f467SAtsushi Nemoto 198c6a2f467SAtsushi Nemoto err = sig = fpcsr_pending(&sc->sc_fpc_csr); 199c6a2f467SAtsushi Nemoto if (err > 0) 200c6a2f467SAtsushi Nemoto err = 0; 201faea6234SAtsushi Nemoto err |= protected_restore_fp_context32(sc); 202c6a2f467SAtsushi Nemoto return err ?: sig; 203c6a2f467SAtsushi Nemoto } 204c6a2f467SAtsushi Nemoto 2059432a9baSFranck Bui-Huu static int restore_sigcontext32(struct pt_regs *regs, 2069432a9baSFranck Bui-Huu struct sigcontext32 __user *sc) 2079432a9baSFranck Bui-Huu { 2089432a9baSFranck Bui-Huu u32 used_math; 2099432a9baSFranck Bui-Huu int err = 0; 2109432a9baSFranck Bui-Huu s32 treg; 2119432a9baSFranck Bui-Huu int i; 2129432a9baSFranck Bui-Huu 2139432a9baSFranck Bui-Huu /* Always make any pending restarted system calls return -EINTR */ 2149432a9baSFranck Bui-Huu current_thread_info()->restart_block.fn = do_no_restart_syscall; 2159432a9baSFranck Bui-Huu 2169432a9baSFranck Bui-Huu err |= __get_user(regs->cp0_epc, &sc->sc_pc); 2179432a9baSFranck Bui-Huu err |= __get_user(regs->hi, &sc->sc_mdhi); 2189432a9baSFranck Bui-Huu err |= __get_user(regs->lo, &sc->sc_mdlo); 2199432a9baSFranck Bui-Huu if (cpu_has_dsp) { 2209432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); 2219432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); 2229432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); 2239432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); 2249432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); 2259432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); 2269432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); 2279432a9baSFranck Bui-Huu } 2289432a9baSFranck Bui-Huu 2299432a9baSFranck Bui-Huu for (i = 1; i < 32; i++) 2309432a9baSFranck Bui-Huu err |= __get_user(regs->regs[i], &sc->sc_regs[i]); 2319432a9baSFranck Bui-Huu 2329432a9baSFranck Bui-Huu err |= __get_user(used_math, &sc->sc_used_math); 2339432a9baSFranck Bui-Huu conditional_used_math(used_math); 2349432a9baSFranck Bui-Huu 23553dc8028SAtsushi Nemoto if (used_math) { 2369432a9baSFranck Bui-Huu /* restore fpu context if we have used it before */ 237c6a2f467SAtsushi Nemoto if (!err) 238c6a2f467SAtsushi Nemoto err = check_and_restore_fp_context32(sc); 2399432a9baSFranck Bui-Huu } else { 2409432a9baSFranck Bui-Huu /* signal handler may have used FPU. Give it up. */ 24153dc8028SAtsushi Nemoto lose_fpu(0); 2429432a9baSFranck Bui-Huu } 2439432a9baSFranck Bui-Huu 2449432a9baSFranck Bui-Huu return err; 2459432a9baSFranck Bui-Huu } 2469432a9baSFranck Bui-Huu 2479432a9baSFranck Bui-Huu /* 2489432a9baSFranck Bui-Huu * 2499432a9baSFranck Bui-Huu */ 2501da177e4SLinus Torvalds extern void __put_sigset_unknown_nsig(void); 2511da177e4SLinus Torvalds extern void __get_sigset_unknown_nsig(void); 2521da177e4SLinus Torvalds 2539bbf28a3SAtsushi Nemoto static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) 2541da177e4SLinus Torvalds { 2551da177e4SLinus Torvalds int err = 0; 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) 2581da177e4SLinus Torvalds return -EFAULT; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds switch (_NSIG_WORDS) { 2611da177e4SLinus Torvalds default: 2621da177e4SLinus Torvalds __put_sigset_unknown_nsig(); 2631da177e4SLinus Torvalds case 2: 2641da177e4SLinus Torvalds err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]); 2651da177e4SLinus Torvalds err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); 2661da177e4SLinus Torvalds case 1: 2671da177e4SLinus Torvalds err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]); 2681da177e4SLinus Torvalds err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds return err; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 2749c6031ccSAtsushi Nemoto static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) 2751da177e4SLinus Torvalds { 2761da177e4SLinus Torvalds int err = 0; 2771da177e4SLinus Torvalds unsigned long sig[4]; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) 2801da177e4SLinus Torvalds return -EFAULT; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds switch (_NSIG_WORDS) { 2831da177e4SLinus Torvalds default: 2841da177e4SLinus Torvalds __get_sigset_unknown_nsig(); 2851da177e4SLinus Torvalds case 2: 2861da177e4SLinus Torvalds err |= __get_user(sig[3], &ubuf->sig[3]); 2871da177e4SLinus Torvalds err |= __get_user(sig[2], &ubuf->sig[2]); 2881da177e4SLinus Torvalds kbuf->sig[1] = sig[2] | (sig[3] << 32); 2891da177e4SLinus Torvalds case 1: 2901da177e4SLinus Torvalds err |= __get_user(sig[1], &ubuf->sig[1]); 2911da177e4SLinus Torvalds err |= __get_user(sig[0], &ubuf->sig[0]); 2921da177e4SLinus Torvalds kbuf->sig[0] = sig[0] | (sig[1] << 32); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds return err; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds /* 2991da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 3001da177e4SLinus Torvalds */ 3011da177e4SLinus Torvalds 302f90080a0SFranck Bui-Huu asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) 3031da177e4SLinus Torvalds { 3049c6031ccSAtsushi Nemoto compat_sigset_t __user *uset; 30568fa383fSMartin Michlmayr sigset_t newset; 3061da177e4SLinus Torvalds 3079c6031ccSAtsushi Nemoto uset = (compat_sigset_t __user *) regs.regs[4]; 3081da177e4SLinus Torvalds if (get_sigset(&newset, uset)) 3091da177e4SLinus Torvalds return -EFAULT; 3101da177e4SLinus Torvalds sigdelsetmask(&newset, ~_BLOCKABLE); 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 31368fa383fSMartin Michlmayr current->saved_sigmask = current->blocked; 3141da177e4SLinus Torvalds current->blocked = newset; 3151da177e4SLinus Torvalds recalc_sigpending(); 3161da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 3191da177e4SLinus Torvalds schedule(); 32068fa383fSMartin Michlmayr set_thread_flag(TIF_RESTORE_SIGMASK); 32168fa383fSMartin Michlmayr return -ERESTARTNOHAND; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 324f90080a0SFranck Bui-Huu asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) 3251da177e4SLinus Torvalds { 3269c6031ccSAtsushi Nemoto compat_sigset_t __user *uset; 32768fa383fSMartin Michlmayr sigset_t newset; 3281da177e4SLinus Torvalds size_t sigsetsize; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds /* XXX Don't preclude handling different sized sigset_t's. */ 3311da177e4SLinus Torvalds sigsetsize = regs.regs[5]; 3321da177e4SLinus Torvalds if (sigsetsize != sizeof(compat_sigset_t)) 3331da177e4SLinus Torvalds return -EINVAL; 3341da177e4SLinus Torvalds 3359c6031ccSAtsushi Nemoto uset = (compat_sigset_t __user *) regs.regs[4]; 3361da177e4SLinus Torvalds if (get_sigset(&newset, uset)) 3371da177e4SLinus Torvalds return -EFAULT; 3381da177e4SLinus Torvalds sigdelsetmask(&newset, ~_BLOCKABLE); 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 34168fa383fSMartin Michlmayr current->saved_sigmask = current->blocked; 3421da177e4SLinus Torvalds current->blocked = newset; 3431da177e4SLinus Torvalds recalc_sigpending(); 3441da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 3471da177e4SLinus Torvalds schedule(); 34868fa383fSMartin Michlmayr set_thread_flag(TIF_RESTORE_SIGMASK); 34968fa383fSMartin Michlmayr return -ERESTARTNOHAND; 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds 3529c6031ccSAtsushi Nemoto asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act, 3539c6031ccSAtsushi Nemoto struct sigaction32 __user *oact) 3541da177e4SLinus Torvalds { 3551da177e4SLinus Torvalds struct k_sigaction new_ka, old_ka; 3561da177e4SLinus Torvalds int ret; 3571da177e4SLinus Torvalds int err = 0; 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds if (act) { 3601da177e4SLinus Torvalds old_sigset_t mask; 36177c728c2SRalf Baechle s32 handler; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, act, sizeof(*act))) 3641da177e4SLinus Torvalds return -EFAULT; 36577c728c2SRalf Baechle err |= __get_user(handler, &act->sa_handler); 3669bbf28a3SAtsushi Nemoto new_ka.sa.sa_handler = (void __user *)(s64)handler; 3671da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 3681da177e4SLinus Torvalds err |= __get_user(mask, &act->sa_mask.sig[0]); 3691da177e4SLinus Torvalds if (err) 3701da177e4SLinus Torvalds return -EFAULT; 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds siginitset(&new_ka.sa.sa_mask, mask); 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds if (!ret && oact) { 3781da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 3791da177e4SLinus Torvalds return -EFAULT; 3801da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 3811da177e4SLinus Torvalds err |= __put_user((u32)(u64)old_ka.sa.sa_handler, 3821da177e4SLinus Torvalds &oact->sa_handler); 3831da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 3841da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[1]); 3851da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[2]); 3861da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[3]); 3871da177e4SLinus Torvalds if (err) 3881da177e4SLinus Torvalds return -EFAULT; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds return ret; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) 3951da177e4SLinus Torvalds { 3969bbf28a3SAtsushi Nemoto const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4]; 3979bbf28a3SAtsushi Nemoto stack32_t __user *uoss = (stack32_t __user *) regs.regs[5]; 3981da177e4SLinus Torvalds unsigned long usp = regs.regs[29]; 3991da177e4SLinus Torvalds stack_t kss, koss; 4001da177e4SLinus Torvalds int ret, err = 0; 4011da177e4SLinus Torvalds mm_segment_t old_fs = get_fs(); 4021da177e4SLinus Torvalds s32 sp; 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds if (uss) { 4051da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) 4061da177e4SLinus Torvalds return -EFAULT; 4071da177e4SLinus Torvalds err |= __get_user(sp, &uss->ss_sp); 4089c6031ccSAtsushi Nemoto kss.ss_sp = (void __user *) (long) sp; 4091da177e4SLinus Torvalds err |= __get_user(kss.ss_size, &uss->ss_size); 4101da177e4SLinus Torvalds err |= __get_user(kss.ss_flags, &uss->ss_flags); 4111da177e4SLinus Torvalds if (err) 4121da177e4SLinus Torvalds return -EFAULT; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds set_fs(KERNEL_DS); 4169bbf28a3SAtsushi Nemoto ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL, 4179bbf28a3SAtsushi Nemoto uoss ? (stack_t __user *)&koss : NULL, usp); 4181da177e4SLinus Torvalds set_fs(old_fs); 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds if (!ret && uoss) { 4211da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) 4221da177e4SLinus Torvalds return -EFAULT; 4239c6031ccSAtsushi Nemoto sp = (int) (unsigned long) koss.ss_sp; 4241da177e4SLinus Torvalds err |= __put_user(sp, &uoss->ss_sp); 4251da177e4SLinus Torvalds err |= __put_user(koss.ss_size, &uoss->ss_size); 4261da177e4SLinus Torvalds err |= __put_user(koss.ss_flags, &uoss->ss_flags); 4271da177e4SLinus Torvalds if (err) 4281da177e4SLinus Torvalds return -EFAULT; 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds return ret; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 4339bbf28a3SAtsushi Nemoto int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) 4341da177e4SLinus Torvalds { 4351da177e4SLinus Torvalds int err; 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) 4381da177e4SLinus Torvalds return -EFAULT; 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds /* If you change siginfo_t structure, please be sure 4411da177e4SLinus Torvalds this code is fixed accordingly. 4421da177e4SLinus Torvalds It should never copy any pad contained in the structure 4431da177e4SLinus Torvalds to avoid security leaks, but must copy the generic 4441da177e4SLinus Torvalds 3 ints plus the relevant union member. 4451da177e4SLinus Torvalds This routine must convert siginfo from 64bit to 32bit as well 4461da177e4SLinus Torvalds at the same time. */ 4471da177e4SLinus Torvalds err = __put_user(from->si_signo, &to->si_signo); 4481da177e4SLinus Torvalds err |= __put_user(from->si_errno, &to->si_errno); 4491da177e4SLinus Torvalds err |= __put_user((short)from->si_code, &to->si_code); 4501da177e4SLinus Torvalds if (from->si_code < 0) 4511da177e4SLinus Torvalds err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); 4521da177e4SLinus Torvalds else { 4531da177e4SLinus Torvalds switch (from->si_code >> 16) { 454a982099cSRalf Baechle case __SI_TIMER >> 16: 455a982099cSRalf Baechle err |= __put_user(from->si_tid, &to->si_tid); 456a982099cSRalf Baechle err |= __put_user(from->si_overrun, &to->si_overrun); 457a982099cSRalf Baechle err |= __put_user(from->si_int, &to->si_int); 458a982099cSRalf Baechle break; 4591da177e4SLinus Torvalds case __SI_CHLD >> 16: 4601da177e4SLinus Torvalds err |= __put_user(from->si_utime, &to->si_utime); 4611da177e4SLinus Torvalds err |= __put_user(from->si_stime, &to->si_stime); 4621da177e4SLinus Torvalds err |= __put_user(from->si_status, &to->si_status); 4631da177e4SLinus Torvalds default: 4641da177e4SLinus Torvalds err |= __put_user(from->si_pid, &to->si_pid); 4651da177e4SLinus Torvalds err |= __put_user(from->si_uid, &to->si_uid); 4661da177e4SLinus Torvalds break; 4671da177e4SLinus Torvalds case __SI_FAULT >> 16: 4685665a0acSAtsushi Nemoto err |= __put_user((unsigned long)from->si_addr, &to->si_addr); 4691da177e4SLinus Torvalds break; 4701da177e4SLinus Torvalds case __SI_POLL >> 16: 4711da177e4SLinus Torvalds err |= __put_user(from->si_band, &to->si_band); 4721da177e4SLinus Torvalds err |= __put_user(from->si_fd, &to->si_fd); 4731da177e4SLinus Torvalds break; 4741da177e4SLinus Torvalds case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ 4751da177e4SLinus Torvalds case __SI_MESGQ >> 16: 4761da177e4SLinus Torvalds err |= __put_user(from->si_pid, &to->si_pid); 4771da177e4SLinus Torvalds err |= __put_user(from->si_uid, &to->si_uid); 4781da177e4SLinus Torvalds err |= __put_user(from->si_int, &to->si_int); 4791da177e4SLinus Torvalds break; 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds } 4821da177e4SLinus Torvalds return err; 4831da177e4SLinus Torvalds } 4841da177e4SLinus Torvalds 485*5d9a76cdSThomas Bogendoerfer int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) 486*5d9a76cdSThomas Bogendoerfer { 487*5d9a76cdSThomas Bogendoerfer memset(to, 0, sizeof *to); 488*5d9a76cdSThomas Bogendoerfer 489*5d9a76cdSThomas Bogendoerfer if (copy_from_user(to, from, 3*sizeof(int)) || 490*5d9a76cdSThomas Bogendoerfer copy_from_user(to->_sifields._pad, 491*5d9a76cdSThomas Bogendoerfer from->_sifields._pad, SI_PAD_SIZE32)) 492*5d9a76cdSThomas Bogendoerfer return -EFAULT; 493*5d9a76cdSThomas Bogendoerfer 494*5d9a76cdSThomas Bogendoerfer return 0; 495*5d9a76cdSThomas Bogendoerfer } 496*5d9a76cdSThomas Bogendoerfer 497f90080a0SFranck Bui-Huu asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) 4981da177e4SLinus Torvalds { 499dd02f06aSRalf Baechle struct sigframe32 __user *frame; 5001da177e4SLinus Torvalds sigset_t blocked; 501c6a2f467SAtsushi Nemoto int sig; 5021da177e4SLinus Torvalds 503dd02f06aSRalf Baechle frame = (struct sigframe32 __user *) regs.regs[29]; 5041da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 5051da177e4SLinus Torvalds goto badframe; 506431dc804SRalf Baechle if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) 5071da177e4SLinus Torvalds goto badframe; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds sigdelsetmask(&blocked, ~_BLOCKABLE); 5101da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 5111da177e4SLinus Torvalds current->blocked = blocked; 5121da177e4SLinus Torvalds recalc_sigpending(); 5131da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 5141da177e4SLinus Torvalds 515c6a2f467SAtsushi Nemoto sig = restore_sigcontext32(®s, &frame->sf_sc); 516c6a2f467SAtsushi Nemoto if (sig < 0) 5171da177e4SLinus Torvalds goto badframe; 518c6a2f467SAtsushi Nemoto else if (sig) 519c6a2f467SAtsushi Nemoto force_sig(sig, current); 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds /* 5221da177e4SLinus Torvalds * Don't let your children do this ... 5231da177e4SLinus Torvalds */ 5241da177e4SLinus Torvalds __asm__ __volatile__( 5251da177e4SLinus Torvalds "move\t$29, %0\n\t" 5261da177e4SLinus Torvalds "j\tsyscall_exit" 5271da177e4SLinus Torvalds :/* no outputs */ 5281da177e4SLinus Torvalds :"r" (®s)); 5291da177e4SLinus Torvalds /* Unreached */ 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds badframe: 5321da177e4SLinus Torvalds force_sig(SIGSEGV, current); 5331da177e4SLinus Torvalds } 5341da177e4SLinus Torvalds 535f90080a0SFranck Bui-Huu asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) 5361da177e4SLinus Torvalds { 5379bbf28a3SAtsushi Nemoto struct rt_sigframe32 __user *frame; 5381fcf1cc7SRalf Baechle mm_segment_t old_fs; 5391da177e4SLinus Torvalds sigset_t set; 5401da177e4SLinus Torvalds stack_t st; 5411da177e4SLinus Torvalds s32 sp; 542c6a2f467SAtsushi Nemoto int sig; 5431da177e4SLinus Torvalds 5449bbf28a3SAtsushi Nemoto frame = (struct rt_sigframe32 __user *) regs.regs[29]; 5451da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 5461da177e4SLinus Torvalds goto badframe; 547431dc804SRalf Baechle if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) 5481da177e4SLinus Torvalds goto badframe; 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds sigdelsetmask(&set, ~_BLOCKABLE); 5511da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 5521da177e4SLinus Torvalds current->blocked = set; 5531da177e4SLinus Torvalds recalc_sigpending(); 5541da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 5551da177e4SLinus Torvalds 556c6a2f467SAtsushi Nemoto sig = restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext); 557c6a2f467SAtsushi Nemoto if (sig < 0) 5581da177e4SLinus Torvalds goto badframe; 559c6a2f467SAtsushi Nemoto else if (sig) 560c6a2f467SAtsushi Nemoto force_sig(sig, current); 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds /* The ucontext contains a stack32_t, so we must convert! */ 5631da177e4SLinus Torvalds if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) 5641da177e4SLinus Torvalds goto badframe; 5659c6031ccSAtsushi Nemoto st.ss_sp = (void __user *)(long) sp; 5661da177e4SLinus Torvalds if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size)) 5671da177e4SLinus Torvalds goto badframe; 5681da177e4SLinus Torvalds if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags)) 5691da177e4SLinus Torvalds goto badframe; 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds /* It is more difficult to avoid calling this function than to 5721da177e4SLinus Torvalds call it and ignore errors. */ 5731fcf1cc7SRalf Baechle old_fs = get_fs(); 5741fcf1cc7SRalf Baechle set_fs(KERNEL_DS); 5759bbf28a3SAtsushi Nemoto do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]); 5761fcf1cc7SRalf Baechle set_fs(old_fs); 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds /* 5791da177e4SLinus Torvalds * Don't let your children do this ... 5801da177e4SLinus Torvalds */ 5811da177e4SLinus Torvalds __asm__ __volatile__( 5821da177e4SLinus Torvalds "move\t$29, %0\n\t" 5831da177e4SLinus Torvalds "j\tsyscall_exit" 5841da177e4SLinus Torvalds :/* no outputs */ 5851da177e4SLinus Torvalds :"r" (®s)); 5861da177e4SLinus Torvalds /* Unreached */ 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds badframe: 5891da177e4SLinus Torvalds force_sig(SIGSEGV, current); 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds 592151fd6acSRalf Baechle static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 5931da177e4SLinus Torvalds int signr, sigset_t *set) 5941da177e4SLinus Torvalds { 595dd02f06aSRalf Baechle struct sigframe32 __user *frame; 5961da177e4SLinus Torvalds int err = 0; 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 5991da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 6001da177e4SLinus Torvalds goto give_sigsegv; 6011da177e4SLinus Torvalds 60236a1f2c2SFranck Bui-Huu err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn); 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds err |= setup_sigcontext32(regs, &frame->sf_sc); 605431dc804SRalf Baechle err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); 606431dc804SRalf Baechle 6071da177e4SLinus Torvalds if (err) 6081da177e4SLinus Torvalds goto give_sigsegv; 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds /* 6111da177e4SLinus Torvalds * Arguments to signal handler: 6121da177e4SLinus Torvalds * 6131da177e4SLinus Torvalds * a0 = signal number 6141da177e4SLinus Torvalds * a1 = 0 (should be cause) 6151da177e4SLinus Torvalds * a2 = pointer to struct sigcontext 6161da177e4SLinus Torvalds * 6171da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to the 6181da177e4SLinus Torvalds * struct sigframe. 6191da177e4SLinus Torvalds */ 6201da177e4SLinus Torvalds regs->regs[ 4] = signr; 6211da177e4SLinus Torvalds regs->regs[ 5] = 0; 6221da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->sf_sc; 6231da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 6241da177e4SLinus Torvalds regs->regs[31] = (unsigned long) frame->sf_code; 6251da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 6261da177e4SLinus Torvalds 627722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 6281da177e4SLinus Torvalds current->comm, current->pid, 629722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 630722bb63dSFranck Bui-Huu 6317b3e2fc8SRalf Baechle return 0; 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds give_sigsegv: 6341da177e4SLinus Torvalds force_sigsegv(signr, current); 6357b3e2fc8SRalf Baechle return -EFAULT; 6361da177e4SLinus Torvalds } 6371da177e4SLinus Torvalds 638151fd6acSRalf Baechle static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 63916cd3951SAtsushi Nemoto int signr, sigset_t *set, siginfo_t *info) 6401da177e4SLinus Torvalds { 6419bbf28a3SAtsushi Nemoto struct rt_sigframe32 __user *frame; 6421da177e4SLinus Torvalds int err = 0; 6431da177e4SLinus Torvalds s32 sp; 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 6461da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 6471da177e4SLinus Torvalds goto give_sigsegv; 6481da177e4SLinus Torvalds 64936a1f2c2SFranck Bui-Huu err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn); 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ 6521da177e4SLinus Torvalds err |= copy_siginfo_to_user32(&frame->rs_info, info); 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds /* Create the ucontext. */ 6551da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 6561da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_link); 6571da177e4SLinus Torvalds sp = (int) (long) current->sas_ss_sp; 6581da177e4SLinus Torvalds err |= __put_user(sp, 6591da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_sp); 6601da177e4SLinus Torvalds err |= __put_user(sas_ss_flags(regs->regs[29]), 6611da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_flags); 6621da177e4SLinus Torvalds err |= __put_user(current->sas_ss_size, 6631da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_size); 6641da177e4SLinus Torvalds err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); 665431dc804SRalf Baechle err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds if (err) 6681da177e4SLinus Torvalds goto give_sigsegv; 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds /* 6711da177e4SLinus Torvalds * Arguments to signal handler: 6721da177e4SLinus Torvalds * 6731da177e4SLinus Torvalds * a0 = signal number 6741da177e4SLinus Torvalds * a1 = 0 (should be cause) 6751da177e4SLinus Torvalds * a2 = pointer to ucontext 6761da177e4SLinus Torvalds * 6771da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 6781da177e4SLinus Torvalds * the struct rt_sigframe32. 6791da177e4SLinus Torvalds */ 6801da177e4SLinus Torvalds regs->regs[ 4] = signr; 6811da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 6821da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 6831da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 6841da177e4SLinus Torvalds regs->regs[31] = (unsigned long) frame->rs_code; 6851da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 6861da177e4SLinus Torvalds 687722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 6881da177e4SLinus Torvalds current->comm, current->pid, 689722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 690722bb63dSFranck Bui-Huu 6917b3e2fc8SRalf Baechle return 0; 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds give_sigsegv: 6941da177e4SLinus Torvalds force_sigsegv(signr, current); 6957b3e2fc8SRalf Baechle return -EFAULT; 6961da177e4SLinus Torvalds } 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds /* 699151fd6acSRalf Baechle * o32 compatibility on 64-bit kernels, without DSP ASE 7001da177e4SLinus Torvalds */ 701151fd6acSRalf Baechle struct mips_abi mips_abi_32 = { 702151fd6acSRalf Baechle .setup_frame = setup_frame_32, 703151fd6acSRalf Baechle .setup_rt_frame = setup_rt_frame_32, 704151fd6acSRalf Baechle .restart = __NR_O32_restart_syscall 705151fd6acSRalf Baechle }; 7061da177e4SLinus Torvalds 7079c6031ccSAtsushi Nemoto asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, 7089bbf28a3SAtsushi Nemoto struct sigaction32 __user *oact, 7091da177e4SLinus Torvalds unsigned int sigsetsize) 7101da177e4SLinus Torvalds { 7111da177e4SLinus Torvalds struct k_sigaction new_sa, old_sa; 7121da177e4SLinus Torvalds int ret = -EINVAL; 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds /* XXX: Don't preclude handling different sized sigset_t's. */ 7151da177e4SLinus Torvalds if (sigsetsize != sizeof(sigset_t)) 7161da177e4SLinus Torvalds goto out; 7171da177e4SLinus Torvalds 7181da177e4SLinus Torvalds if (act) { 71977c728c2SRalf Baechle s32 handler; 7201da177e4SLinus Torvalds int err = 0; 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, act, sizeof(*act))) 7231da177e4SLinus Torvalds return -EFAULT; 72477c728c2SRalf Baechle err |= __get_user(handler, &act->sa_handler); 7259bbf28a3SAtsushi Nemoto new_sa.sa.sa_handler = (void __user *)(s64)handler; 7261da177e4SLinus Torvalds err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags); 7271da177e4SLinus Torvalds err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); 7281da177e4SLinus Torvalds if (err) 7291da177e4SLinus Torvalds return -EFAULT; 7301da177e4SLinus Torvalds } 7311da177e4SLinus Torvalds 7321da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds if (!ret && oact) { 7351da177e4SLinus Torvalds int err = 0; 7361da177e4SLinus Torvalds 7371da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 7381da177e4SLinus Torvalds return -EFAULT; 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds err |= __put_user((u32)(u64)old_sa.sa.sa_handler, 7411da177e4SLinus Torvalds &oact->sa_handler); 7421da177e4SLinus Torvalds err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags); 7431da177e4SLinus Torvalds err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask); 7441da177e4SLinus Torvalds if (err) 7451da177e4SLinus Torvalds return -EFAULT; 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds out: 7481da177e4SLinus Torvalds return ret; 7491da177e4SLinus Torvalds } 7501da177e4SLinus Torvalds 7519c6031ccSAtsushi Nemoto asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, 7529bbf28a3SAtsushi Nemoto compat_sigset_t __user *oset, unsigned int sigsetsize) 7531da177e4SLinus Torvalds { 7541da177e4SLinus Torvalds sigset_t old_set, new_set; 7551da177e4SLinus Torvalds int ret; 7561da177e4SLinus Torvalds mm_segment_t old_fs = get_fs(); 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds if (set && get_sigset(&new_set, set)) 7591da177e4SLinus Torvalds return -EFAULT; 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds set_fs(KERNEL_DS); 7629bbf28a3SAtsushi Nemoto ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL, 7639bbf28a3SAtsushi Nemoto oset ? (sigset_t __user *)&old_set : NULL, 7649bbf28a3SAtsushi Nemoto sigsetsize); 7651da177e4SLinus Torvalds set_fs(old_fs); 7661da177e4SLinus Torvalds 7671da177e4SLinus Torvalds if (!ret && oset && put_sigset(&old_set, oset)) 7681da177e4SLinus Torvalds return -EFAULT; 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds return ret; 7711da177e4SLinus Torvalds } 7721da177e4SLinus Torvalds 7739bbf28a3SAtsushi Nemoto asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset, 7741da177e4SLinus Torvalds unsigned int sigsetsize) 7751da177e4SLinus Torvalds { 7761da177e4SLinus Torvalds int ret; 7771da177e4SLinus Torvalds sigset_t set; 7781da177e4SLinus Torvalds mm_segment_t old_fs = get_fs(); 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds set_fs(KERNEL_DS); 7819bbf28a3SAtsushi Nemoto ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize); 7821da177e4SLinus Torvalds set_fs(old_fs); 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds if (!ret && put_sigset(&set, uset)) 7851da177e4SLinus Torvalds return -EFAULT; 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds return ret; 7881da177e4SLinus Torvalds } 7891da177e4SLinus Torvalds 7909bbf28a3SAtsushi Nemoto asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) 7911da177e4SLinus Torvalds { 7921da177e4SLinus Torvalds siginfo_t info; 7931da177e4SLinus Torvalds int ret; 7941da177e4SLinus Torvalds mm_segment_t old_fs = get_fs(); 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds if (copy_from_user(&info, uinfo, 3*sizeof(int)) || 7971da177e4SLinus Torvalds copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) 7981da177e4SLinus Torvalds return -EFAULT; 7991da177e4SLinus Torvalds set_fs(KERNEL_DS); 8009bbf28a3SAtsushi Nemoto ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info); 8011da177e4SLinus Torvalds set_fs(old_fs); 8021da177e4SLinus Torvalds return ret; 8031da177e4SLinus Torvalds } 80454f2da75SRalf Baechle 80554f2da75SRalf Baechle asmlinkage long 80654f2da75SRalf Baechle sys32_waitid(int which, compat_pid_t pid, 80754f2da75SRalf Baechle compat_siginfo_t __user *uinfo, int options, 80854f2da75SRalf Baechle struct compat_rusage __user *uru) 80954f2da75SRalf Baechle { 81054f2da75SRalf Baechle siginfo_t info; 81154f2da75SRalf Baechle struct rusage ru; 81254f2da75SRalf Baechle long ret; 81354f2da75SRalf Baechle mm_segment_t old_fs = get_fs(); 81454f2da75SRalf Baechle 81554f2da75SRalf Baechle info.si_signo = 0; 81654f2da75SRalf Baechle set_fs(KERNEL_DS); 81754f2da75SRalf Baechle ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, 81854f2da75SRalf Baechle uru ? (struct rusage __user *) &ru : NULL); 81954f2da75SRalf Baechle set_fs(old_fs); 82054f2da75SRalf Baechle 82154f2da75SRalf Baechle if (ret < 0 || info.si_signo == 0) 82254f2da75SRalf Baechle return ret; 82354f2da75SRalf Baechle 82454f2da75SRalf Baechle if (uru && (ret = put_compat_rusage(&ru, uru))) 82554f2da75SRalf Baechle return ret; 82654f2da75SRalf Baechle 82754f2da75SRalf Baechle BUG_ON(info.si_code & __SI_MASK); 82854f2da75SRalf Baechle info.si_code |= __SI_CHLD; 82954f2da75SRalf Baechle return copy_siginfo_to_user32(uinfo, &info); 83054f2da75SRalf Baechle } 831