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/fpu.h> 3302416dcfSRalf Baechle #include <asm/war.h> 34d814c28cSDavid Daney #include <asm/vdso.h> 35b81947c6SDavid Howells #include <asm/dsp.h> 361da177e4SLinus Torvalds 3736a1f2c2SFranck Bui-Huu #include "signal-common.h" 3836a1f2c2SFranck Bui-Huu 39137f6f3eSRalf Baechle static int (*save_fp_context32)(struct sigcontext32 __user *sc); 40137f6f3eSRalf Baechle static int (*restore_fp_context32)(struct sigcontext32 __user *sc); 41137f6f3eSRalf Baechle 42137f6f3eSRalf Baechle extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); 43137f6f3eSRalf Baechle extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); 44137f6f3eSRalf Baechle 45137f6f3eSRalf Baechle extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc); 46137f6f3eSRalf Baechle extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc); 47137f6f3eSRalf Baechle 481da177e4SLinus Torvalds /* 491da177e4SLinus Torvalds * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 501da177e4SLinus Torvalds */ 511da177e4SLinus Torvalds #define __NR_O32_restart_syscall 4253 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds /* 32-bit compatibility types */ 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds typedef unsigned int __sighandler32_t; 561da177e4SLinus Torvalds typedef void (*vfptr_t)(void); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds struct ucontext32 { 591da177e4SLinus Torvalds u32 uc_flags; 601da177e4SLinus Torvalds s32 uc_link; 61ea536ad4SAl Viro compat_stack_t uc_stack; 621da177e4SLinus Torvalds struct sigcontext32 uc_mcontext; 6301ee6037SRalf Baechle compat_sigset_t uc_sigmask; /* mask last for extensibility */ 641da177e4SLinus Torvalds }; 651da177e4SLinus Torvalds 66dd02f06aSRalf Baechle struct sigframe32 { 67dd02f06aSRalf Baechle u32 sf_ass[4]; /* argument save space for o32 */ 68d814c28cSDavid Daney u32 sf_pad[2]; /* Was: signal trampoline */ 69dd02f06aSRalf Baechle struct sigcontext32 sf_sc; 70755f21bbSAtsushi Nemoto compat_sigset_t sf_mask; 71dd02f06aSRalf Baechle }; 72dd02f06aSRalf Baechle 73c0b9bae9SFranck Bui-Huu struct rt_sigframe32 { 74c0b9bae9SFranck Bui-Huu u32 rs_ass[4]; /* argument save space for o32 */ 75d814c28cSDavid Daney u32 rs_pad[2]; /* Was: signal trampoline */ 76c0b9bae9SFranck Bui-Huu compat_siginfo_t rs_info; 77c0b9bae9SFranck Bui-Huu struct ucontext32 rs_uc; 78c0b9bae9SFranck Bui-Huu }; 79c0b9bae9SFranck Bui-Huu 809432a9baSFranck Bui-Huu /* 819432a9baSFranck Bui-Huu * sigcontext handlers 829432a9baSFranck Bui-Huu */ 83faea6234SAtsushi Nemoto static int protected_save_fp_context32(struct sigcontext32 __user *sc) 84faea6234SAtsushi Nemoto { 85faea6234SAtsushi Nemoto int err; 86faea6234SAtsushi Nemoto while (1) { 87faea6234SAtsushi Nemoto lock_fpu_owner(); 88faea6234SAtsushi Nemoto own_fpu_inatomic(1); 89faea6234SAtsushi Nemoto err = save_fp_context32(sc); /* this might fail */ 90faea6234SAtsushi Nemoto unlock_fpu_owner(); 91faea6234SAtsushi Nemoto if (likely(!err)) 92faea6234SAtsushi Nemoto break; 93faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 94faea6234SAtsushi Nemoto err = __put_user(0, &sc->sc_fpregs[0]) | 95faea6234SAtsushi Nemoto __put_user(0, &sc->sc_fpregs[31]) | 96faea6234SAtsushi Nemoto __put_user(0, &sc->sc_fpc_csr); 97faea6234SAtsushi Nemoto if (err) 98faea6234SAtsushi Nemoto break; /* really bad sigcontext */ 99faea6234SAtsushi Nemoto } 100faea6234SAtsushi Nemoto return err; 101faea6234SAtsushi Nemoto } 102faea6234SAtsushi Nemoto 103faea6234SAtsushi Nemoto static int protected_restore_fp_context32(struct sigcontext32 __user *sc) 104faea6234SAtsushi Nemoto { 105c726b822SDavid Daney int err, tmp __maybe_unused; 106faea6234SAtsushi Nemoto while (1) { 107faea6234SAtsushi Nemoto lock_fpu_owner(); 108faea6234SAtsushi Nemoto own_fpu_inatomic(0); 109faea6234SAtsushi Nemoto err = restore_fp_context32(sc); /* this might fail */ 110faea6234SAtsushi Nemoto unlock_fpu_owner(); 111faea6234SAtsushi Nemoto if (likely(!err)) 112faea6234SAtsushi Nemoto break; 113faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 114faea6234SAtsushi Nemoto err = __get_user(tmp, &sc->sc_fpregs[0]) | 115faea6234SAtsushi Nemoto __get_user(tmp, &sc->sc_fpregs[31]) | 116faea6234SAtsushi Nemoto __get_user(tmp, &sc->sc_fpc_csr); 117faea6234SAtsushi Nemoto if (err) 118faea6234SAtsushi Nemoto break; /* really bad sigcontext */ 119faea6234SAtsushi Nemoto } 120faea6234SAtsushi Nemoto return err; 121faea6234SAtsushi Nemoto } 122faea6234SAtsushi Nemoto 1239432a9baSFranck Bui-Huu static int setup_sigcontext32(struct pt_regs *regs, 1249432a9baSFranck Bui-Huu struct sigcontext32 __user *sc) 1259432a9baSFranck Bui-Huu { 1269432a9baSFranck Bui-Huu int err = 0; 1279432a9baSFranck Bui-Huu int i; 12853dc8028SAtsushi Nemoto u32 used_math; 1299432a9baSFranck Bui-Huu 1309432a9baSFranck Bui-Huu err |= __put_user(regs->cp0_epc, &sc->sc_pc); 1319432a9baSFranck Bui-Huu 1329432a9baSFranck Bui-Huu err |= __put_user(0, &sc->sc_regs[0]); 1339432a9baSFranck Bui-Huu for (i = 1; i < 32; i++) 1349432a9baSFranck Bui-Huu err |= __put_user(regs->regs[i], &sc->sc_regs[i]); 1359432a9baSFranck Bui-Huu 1369432a9baSFranck Bui-Huu err |= __put_user(regs->hi, &sc->sc_mdhi); 1379432a9baSFranck Bui-Huu err |= __put_user(regs->lo, &sc->sc_mdlo); 1389432a9baSFranck Bui-Huu if (cpu_has_dsp) { 1399432a9baSFranck Bui-Huu err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 1409432a9baSFranck Bui-Huu err |= __put_user(mfhi1(), &sc->sc_hi1); 1419432a9baSFranck Bui-Huu err |= __put_user(mflo1(), &sc->sc_lo1); 1429432a9baSFranck Bui-Huu err |= __put_user(mfhi2(), &sc->sc_hi2); 1439432a9baSFranck Bui-Huu err |= __put_user(mflo2(), &sc->sc_lo2); 1449432a9baSFranck Bui-Huu err |= __put_user(mfhi3(), &sc->sc_hi3); 1459432a9baSFranck Bui-Huu err |= __put_user(mflo3(), &sc->sc_lo3); 1469432a9baSFranck Bui-Huu } 1479432a9baSFranck Bui-Huu 14853dc8028SAtsushi Nemoto used_math = !!used_math(); 14953dc8028SAtsushi Nemoto err |= __put_user(used_math, &sc->sc_used_math); 1509432a9baSFranck Bui-Huu 15153dc8028SAtsushi Nemoto if (used_math) { 1529432a9baSFranck Bui-Huu /* 1539432a9baSFranck Bui-Huu * Save FPU state to signal context. Signal handler 1549432a9baSFranck Bui-Huu * will "inherit" current FPU state. 1559432a9baSFranck Bui-Huu */ 156faea6234SAtsushi Nemoto err |= protected_save_fp_context32(sc); 1579432a9baSFranck Bui-Huu } 1589432a9baSFranck Bui-Huu return err; 1599432a9baSFranck Bui-Huu } 1609432a9baSFranck Bui-Huu 161c6a2f467SAtsushi Nemoto static int 162c6a2f467SAtsushi Nemoto check_and_restore_fp_context32(struct sigcontext32 __user *sc) 163c6a2f467SAtsushi Nemoto { 164c6a2f467SAtsushi Nemoto int err, sig; 165c6a2f467SAtsushi Nemoto 166c6a2f467SAtsushi Nemoto err = sig = fpcsr_pending(&sc->sc_fpc_csr); 167c6a2f467SAtsushi Nemoto if (err > 0) 168c6a2f467SAtsushi Nemoto err = 0; 169faea6234SAtsushi Nemoto err |= protected_restore_fp_context32(sc); 170c6a2f467SAtsushi Nemoto return err ?: sig; 171c6a2f467SAtsushi Nemoto } 172c6a2f467SAtsushi Nemoto 1739432a9baSFranck Bui-Huu static int restore_sigcontext32(struct pt_regs *regs, 1749432a9baSFranck Bui-Huu struct sigcontext32 __user *sc) 1759432a9baSFranck Bui-Huu { 1769432a9baSFranck Bui-Huu u32 used_math; 1779432a9baSFranck Bui-Huu int err = 0; 1789432a9baSFranck Bui-Huu s32 treg; 1799432a9baSFranck Bui-Huu int i; 1809432a9baSFranck Bui-Huu 1819432a9baSFranck Bui-Huu /* Always make any pending restarted system calls return -EINTR */ 1829432a9baSFranck Bui-Huu current_thread_info()->restart_block.fn = do_no_restart_syscall; 1839432a9baSFranck Bui-Huu 1849432a9baSFranck Bui-Huu err |= __get_user(regs->cp0_epc, &sc->sc_pc); 1859432a9baSFranck Bui-Huu err |= __get_user(regs->hi, &sc->sc_mdhi); 1869432a9baSFranck Bui-Huu err |= __get_user(regs->lo, &sc->sc_mdlo); 1879432a9baSFranck Bui-Huu if (cpu_has_dsp) { 1889432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); 1899432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); 1909432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); 1919432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); 1929432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); 1939432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); 1949432a9baSFranck Bui-Huu err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); 1959432a9baSFranck Bui-Huu } 1969432a9baSFranck Bui-Huu 1979432a9baSFranck Bui-Huu for (i = 1; i < 32; i++) 1989432a9baSFranck Bui-Huu err |= __get_user(regs->regs[i], &sc->sc_regs[i]); 1999432a9baSFranck Bui-Huu 2009432a9baSFranck Bui-Huu err |= __get_user(used_math, &sc->sc_used_math); 2019432a9baSFranck Bui-Huu conditional_used_math(used_math); 2029432a9baSFranck Bui-Huu 20353dc8028SAtsushi Nemoto if (used_math) { 2049432a9baSFranck Bui-Huu /* restore fpu context if we have used it before */ 205c6a2f467SAtsushi Nemoto if (!err) 206c6a2f467SAtsushi Nemoto err = check_and_restore_fp_context32(sc); 2079432a9baSFranck Bui-Huu } else { 2089432a9baSFranck Bui-Huu /* signal handler may have used FPU. Give it up. */ 20953dc8028SAtsushi Nemoto lose_fpu(0); 2109432a9baSFranck Bui-Huu } 2119432a9baSFranck Bui-Huu 2129432a9baSFranck Bui-Huu return err; 2139432a9baSFranck Bui-Huu } 2149432a9baSFranck Bui-Huu 2159432a9baSFranck Bui-Huu /* 2169432a9baSFranck Bui-Huu * 2179432a9baSFranck Bui-Huu */ 2181da177e4SLinus Torvalds extern void __put_sigset_unknown_nsig(void); 2191da177e4SLinus Torvalds extern void __get_sigset_unknown_nsig(void); 2201da177e4SLinus Torvalds 2219bbf28a3SAtsushi Nemoto static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) 2221da177e4SLinus Torvalds { 2231da177e4SLinus Torvalds int err = 0; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) 2261da177e4SLinus Torvalds return -EFAULT; 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds switch (_NSIG_WORDS) { 2291da177e4SLinus Torvalds default: 2301da177e4SLinus Torvalds __put_sigset_unknown_nsig(); 2311da177e4SLinus Torvalds case 2: 2321da177e4SLinus Torvalds err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]); 2331da177e4SLinus Torvalds err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); 2341da177e4SLinus Torvalds case 1: 2351da177e4SLinus Torvalds err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]); 2361da177e4SLinus Torvalds err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds return err; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2429c6031ccSAtsushi Nemoto static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) 2431da177e4SLinus Torvalds { 2441da177e4SLinus Torvalds int err = 0; 2451da177e4SLinus Torvalds unsigned long sig[4]; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) 2481da177e4SLinus Torvalds return -EFAULT; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds switch (_NSIG_WORDS) { 2511da177e4SLinus Torvalds default: 2521da177e4SLinus Torvalds __get_sigset_unknown_nsig(); 2531da177e4SLinus Torvalds case 2: 2541da177e4SLinus Torvalds err |= __get_user(sig[3], &ubuf->sig[3]); 2551da177e4SLinus Torvalds err |= __get_user(sig[2], &ubuf->sig[2]); 2561da177e4SLinus Torvalds kbuf->sig[1] = sig[2] | (sig[3] << 32); 2571da177e4SLinus Torvalds case 1: 2581da177e4SLinus Torvalds err |= __get_user(sig[1], &ubuf->sig[1]); 2591da177e4SLinus Torvalds err |= __get_user(sig[0], &ubuf->sig[0]); 2601da177e4SLinus Torvalds kbuf->sig[0] = sig[0] | (sig[1] << 32); 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds return err; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /* 2671da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 2681da177e4SLinus Torvalds */ 2691da177e4SLinus Torvalds 2701910f4abSAl Viro asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset) 2711da177e4SLinus Torvalds { 2721910f4abSAl Viro return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t)); 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 275aa584802SAl Viro SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act, 276aa584802SAl Viro struct compat_sigaction __user *, oact) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds struct k_sigaction new_ka, old_ka; 2791da177e4SLinus Torvalds int ret; 2801da177e4SLinus Torvalds int err = 0; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds if (act) { 2831da177e4SLinus Torvalds old_sigset_t mask; 28477c728c2SRalf Baechle s32 handler; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, act, sizeof(*act))) 2871da177e4SLinus Torvalds return -EFAULT; 28877c728c2SRalf Baechle err |= __get_user(handler, &act->sa_handler); 2899bbf28a3SAtsushi Nemoto new_ka.sa.sa_handler = (void __user *)(s64)handler; 2901da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 2911da177e4SLinus Torvalds err |= __get_user(mask, &act->sa_mask.sig[0]); 2921da177e4SLinus Torvalds if (err) 2931da177e4SLinus Torvalds return -EFAULT; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds siginitset(&new_ka.sa.sa_mask, mask); 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds if (!ret && oact) { 3011da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 3021da177e4SLinus Torvalds return -EFAULT; 3031da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 3041da177e4SLinus Torvalds err |= __put_user((u32)(u64)old_ka.sa.sa_handler, 3051da177e4SLinus Torvalds &oact->sa_handler); 3061da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 3071da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[1]); 3081da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[2]); 3091da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[3]); 3101da177e4SLinus Torvalds if (err) 3111da177e4SLinus Torvalds return -EFAULT; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds return ret; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 317*ce395960SAl Viro int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) 3181da177e4SLinus Torvalds { 3191da177e4SLinus Torvalds int err; 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) 3221da177e4SLinus Torvalds return -EFAULT; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /* If you change siginfo_t structure, please be sure 3251da177e4SLinus Torvalds this code is fixed accordingly. 3261da177e4SLinus Torvalds It should never copy any pad contained in the structure 3271da177e4SLinus Torvalds to avoid security leaks, but must copy the generic 3281da177e4SLinus Torvalds 3 ints plus the relevant union member. 3291da177e4SLinus Torvalds This routine must convert siginfo from 64bit to 32bit as well 3301da177e4SLinus Torvalds at the same time. */ 3311da177e4SLinus Torvalds err = __put_user(from->si_signo, &to->si_signo); 3321da177e4SLinus Torvalds err |= __put_user(from->si_errno, &to->si_errno); 3331da177e4SLinus Torvalds err |= __put_user((short)from->si_code, &to->si_code); 3341da177e4SLinus Torvalds if (from->si_code < 0) 3351da177e4SLinus Torvalds err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); 3361da177e4SLinus Torvalds else { 3371da177e4SLinus Torvalds switch (from->si_code >> 16) { 338a982099cSRalf Baechle case __SI_TIMER >> 16: 339a982099cSRalf Baechle err |= __put_user(from->si_tid, &to->si_tid); 340a982099cSRalf Baechle err |= __put_user(from->si_overrun, &to->si_overrun); 341a982099cSRalf Baechle err |= __put_user(from->si_int, &to->si_int); 342a982099cSRalf Baechle break; 3431da177e4SLinus Torvalds case __SI_CHLD >> 16: 3441da177e4SLinus Torvalds err |= __put_user(from->si_utime, &to->si_utime); 3451da177e4SLinus Torvalds err |= __put_user(from->si_stime, &to->si_stime); 3461da177e4SLinus Torvalds err |= __put_user(from->si_status, &to->si_status); 3471da177e4SLinus Torvalds default: 3481da177e4SLinus Torvalds err |= __put_user(from->si_pid, &to->si_pid); 3491da177e4SLinus Torvalds err |= __put_user(from->si_uid, &to->si_uid); 3501da177e4SLinus Torvalds break; 3511da177e4SLinus Torvalds case __SI_FAULT >> 16: 3525665a0acSAtsushi Nemoto err |= __put_user((unsigned long)from->si_addr, &to->si_addr); 3531da177e4SLinus Torvalds break; 3541da177e4SLinus Torvalds case __SI_POLL >> 16: 3551da177e4SLinus Torvalds err |= __put_user(from->si_band, &to->si_band); 3561da177e4SLinus Torvalds err |= __put_user(from->si_fd, &to->si_fd); 3571da177e4SLinus Torvalds break; 3581da177e4SLinus Torvalds case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ 3591da177e4SLinus Torvalds case __SI_MESGQ >> 16: 3601da177e4SLinus Torvalds err |= __put_user(from->si_pid, &to->si_pid); 3611da177e4SLinus Torvalds err |= __put_user(from->si_uid, &to->si_uid); 3621da177e4SLinus Torvalds err |= __put_user(from->si_int, &to->si_int); 3631da177e4SLinus Torvalds break; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds return err; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 3695d9a76cdSThomas Bogendoerfer int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) 3705d9a76cdSThomas Bogendoerfer { 3715d9a76cdSThomas Bogendoerfer memset(to, 0, sizeof *to); 3725d9a76cdSThomas Bogendoerfer 3735d9a76cdSThomas Bogendoerfer if (copy_from_user(to, from, 3*sizeof(int)) || 3745d9a76cdSThomas Bogendoerfer copy_from_user(to->_sifields._pad, 3755d9a76cdSThomas Bogendoerfer from->_sifields._pad, SI_PAD_SIZE32)) 3765d9a76cdSThomas Bogendoerfer return -EFAULT; 3775d9a76cdSThomas Bogendoerfer 3785d9a76cdSThomas Bogendoerfer return 0; 3795d9a76cdSThomas Bogendoerfer } 3805d9a76cdSThomas Bogendoerfer 381f90080a0SFranck Bui-Huu asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) 3821da177e4SLinus Torvalds { 383dd02f06aSRalf Baechle struct sigframe32 __user *frame; 3841da177e4SLinus Torvalds sigset_t blocked; 385c6a2f467SAtsushi Nemoto int sig; 3861da177e4SLinus Torvalds 387dd02f06aSRalf Baechle frame = (struct sigframe32 __user *) regs.regs[29]; 3881da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 3891da177e4SLinus Torvalds goto badframe; 390431dc804SRalf Baechle if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) 3911da177e4SLinus Torvalds goto badframe; 3921da177e4SLinus Torvalds 3938598f3cdSMatt Fleming set_current_blocked(&blocked); 3941da177e4SLinus Torvalds 395c6a2f467SAtsushi Nemoto sig = restore_sigcontext32(®s, &frame->sf_sc); 396c6a2f467SAtsushi Nemoto if (sig < 0) 3971da177e4SLinus Torvalds goto badframe; 398c6a2f467SAtsushi Nemoto else if (sig) 399c6a2f467SAtsushi Nemoto force_sig(sig, current); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* 4021da177e4SLinus Torvalds * Don't let your children do this ... 4031da177e4SLinus Torvalds */ 4041da177e4SLinus Torvalds __asm__ __volatile__( 4051da177e4SLinus Torvalds "move\t$29, %0\n\t" 4061da177e4SLinus Torvalds "j\tsyscall_exit" 4071da177e4SLinus Torvalds :/* no outputs */ 4081da177e4SLinus Torvalds :"r" (®s)); 4091da177e4SLinus Torvalds /* Unreached */ 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds badframe: 4121da177e4SLinus Torvalds force_sig(SIGSEGV, current); 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 415f90080a0SFranck Bui-Huu asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) 4161da177e4SLinus Torvalds { 4179bbf28a3SAtsushi Nemoto struct rt_sigframe32 __user *frame; 4181da177e4SLinus Torvalds sigset_t set; 419c6a2f467SAtsushi Nemoto int sig; 4201da177e4SLinus Torvalds 4219bbf28a3SAtsushi Nemoto frame = (struct rt_sigframe32 __user *) regs.regs[29]; 4221da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 4231da177e4SLinus Torvalds goto badframe; 424431dc804SRalf Baechle if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) 4251da177e4SLinus Torvalds goto badframe; 4261da177e4SLinus Torvalds 4278598f3cdSMatt Fleming set_current_blocked(&set); 4281da177e4SLinus Torvalds 429c6a2f467SAtsushi Nemoto sig = restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext); 430c6a2f467SAtsushi Nemoto if (sig < 0) 4311da177e4SLinus Torvalds goto badframe; 432c6a2f467SAtsushi Nemoto else if (sig) 433c6a2f467SAtsushi Nemoto force_sig(sig, current); 4341da177e4SLinus Torvalds 435ea536ad4SAl Viro if (compat_restore_altstack(&frame->rs_uc.uc_stack)) 4361da177e4SLinus Torvalds goto badframe; 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds /* 4391da177e4SLinus Torvalds * Don't let your children do this ... 4401da177e4SLinus Torvalds */ 4411da177e4SLinus Torvalds __asm__ __volatile__( 4421da177e4SLinus Torvalds "move\t$29, %0\n\t" 4431da177e4SLinus Torvalds "j\tsyscall_exit" 4441da177e4SLinus Torvalds :/* no outputs */ 4451da177e4SLinus Torvalds :"r" (®s)); 4461da177e4SLinus Torvalds /* Unreached */ 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds badframe: 4491da177e4SLinus Torvalds force_sig(SIGSEGV, current); 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds 452d814c28cSDavid Daney static int setup_frame_32(void *sig_return, struct k_sigaction *ka, 453d814c28cSDavid Daney struct pt_regs *regs, int signr, sigset_t *set) 4541da177e4SLinus Torvalds { 455dd02f06aSRalf Baechle struct sigframe32 __user *frame; 4561da177e4SLinus Torvalds int err = 0; 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 4591da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 4601da177e4SLinus Torvalds goto give_sigsegv; 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds err |= setup_sigcontext32(regs, &frame->sf_sc); 463431dc804SRalf Baechle err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); 464431dc804SRalf Baechle 4651da177e4SLinus Torvalds if (err) 4661da177e4SLinus Torvalds goto give_sigsegv; 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds /* 4691da177e4SLinus Torvalds * Arguments to signal handler: 4701da177e4SLinus Torvalds * 4711da177e4SLinus Torvalds * a0 = signal number 4721da177e4SLinus Torvalds * a1 = 0 (should be cause) 4731da177e4SLinus Torvalds * a2 = pointer to struct sigcontext 4741da177e4SLinus Torvalds * 4751da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to the 4761da177e4SLinus Torvalds * struct sigframe. 4771da177e4SLinus Torvalds */ 4781da177e4SLinus Torvalds regs->regs[ 4] = signr; 4791da177e4SLinus Torvalds regs->regs[ 5] = 0; 4801da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->sf_sc; 4811da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 482d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 4831da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 4841da177e4SLinus Torvalds 485722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 4861da177e4SLinus Torvalds current->comm, current->pid, 487722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 488722bb63dSFranck Bui-Huu 4897b3e2fc8SRalf Baechle return 0; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds give_sigsegv: 4921da177e4SLinus Torvalds force_sigsegv(signr, current); 4937b3e2fc8SRalf Baechle return -EFAULT; 4941da177e4SLinus Torvalds } 4951da177e4SLinus Torvalds 496d814c28cSDavid Daney static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, 497d814c28cSDavid Daney struct pt_regs *regs, int signr, sigset_t *set, 498d814c28cSDavid Daney siginfo_t *info) 4991da177e4SLinus Torvalds { 5009bbf28a3SAtsushi Nemoto struct rt_sigframe32 __user *frame; 5011da177e4SLinus Torvalds int err = 0; 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 5041da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 5051da177e4SLinus Torvalds goto give_sigsegv; 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ 5081da177e4SLinus Torvalds err |= copy_siginfo_to_user32(&frame->rs_info, info); 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds /* Create the ucontext. */ 5111da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 5121da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_link); 513ea536ad4SAl Viro err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); 5141da177e4SLinus Torvalds err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); 515431dc804SRalf Baechle err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds if (err) 5181da177e4SLinus Torvalds goto give_sigsegv; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /* 5211da177e4SLinus Torvalds * Arguments to signal handler: 5221da177e4SLinus Torvalds * 5231da177e4SLinus Torvalds * a0 = signal number 5241da177e4SLinus Torvalds * a1 = 0 (should be cause) 5251da177e4SLinus Torvalds * a2 = pointer to ucontext 5261da177e4SLinus Torvalds * 5271da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 5281da177e4SLinus Torvalds * the struct rt_sigframe32. 5291da177e4SLinus Torvalds */ 5301da177e4SLinus Torvalds regs->regs[ 4] = signr; 5311da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 5321da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 5331da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 534d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 5351da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 5361da177e4SLinus Torvalds 537722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 5381da177e4SLinus Torvalds current->comm, current->pid, 539722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 540722bb63dSFranck Bui-Huu 5417b3e2fc8SRalf Baechle return 0; 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds give_sigsegv: 5441da177e4SLinus Torvalds force_sigsegv(signr, current); 5457b3e2fc8SRalf Baechle return -EFAULT; 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds /* 549151fd6acSRalf Baechle * o32 compatibility on 64-bit kernels, without DSP ASE 5501da177e4SLinus Torvalds */ 551151fd6acSRalf Baechle struct mips_abi mips_abi_32 = { 552151fd6acSRalf Baechle .setup_frame = setup_frame_32, 553d814c28cSDavid Daney .signal_return_offset = 554d814c28cSDavid Daney offsetof(struct mips_vdso, o32_signal_trampoline), 555151fd6acSRalf Baechle .setup_rt_frame = setup_rt_frame_32, 556d814c28cSDavid Daney .rt_signal_return_offset = 557d814c28cSDavid Daney offsetof(struct mips_vdso, o32_rt_signal_trampoline), 558151fd6acSRalf Baechle .restart = __NR_O32_restart_syscall 559151fd6acSRalf Baechle }; 5601da177e4SLinus Torvalds 561137f6f3eSRalf Baechle static int signal32_init(void) 562137f6f3eSRalf Baechle { 563137f6f3eSRalf Baechle if (cpu_has_fpu) { 564137f6f3eSRalf Baechle save_fp_context32 = _save_fp_context32; 565137f6f3eSRalf Baechle restore_fp_context32 = _restore_fp_context32; 566137f6f3eSRalf Baechle } else { 567137f6f3eSRalf Baechle save_fp_context32 = fpu_emulator_save_context32; 568137f6f3eSRalf Baechle restore_fp_context32 = fpu_emulator_restore_context32; 569137f6f3eSRalf Baechle } 570137f6f3eSRalf Baechle 571137f6f3eSRalf Baechle return 0; 572137f6f3eSRalf Baechle } 573137f6f3eSRalf Baechle 574137f6f3eSRalf Baechle arch_initcall(signal32_init); 575