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 71da177e4SLinus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle 81da177e4SLinus Torvalds * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 91da177e4SLinus Torvalds */ 1002416dcfSRalf Baechle #include <linux/cache.h> 111da177e4SLinus Torvalds #include <linux/sched.h> 121da177e4SLinus Torvalds #include <linux/mm.h> 131da177e4SLinus Torvalds #include <linux/personality.h> 141da177e4SLinus Torvalds #include <linux/smp.h> 151da177e4SLinus Torvalds #include <linux/smp_lock.h> 161da177e4SLinus Torvalds #include <linux/kernel.h> 171da177e4SLinus Torvalds #include <linux/signal.h> 181da177e4SLinus Torvalds #include <linux/errno.h> 191da177e4SLinus Torvalds #include <linux/wait.h> 201da177e4SLinus Torvalds #include <linux/ptrace.h> 211da177e4SLinus Torvalds #include <linux/unistd.h> 221da177e4SLinus Torvalds #include <linux/compiler.h> 231da177e4SLinus Torvalds 24e50c0a8fSRalf Baechle #include <asm/abi.h> 251da177e4SLinus Torvalds #include <asm/asm.h> 261da177e4SLinus Torvalds #include <linux/bitops.h> 271da177e4SLinus Torvalds #include <asm/cacheflush.h> 281da177e4SLinus Torvalds #include <asm/fpu.h> 291da177e4SLinus Torvalds #include <asm/sim.h> 301da177e4SLinus Torvalds #include <asm/uaccess.h> 311da177e4SLinus Torvalds #include <asm/ucontext.h> 321da177e4SLinus Torvalds #include <asm/cpu-features.h> 3302416dcfSRalf Baechle #include <asm/war.h> 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds #include "signal-common.h" 361da177e4SLinus Torvalds 3766680583SRalf Baechle /* 3866680583SRalf Baechle * Horribly complicated - with the bloody RM9000 workarounds enabled 3966680583SRalf Baechle * the signal trampolines is moving to the end of the structure so we can 4066680583SRalf Baechle * increase the alignment without breaking software compatibility. 4166680583SRalf Baechle */ 42c0b9bae9SFranck Bui-Huu #if ICACHE_REFILLS_WORKAROUND_WAR == 0 43c0b9bae9SFranck Bui-Huu 4466680583SRalf Baechle struct sigframe { 4566680583SRalf Baechle u32 sf_ass[4]; /* argument save space for o32 */ 4666680583SRalf Baechle u32 sf_code[2]; /* signal trampoline */ 4766680583SRalf Baechle struct sigcontext sf_sc; 4866680583SRalf Baechle sigset_t sf_mask; 4966680583SRalf Baechle }; 5066680583SRalf Baechle 51c0b9bae9SFranck Bui-Huu struct rt_sigframe { 52c0b9bae9SFranck Bui-Huu u32 rs_ass[4]; /* argument save space for o32 */ 53c0b9bae9SFranck Bui-Huu u32 rs_code[2]; /* signal trampoline */ 54c0b9bae9SFranck Bui-Huu struct siginfo rs_info; 55c0b9bae9SFranck Bui-Huu struct ucontext rs_uc; 56c0b9bae9SFranck Bui-Huu }; 57c0b9bae9SFranck Bui-Huu 58c0b9bae9SFranck Bui-Huu #else 59c0b9bae9SFranck Bui-Huu 6066680583SRalf Baechle struct sigframe { 6166680583SRalf Baechle u32 sf_ass[4]; /* argument save space for o32 */ 6266680583SRalf Baechle u32 sf_pad[2]; 6366680583SRalf Baechle struct sigcontext sf_sc; /* hw context */ 6466680583SRalf Baechle sigset_t sf_mask; 6566680583SRalf Baechle u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ 6666680583SRalf Baechle }; 6766680583SRalf Baechle 68c0b9bae9SFranck Bui-Huu struct rt_sigframe { 69c0b9bae9SFranck Bui-Huu u32 rs_ass[4]; /* argument save space for o32 */ 70c0b9bae9SFranck Bui-Huu u32 rs_pad[2]; 71c0b9bae9SFranck Bui-Huu struct siginfo rs_info; 72c0b9bae9SFranck Bui-Huu struct ucontext rs_uc; 73c0b9bae9SFranck Bui-Huu u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ 74c0b9bae9SFranck Bui-Huu }; 75c0b9bae9SFranck Bui-Huu 76c0b9bae9SFranck Bui-Huu #endif 77c0b9bae9SFranck Bui-Huu 781da177e4SLinus Torvalds /* 79c3fc4ab3SFranck Bui-Huu * Helper routines 80c3fc4ab3SFranck Bui-Huu */ 81c3fc4ab3SFranck Bui-Huu int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 82c3fc4ab3SFranck Bui-Huu { 83c3fc4ab3SFranck Bui-Huu int err = 0; 84c3fc4ab3SFranck Bui-Huu int i; 8553dc8028SAtsushi Nemoto unsigned int used_math; 86c3fc4ab3SFranck Bui-Huu 87c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->cp0_epc, &sc->sc_pc); 88c3fc4ab3SFranck Bui-Huu 89c3fc4ab3SFranck Bui-Huu err |= __put_user(0, &sc->sc_regs[0]); 90c3fc4ab3SFranck Bui-Huu for (i = 1; i < 32; i++) 91c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->regs[i], &sc->sc_regs[i]); 92c3fc4ab3SFranck Bui-Huu 939693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS 949693a853SFranck Bui-Huu err |= __put_user(regs->acx, &sc->sc_acx); 959693a853SFranck Bui-Huu #endif 96c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->hi, &sc->sc_mdhi); 97c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->lo, &sc->sc_mdlo); 98c3fc4ab3SFranck Bui-Huu if (cpu_has_dsp) { 99c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi1(), &sc->sc_hi1); 100c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo1(), &sc->sc_lo1); 101c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi2(), &sc->sc_hi2); 102c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo2(), &sc->sc_lo2); 103c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi3(), &sc->sc_hi3); 104c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo3(), &sc->sc_lo3); 105c3fc4ab3SFranck Bui-Huu err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 106c3fc4ab3SFranck Bui-Huu } 107c3fc4ab3SFranck Bui-Huu 10853dc8028SAtsushi Nemoto used_math = !!used_math(); 10953dc8028SAtsushi Nemoto err |= __put_user(used_math, &sc->sc_used_math); 110c3fc4ab3SFranck Bui-Huu 11153dc8028SAtsushi Nemoto if (used_math) { 112c3fc4ab3SFranck Bui-Huu /* 113c3fc4ab3SFranck Bui-Huu * Save FPU state to signal context. Signal handler 114c3fc4ab3SFranck Bui-Huu * will "inherit" current FPU state. 115c3fc4ab3SFranck Bui-Huu */ 11653dc8028SAtsushi Nemoto own_fpu(1); 11753dc8028SAtsushi Nemoto enable_fp_in_kernel(); 118c3fc4ab3SFranck Bui-Huu err |= save_fp_context(sc); 11953dc8028SAtsushi Nemoto disable_fp_in_kernel(); 120c3fc4ab3SFranck Bui-Huu } 121c3fc4ab3SFranck Bui-Huu return err; 122c3fc4ab3SFranck Bui-Huu } 123c3fc4ab3SFranck Bui-Huu 124c6a2f467SAtsushi Nemoto int fpcsr_pending(unsigned int __user *fpcsr) 125c6a2f467SAtsushi Nemoto { 126c6a2f467SAtsushi Nemoto int err, sig = 0; 127c6a2f467SAtsushi Nemoto unsigned int csr, enabled; 128c6a2f467SAtsushi Nemoto 129c6a2f467SAtsushi Nemoto err = __get_user(csr, fpcsr); 130c6a2f467SAtsushi Nemoto enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); 131c6a2f467SAtsushi Nemoto /* 132c6a2f467SAtsushi Nemoto * If the signal handler set some FPU exceptions, clear it and 133c6a2f467SAtsushi Nemoto * send SIGFPE. 134c6a2f467SAtsushi Nemoto */ 135c6a2f467SAtsushi Nemoto if (csr & enabled) { 136c6a2f467SAtsushi Nemoto csr &= ~enabled; 137c6a2f467SAtsushi Nemoto err |= __put_user(csr, fpcsr); 138c6a2f467SAtsushi Nemoto sig = SIGFPE; 139c6a2f467SAtsushi Nemoto } 140c6a2f467SAtsushi Nemoto return err ?: sig; 141c6a2f467SAtsushi Nemoto } 142c6a2f467SAtsushi Nemoto 143c6a2f467SAtsushi Nemoto static int 144c6a2f467SAtsushi Nemoto check_and_restore_fp_context(struct sigcontext __user *sc) 145c6a2f467SAtsushi Nemoto { 146c6a2f467SAtsushi Nemoto int err, sig; 147c6a2f467SAtsushi Nemoto 148c6a2f467SAtsushi Nemoto err = sig = fpcsr_pending(&sc->sc_fpc_csr); 149c6a2f467SAtsushi Nemoto if (err > 0) 150c6a2f467SAtsushi Nemoto err = 0; 151c6a2f467SAtsushi Nemoto err |= restore_fp_context(sc); 152c6a2f467SAtsushi Nemoto return err ?: sig; 153c6a2f467SAtsushi Nemoto } 154c6a2f467SAtsushi Nemoto 155c3fc4ab3SFranck Bui-Huu int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 156c3fc4ab3SFranck Bui-Huu { 157c3fc4ab3SFranck Bui-Huu unsigned int used_math; 158c3fc4ab3SFranck Bui-Huu unsigned long treg; 159c3fc4ab3SFranck Bui-Huu int err = 0; 160c3fc4ab3SFranck Bui-Huu int i; 161c3fc4ab3SFranck Bui-Huu 162c3fc4ab3SFranck Bui-Huu /* Always make any pending restarted system calls return -EINTR */ 163c3fc4ab3SFranck Bui-Huu current_thread_info()->restart_block.fn = do_no_restart_syscall; 164c3fc4ab3SFranck Bui-Huu 165c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->cp0_epc, &sc->sc_pc); 1669693a853SFranck Bui-Huu 1679693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS 1689693a853SFranck Bui-Huu err |= __get_user(regs->acx, &sc->sc_acx); 1699693a853SFranck Bui-Huu #endif 170c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->hi, &sc->sc_mdhi); 171c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->lo, &sc->sc_mdlo); 172c3fc4ab3SFranck Bui-Huu if (cpu_has_dsp) { 173c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); 174c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); 175c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); 176c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); 177c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); 178c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); 179c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); 180c3fc4ab3SFranck Bui-Huu } 181c3fc4ab3SFranck Bui-Huu 182c3fc4ab3SFranck Bui-Huu for (i = 1; i < 32; i++) 183c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->regs[i], &sc->sc_regs[i]); 184c3fc4ab3SFranck Bui-Huu 185c3fc4ab3SFranck Bui-Huu err |= __get_user(used_math, &sc->sc_used_math); 186c3fc4ab3SFranck Bui-Huu conditional_used_math(used_math); 187c3fc4ab3SFranck Bui-Huu 18853dc8028SAtsushi Nemoto if (used_math) { 189c3fc4ab3SFranck Bui-Huu /* restore fpu context if we have used it before */ 19053dc8028SAtsushi Nemoto own_fpu(0); 19153dc8028SAtsushi Nemoto enable_fp_in_kernel(); 192c6a2f467SAtsushi Nemoto if (!err) 193c6a2f467SAtsushi Nemoto err = check_and_restore_fp_context(sc); 19453dc8028SAtsushi Nemoto disable_fp_in_kernel(); 195c3fc4ab3SFranck Bui-Huu } else { 196c3fc4ab3SFranck Bui-Huu /* signal handler may have used FPU. Give it up. */ 19753dc8028SAtsushi Nemoto lose_fpu(0); 198c3fc4ab3SFranck Bui-Huu } 199c3fc4ab3SFranck Bui-Huu 200c3fc4ab3SFranck Bui-Huu return err; 201c3fc4ab3SFranck Bui-Huu } 202c3fc4ab3SFranck Bui-Huu 203c3fc4ab3SFranck Bui-Huu void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 204c3fc4ab3SFranck Bui-Huu size_t frame_size) 205c3fc4ab3SFranck Bui-Huu { 206c3fc4ab3SFranck Bui-Huu unsigned long sp; 207c3fc4ab3SFranck Bui-Huu 208c3fc4ab3SFranck Bui-Huu /* Default to using normal stack */ 209c3fc4ab3SFranck Bui-Huu sp = regs->regs[29]; 210c3fc4ab3SFranck Bui-Huu 211c3fc4ab3SFranck Bui-Huu /* 212c3fc4ab3SFranck Bui-Huu * FPU emulator may have it's own trampoline active just 213c3fc4ab3SFranck Bui-Huu * above the user stack, 16-bytes before the next lowest 214c3fc4ab3SFranck Bui-Huu * 16 byte boundary. Try to avoid trashing it. 215c3fc4ab3SFranck Bui-Huu */ 216c3fc4ab3SFranck Bui-Huu sp -= 32; 217c3fc4ab3SFranck Bui-Huu 218c3fc4ab3SFranck Bui-Huu /* This is the X/Open sanctioned signal stack switching. */ 219c3fc4ab3SFranck Bui-Huu if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) 220c3fc4ab3SFranck Bui-Huu sp = current->sas_ss_sp + current->sas_ss_size; 221c3fc4ab3SFranck Bui-Huu 222c3fc4ab3SFranck Bui-Huu return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); 223c3fc4ab3SFranck Bui-Huu } 224c3fc4ab3SFranck Bui-Huu 225c3fc4ab3SFranck Bui-Huu int install_sigtramp(unsigned int __user *tramp, unsigned int syscall) 226c3fc4ab3SFranck Bui-Huu { 227c3fc4ab3SFranck Bui-Huu int err; 228c3fc4ab3SFranck Bui-Huu 229c3fc4ab3SFranck Bui-Huu /* 230c3fc4ab3SFranck Bui-Huu * Set up the return code ... 231c3fc4ab3SFranck Bui-Huu * 232c3fc4ab3SFranck Bui-Huu * li v0, __NR__foo_sigreturn 233c3fc4ab3SFranck Bui-Huu * syscall 234c3fc4ab3SFranck Bui-Huu */ 235c3fc4ab3SFranck Bui-Huu 236c3fc4ab3SFranck Bui-Huu err = __put_user(0x24020000 + syscall, tramp + 0); 237c3fc4ab3SFranck Bui-Huu err |= __put_user(0x0000000c , tramp + 1); 238c3fc4ab3SFranck Bui-Huu if (ICACHE_REFILLS_WORKAROUND_WAR) { 239c3fc4ab3SFranck Bui-Huu err |= __put_user(0, tramp + 2); 240c3fc4ab3SFranck Bui-Huu err |= __put_user(0, tramp + 3); 241c3fc4ab3SFranck Bui-Huu err |= __put_user(0, tramp + 4); 242c3fc4ab3SFranck Bui-Huu err |= __put_user(0, tramp + 5); 243c3fc4ab3SFranck Bui-Huu err |= __put_user(0, tramp + 6); 244c3fc4ab3SFranck Bui-Huu err |= __put_user(0, tramp + 7); 245c3fc4ab3SFranck Bui-Huu } 246c3fc4ab3SFranck Bui-Huu flush_cache_sigtramp((unsigned long) tramp); 247c3fc4ab3SFranck Bui-Huu 248c3fc4ab3SFranck Bui-Huu return err; 249c3fc4ab3SFranck Bui-Huu } 250c3fc4ab3SFranck Bui-Huu 251c3fc4ab3SFranck Bui-Huu /* 2521da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 2531da177e4SLinus Torvalds */ 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 256f90080a0SFranck Bui-Huu asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs) 2571da177e4SLinus Torvalds { 2587b3e2fc8SRalf Baechle sigset_t newset; 259fe00f943SRalf Baechle sigset_t __user *uset; 2601da177e4SLinus Torvalds 261fe00f943SRalf Baechle uset = (sigset_t __user *) regs.regs[4]; 2621da177e4SLinus Torvalds if (copy_from_user(&newset, uset, sizeof(sigset_t))) 2631da177e4SLinus Torvalds return -EFAULT; 2641da177e4SLinus Torvalds sigdelsetmask(&newset, ~_BLOCKABLE); 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 2677b3e2fc8SRalf Baechle current->saved_sigmask = current->blocked; 2681da177e4SLinus Torvalds current->blocked = newset; 2691da177e4SLinus Torvalds recalc_sigpending(); 2701da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 2731da177e4SLinus Torvalds schedule(); 2747b3e2fc8SRalf Baechle set_thread_flag(TIF_RESTORE_SIGMASK); 2757b3e2fc8SRalf Baechle return -ERESTARTNOHAND; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds #endif 2781da177e4SLinus Torvalds 279f90080a0SFranck Bui-Huu asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) 2801da177e4SLinus Torvalds { 2817b3e2fc8SRalf Baechle sigset_t newset; 282fe00f943SRalf Baechle sigset_t __user *unewset; 2831da177e4SLinus Torvalds size_t sigsetsize; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds /* XXX Don't preclude handling different sized sigset_t's. */ 2861da177e4SLinus Torvalds sigsetsize = regs.regs[5]; 2871da177e4SLinus Torvalds if (sigsetsize != sizeof(sigset_t)) 2881da177e4SLinus Torvalds return -EINVAL; 2891da177e4SLinus Torvalds 290fe00f943SRalf Baechle unewset = (sigset_t __user *) regs.regs[4]; 2911da177e4SLinus Torvalds if (copy_from_user(&newset, unewset, sizeof(newset))) 2921da177e4SLinus Torvalds return -EFAULT; 2931da177e4SLinus Torvalds sigdelsetmask(&newset, ~_BLOCKABLE); 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 2967b3e2fc8SRalf Baechle current->saved_sigmask = current->blocked; 2971da177e4SLinus Torvalds current->blocked = newset; 2981da177e4SLinus Torvalds recalc_sigpending(); 2991da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds current->state = TASK_INTERRUPTIBLE; 3021da177e4SLinus Torvalds schedule(); 3037b3e2fc8SRalf Baechle set_thread_flag(TIF_RESTORE_SIGMASK); 3047b3e2fc8SRalf Baechle return -ERESTARTNOHAND; 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 3089c6031ccSAtsushi Nemoto asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act, 3099c6031ccSAtsushi Nemoto struct sigaction __user *oact) 3101da177e4SLinus Torvalds { 3111da177e4SLinus Torvalds struct k_sigaction new_ka, old_ka; 3121da177e4SLinus Torvalds int ret; 3131da177e4SLinus Torvalds int err = 0; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds if (act) { 3161da177e4SLinus Torvalds old_sigset_t mask; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, act, sizeof(*act))) 3191da177e4SLinus Torvalds return -EFAULT; 3201da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); 3211da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 3221da177e4SLinus Torvalds err |= __get_user(mask, &act->sa_mask.sig[0]); 3231da177e4SLinus Torvalds if (err) 3241da177e4SLinus Torvalds return -EFAULT; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds siginitset(&new_ka.sa.sa_mask, mask); 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds if (!ret && oact) { 3321da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 3331da177e4SLinus Torvalds return -EFAULT; 3341da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 3351da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); 3361da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 3371da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[1]); 3381da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[2]); 3391da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[3]); 3401da177e4SLinus Torvalds if (err) 3411da177e4SLinus Torvalds return -EFAULT; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds return ret; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds #endif 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs) 3491da177e4SLinus Torvalds { 350fe00f943SRalf Baechle const stack_t __user *uss = (const stack_t __user *) regs.regs[4]; 351fe00f943SRalf Baechle stack_t __user *uoss = (stack_t __user *) regs.regs[5]; 3521da177e4SLinus Torvalds unsigned long usp = regs.regs[29]; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds return do_sigaltstack(uss, uoss, usp); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 358f90080a0SFranck Bui-Huu asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) 3591da177e4SLinus Torvalds { 3609bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 3611da177e4SLinus Torvalds sigset_t blocked; 362c6a2f467SAtsushi Nemoto int sig; 3631da177e4SLinus Torvalds 3649bbf28a3SAtsushi Nemoto frame = (struct sigframe __user *) regs.regs[29]; 3651da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 3661da177e4SLinus Torvalds goto badframe; 3671da177e4SLinus Torvalds if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) 3681da177e4SLinus Torvalds goto badframe; 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds sigdelsetmask(&blocked, ~_BLOCKABLE); 3711da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 3721da177e4SLinus Torvalds current->blocked = blocked; 3731da177e4SLinus Torvalds recalc_sigpending(); 3741da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 3751da177e4SLinus Torvalds 376c6a2f467SAtsushi Nemoto sig = restore_sigcontext(®s, &frame->sf_sc); 377c6a2f467SAtsushi Nemoto if (sig < 0) 3781da177e4SLinus Torvalds goto badframe; 379c6a2f467SAtsushi Nemoto else if (sig) 380c6a2f467SAtsushi Nemoto force_sig(sig, current); 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds /* 3831da177e4SLinus Torvalds * Don't let your children do this ... 3841da177e4SLinus Torvalds */ 3851da177e4SLinus Torvalds __asm__ __volatile__( 3861da177e4SLinus Torvalds "move\t$29, %0\n\t" 3871da177e4SLinus Torvalds "j\tsyscall_exit" 3881da177e4SLinus Torvalds :/* no outputs */ 3891da177e4SLinus Torvalds :"r" (®s)); 3901da177e4SLinus Torvalds /* Unreached */ 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds badframe: 3931da177e4SLinus Torvalds force_sig(SIGSEGV, current); 3941da177e4SLinus Torvalds } 395e50c0a8fSRalf Baechle #endif /* CONFIG_TRAD_SIGNALS */ 3961da177e4SLinus Torvalds 397f90080a0SFranck Bui-Huu asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) 3981da177e4SLinus Torvalds { 3999bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 4001da177e4SLinus Torvalds sigset_t set; 4011da177e4SLinus Torvalds stack_t st; 402c6a2f467SAtsushi Nemoto int sig; 4031da177e4SLinus Torvalds 4049bbf28a3SAtsushi Nemoto frame = (struct rt_sigframe __user *) regs.regs[29]; 4051da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 4061da177e4SLinus Torvalds goto badframe; 4071da177e4SLinus Torvalds if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 4081da177e4SLinus Torvalds goto badframe; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds sigdelsetmask(&set, ~_BLOCKABLE); 4111da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 4121da177e4SLinus Torvalds current->blocked = set; 4131da177e4SLinus Torvalds recalc_sigpending(); 4141da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 4151da177e4SLinus Torvalds 416c6a2f467SAtsushi Nemoto sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); 417c6a2f467SAtsushi Nemoto if (sig < 0) 4181da177e4SLinus Torvalds goto badframe; 419c6a2f467SAtsushi Nemoto else if (sig) 420c6a2f467SAtsushi Nemoto force_sig(sig, current); 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) 4231da177e4SLinus Torvalds goto badframe; 4241da177e4SLinus Torvalds /* It is more difficult to avoid calling this function than to 4251da177e4SLinus Torvalds call it and ignore errors. */ 4269bbf28a3SAtsushi Nemoto do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]); 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* 4291da177e4SLinus Torvalds * Don't let your children do this ... 4301da177e4SLinus Torvalds */ 4311da177e4SLinus Torvalds __asm__ __volatile__( 4321da177e4SLinus Torvalds "move\t$29, %0\n\t" 4331da177e4SLinus Torvalds "j\tsyscall_exit" 4341da177e4SLinus Torvalds :/* no outputs */ 4351da177e4SLinus Torvalds :"r" (®s)); 4361da177e4SLinus Torvalds /* Unreached */ 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds badframe: 4391da177e4SLinus Torvalds force_sig(SIGSEGV, current); 4401da177e4SLinus Torvalds } 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 443151fd6acSRalf Baechle static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, 4441da177e4SLinus Torvalds int signr, sigset_t *set) 4451da177e4SLinus Torvalds { 4469bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 4471da177e4SLinus Torvalds int err = 0; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 4501da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 4511da177e4SLinus Torvalds goto give_sigsegv; 4521da177e4SLinus Torvalds 453601dde45SFranck Bui-Huu err |= install_sigtramp(frame->sf_code, __NR_sigreturn); 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->sf_sc); 4561da177e4SLinus Torvalds err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 4571da177e4SLinus Torvalds if (err) 4581da177e4SLinus Torvalds goto give_sigsegv; 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds /* 4611da177e4SLinus Torvalds * Arguments to signal handler: 4621da177e4SLinus Torvalds * 4631da177e4SLinus Torvalds * a0 = signal number 4641da177e4SLinus Torvalds * a1 = 0 (should be cause) 4651da177e4SLinus Torvalds * a2 = pointer to struct sigcontext 4661da177e4SLinus Torvalds * 4671da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to the 4681da177e4SLinus Torvalds * struct sigframe. 4691da177e4SLinus Torvalds */ 4701da177e4SLinus Torvalds regs->regs[ 4] = signr; 4711da177e4SLinus Torvalds regs->regs[ 5] = 0; 4721da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->sf_sc; 4731da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 4741da177e4SLinus Torvalds regs->regs[31] = (unsigned long) frame->sf_code; 4751da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 4761da177e4SLinus Torvalds 477722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 4781da177e4SLinus Torvalds current->comm, current->pid, 479722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 4807b3e2fc8SRalf Baechle return 0; 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds give_sigsegv: 4831da177e4SLinus Torvalds force_sigsegv(signr, current); 4847b3e2fc8SRalf Baechle return -EFAULT; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds #endif 4871da177e4SLinus Torvalds 488151fd6acSRalf Baechle static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, 4891da177e4SLinus Torvalds int signr, sigset_t *set, siginfo_t *info) 4901da177e4SLinus Torvalds { 4919bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 4921da177e4SLinus Torvalds int err = 0; 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 4951da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 4961da177e4SLinus Torvalds goto give_sigsegv; 4971da177e4SLinus Torvalds 498601dde45SFranck Bui-Huu err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn); 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds /* Create siginfo. */ 5011da177e4SLinus Torvalds err |= copy_siginfo_to_user(&frame->rs_info, info); 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds /* Create the ucontext. */ 5041da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 5055665a0acSAtsushi Nemoto err |= __put_user(NULL, &frame->rs_uc.uc_link); 5069c6031ccSAtsushi Nemoto err |= __put_user((void __user *)current->sas_ss_sp, 5071da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_sp); 5081da177e4SLinus Torvalds err |= __put_user(sas_ss_flags(regs->regs[29]), 5091da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_flags); 5101da177e4SLinus Torvalds err |= __put_user(current->sas_ss_size, 5111da177e4SLinus Torvalds &frame->rs_uc.uc_stack.ss_size); 5121da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 5131da177e4SLinus Torvalds err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds if (err) 5161da177e4SLinus Torvalds goto give_sigsegv; 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds /* 5191da177e4SLinus Torvalds * Arguments to signal handler: 5201da177e4SLinus Torvalds * 5211da177e4SLinus Torvalds * a0 = signal number 5221da177e4SLinus Torvalds * a1 = 0 (should be cause) 5231da177e4SLinus Torvalds * a2 = pointer to ucontext 5241da177e4SLinus Torvalds * 5251da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 5261da177e4SLinus Torvalds * the struct rt_sigframe. 5271da177e4SLinus Torvalds */ 5281da177e4SLinus Torvalds regs->regs[ 4] = signr; 5291da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 5301da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 5311da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 5321da177e4SLinus Torvalds regs->regs[31] = (unsigned long) frame->rs_code; 5331da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 5341da177e4SLinus Torvalds 535722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 5361da177e4SLinus Torvalds current->comm, current->pid, 5371da177e4SLinus Torvalds frame, regs->cp0_epc, regs->regs[31]); 538722bb63dSFranck Bui-Huu 5397b3e2fc8SRalf Baechle return 0; 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds give_sigsegv: 5421da177e4SLinus Torvalds force_sigsegv(signr, current); 5437b3e2fc8SRalf Baechle return -EFAULT; 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 546151fd6acSRalf Baechle struct mips_abi mips_abi = { 547151fd6acSRalf Baechle #ifdef CONFIG_TRAD_SIGNALS 548151fd6acSRalf Baechle .setup_frame = setup_frame, 549151fd6acSRalf Baechle #endif 550151fd6acSRalf Baechle .setup_rt_frame = setup_rt_frame, 551151fd6acSRalf Baechle .restart = __NR_restart_syscall 552151fd6acSRalf Baechle }; 553151fd6acSRalf Baechle 554e692eb30SFranck Bui-Huu static int handle_signal(unsigned long sig, siginfo_t *info, 5551da177e4SLinus Torvalds struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) 5561da177e4SLinus Torvalds { 557129bc8f7SRalf Baechle int ret; 558129bc8f7SRalf Baechle 5591da177e4SLinus Torvalds switch(regs->regs[0]) { 5601da177e4SLinus Torvalds case ERESTART_RESTARTBLOCK: 5611da177e4SLinus Torvalds case ERESTARTNOHAND: 5621da177e4SLinus Torvalds regs->regs[2] = EINTR; 5631da177e4SLinus Torvalds break; 5641da177e4SLinus Torvalds case ERESTARTSYS: 5651da177e4SLinus Torvalds if (!(ka->sa.sa_flags & SA_RESTART)) { 5661da177e4SLinus Torvalds regs->regs[2] = EINTR; 5671da177e4SLinus Torvalds break; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds /* fallthrough */ 5701da177e4SLinus Torvalds case ERESTARTNOINTR: /* Userland will reload $v0. */ 5711da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 5721da177e4SLinus Torvalds regs->cp0_epc -= 8; 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds regs->regs[0] = 0; /* Don't deal with this again. */ 5761da177e4SLinus Torvalds 577e50c0a8fSRalf Baechle if (sig_uses_siginfo(ka)) 578129bc8f7SRalf Baechle ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); 5791da177e4SLinus Torvalds else 580129bc8f7SRalf Baechle ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 5831da177e4SLinus Torvalds sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); 58469be8f18SSteven Rostedt if (!(ka->sa.sa_flags & SA_NODEFER)) 5851da177e4SLinus Torvalds sigaddset(¤t->blocked,sig); 5861da177e4SLinus Torvalds recalc_sigpending(); 5871da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 588129bc8f7SRalf Baechle 589129bc8f7SRalf Baechle return ret; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds 592151fd6acSRalf Baechle static void do_signal(struct pt_regs *regs) 5931da177e4SLinus Torvalds { 5941da177e4SLinus Torvalds struct k_sigaction ka; 5957b3e2fc8SRalf Baechle sigset_t *oldset; 5961da177e4SLinus Torvalds siginfo_t info; 5971da177e4SLinus Torvalds int signr; 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds /* 6001da177e4SLinus Torvalds * We want the common case to go fast, which is why we may in certain 6011da177e4SLinus Torvalds * cases get here from kernel mode. Just return without doing anything 6021da177e4SLinus Torvalds * if so. 6031da177e4SLinus Torvalds */ 6041da177e4SLinus Torvalds if (!user_mode(regs)) 60540ac5d47SRalf Baechle return; 6061da177e4SLinus Torvalds 6077b3e2fc8SRalf Baechle if (test_thread_flag(TIF_RESTORE_SIGMASK)) 6087b3e2fc8SRalf Baechle oldset = ¤t->saved_sigmask; 6097b3e2fc8SRalf Baechle else 6101da177e4SLinus Torvalds oldset = ¤t->blocked; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds signr = get_signal_to_deliver(&info, &ka, regs, NULL); 6137b3e2fc8SRalf Baechle if (signr > 0) { 6147b3e2fc8SRalf Baechle /* Whee! Actually deliver the signal. */ 6157b3e2fc8SRalf Baechle if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { 6167b3e2fc8SRalf Baechle /* 6177b3e2fc8SRalf Baechle * A signal was successfully delivered; the saved 6187b3e2fc8SRalf Baechle * sigmask will have been stored in the signal frame, 6197b3e2fc8SRalf Baechle * and will be restored by sigreturn, so we can simply 6207b3e2fc8SRalf Baechle * clear the TIF_RESTORE_SIGMASK flag. 6217b3e2fc8SRalf Baechle */ 6227b3e2fc8SRalf Baechle if (test_thread_flag(TIF_RESTORE_SIGMASK)) 6237b3e2fc8SRalf Baechle clear_thread_flag(TIF_RESTORE_SIGMASK); 6247b3e2fc8SRalf Baechle } 62545887e12SRalf Baechle 62645887e12SRalf Baechle return; 6277b3e2fc8SRalf Baechle } 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds /* 6301da177e4SLinus Torvalds * Who's code doesn't conform to the restartable syscall convention 6311da177e4SLinus Torvalds * dies here!!! The li instruction, a single machine instruction, 6321da177e4SLinus Torvalds * must directly be followed by the syscall instruction. 6331da177e4SLinus Torvalds */ 6341da177e4SLinus Torvalds if (regs->regs[0]) { 6351da177e4SLinus Torvalds if (regs->regs[2] == ERESTARTNOHAND || 6361da177e4SLinus Torvalds regs->regs[2] == ERESTARTSYS || 6371da177e4SLinus Torvalds regs->regs[2] == ERESTARTNOINTR) { 6381da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 6391da177e4SLinus Torvalds regs->cp0_epc -= 8; 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds if (regs->regs[2] == ERESTART_RESTARTBLOCK) { 642151fd6acSRalf Baechle regs->regs[2] = current->thread.abi->restart; 6431da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 6441da177e4SLinus Torvalds regs->cp0_epc -= 4; 6451da177e4SLinus Torvalds } 64613fdd31aSRalf Baechle regs->regs[0] = 0; /* Don't deal with this again. */ 6471da177e4SLinus Torvalds } 6487b3e2fc8SRalf Baechle 6497b3e2fc8SRalf Baechle /* 6507b3e2fc8SRalf Baechle * If there's no signal to deliver, we just put the saved sigmask 6517b3e2fc8SRalf Baechle * back 6527b3e2fc8SRalf Baechle */ 6537b3e2fc8SRalf Baechle if (test_thread_flag(TIF_RESTORE_SIGMASK)) { 6547b3e2fc8SRalf Baechle clear_thread_flag(TIF_RESTORE_SIGMASK); 6557b3e2fc8SRalf Baechle sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); 6567b3e2fc8SRalf Baechle } 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds /* 6601da177e4SLinus Torvalds * notification of userspace execution resumption 6617b3e2fc8SRalf Baechle * - triggered by the TIF_WORK_MASK flags 6621da177e4SLinus Torvalds */ 6637b3e2fc8SRalf Baechle asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, 6641da177e4SLinus Torvalds __u32 thread_info_flags) 6651da177e4SLinus Torvalds { 6661da177e4SLinus Torvalds /* deal with pending signal delivery */ 6677b3e2fc8SRalf Baechle if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) 668151fd6acSRalf Baechle do_signal(regs); 6691da177e4SLinus Torvalds } 670