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. 9ca750649SLeonid Yegoshin * Copyright (C) 2014, Imagination Technologies Ltd. 101da177e4SLinus Torvalds */ 1102416dcfSRalf Baechle #include <linux/cache.h> 12c3fc5cd5SRalf Baechle #include <linux/context_tracking.h> 131f717929SRalf Baechle #include <linux/irqflags.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 151da177e4SLinus Torvalds #include <linux/mm.h> 161da177e4SLinus Torvalds #include <linux/personality.h> 171da177e4SLinus Torvalds #include <linux/smp.h> 181da177e4SLinus Torvalds #include <linux/kernel.h> 191da177e4SLinus Torvalds #include <linux/signal.h> 201da177e4SLinus Torvalds #include <linux/errno.h> 211da177e4SLinus Torvalds #include <linux/wait.h> 221da177e4SLinus Torvalds #include <linux/ptrace.h> 231da177e4SLinus Torvalds #include <linux/unistd.h> 241da177e4SLinus Torvalds #include <linux/compiler.h> 25dbda6ac0SRalf Baechle #include <linux/syscalls.h> 26faea6234SAtsushi Nemoto #include <linux/uaccess.h> 27733e5e4bSDavid Howells #include <linux/tracehook.h> 281da177e4SLinus Torvalds 29e50c0a8fSRalf Baechle #include <asm/abi.h> 301da177e4SLinus Torvalds #include <asm/asm.h> 311da177e4SLinus Torvalds #include <linux/bitops.h> 321da177e4SLinus Torvalds #include <asm/cacheflush.h> 331da177e4SLinus Torvalds #include <asm/fpu.h> 34eec43a22SPaul Burton #include <asm/msa.h> 351da177e4SLinus Torvalds #include <asm/sim.h> 361da177e4SLinus Torvalds #include <asm/ucontext.h> 371da177e4SLinus Torvalds #include <asm/cpu-features.h> 3802416dcfSRalf Baechle #include <asm/war.h> 39d814c28cSDavid Daney #include <asm/vdso.h> 40b81947c6SDavid Howells #include <asm/dsp.h> 4101be057bSDouglas Leung #include <asm/inst.h> 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds #include "signal-common.h" 441da177e4SLinus Torvalds 45137f6f3eSRalf Baechle static int (*save_fp_context)(struct sigcontext __user *sc); 46137f6f3eSRalf Baechle static int (*restore_fp_context)(struct sigcontext __user *sc); 47137f6f3eSRalf Baechle 48137f6f3eSRalf Baechle extern asmlinkage int _save_fp_context(struct sigcontext __user *sc); 49137f6f3eSRalf Baechle extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); 50137f6f3eSRalf Baechle 51eec43a22SPaul Burton extern asmlinkage int _save_msa_context(struct sigcontext __user *sc); 52eec43a22SPaul Burton extern asmlinkage int _restore_msa_context(struct sigcontext __user *sc); 53eec43a22SPaul Burton 5466680583SRalf Baechle struct sigframe { 5566680583SRalf Baechle u32 sf_ass[4]; /* argument save space for o32 */ 56d814c28cSDavid Daney u32 sf_pad[2]; /* Was: signal trampoline */ 5766680583SRalf Baechle struct sigcontext sf_sc; 5866680583SRalf Baechle sigset_t sf_mask; 5966680583SRalf Baechle }; 6066680583SRalf Baechle 61c0b9bae9SFranck Bui-Huu struct rt_sigframe { 62c0b9bae9SFranck Bui-Huu u32 rs_ass[4]; /* argument save space for o32 */ 63d814c28cSDavid Daney u32 rs_pad[2]; /* Was: signal trampoline */ 64c0b9bae9SFranck Bui-Huu struct siginfo rs_info; 65c0b9bae9SFranck Bui-Huu struct ucontext rs_uc; 66c0b9bae9SFranck Bui-Huu }; 67c0b9bae9SFranck Bui-Huu 681da177e4SLinus Torvalds /* 69b2ead528SPaul Burton * Thread saved context copy to/from a signal context presumed to be on the 70b2ead528SPaul Burton * user stack, and therefore accessed with appropriate macros from uaccess.h. 71b2ead528SPaul Burton */ 72b2ead528SPaul Burton static int copy_fp_to_sigcontext(struct sigcontext __user *sc) 73b2ead528SPaul Burton { 74b2ead528SPaul Burton int i; 75b2ead528SPaul Burton int err = 0; 76b2ead528SPaul Burton 776bbfd65eSPaul Burton for (i = 0; i < NUM_FPU_REGS; i++) { 78b2ead528SPaul Burton err |= 79b2ead528SPaul Burton __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), 80b2ead528SPaul Burton &sc->sc_fpregs[i]); 81b2ead528SPaul Burton } 82b2ead528SPaul Burton err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); 83b2ead528SPaul Burton 84b2ead528SPaul Burton return err; 85b2ead528SPaul Burton } 86b2ead528SPaul Burton 87b2ead528SPaul Burton static int copy_fp_from_sigcontext(struct sigcontext __user *sc) 88b2ead528SPaul Burton { 89b2ead528SPaul Burton int i; 90b2ead528SPaul Burton int err = 0; 91b2ead528SPaul Burton u64 fpr_val; 92b2ead528SPaul Burton 936bbfd65eSPaul Burton for (i = 0; i < NUM_FPU_REGS; i++) { 94b2ead528SPaul Burton err |= __get_user(fpr_val, &sc->sc_fpregs[i]); 95b2ead528SPaul Burton set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); 96b2ead528SPaul Burton } 97b2ead528SPaul Burton err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); 98b2ead528SPaul Burton 99b2ead528SPaul Burton return err; 100b2ead528SPaul Burton } 101b2ead528SPaul Burton 102b2ead528SPaul Burton /* 103eec43a22SPaul Burton * These functions will save only the upper 64 bits of the vector registers, 104eec43a22SPaul Burton * since the lower 64 bits have already been saved as the scalar FP context. 105eec43a22SPaul Burton */ 106eec43a22SPaul Burton static int copy_msa_to_sigcontext(struct sigcontext __user *sc) 107eec43a22SPaul Burton { 108eec43a22SPaul Burton int i; 109eec43a22SPaul Burton int err = 0; 110eec43a22SPaul Burton 111eec43a22SPaul Burton for (i = 0; i < NUM_FPU_REGS; i++) { 112eec43a22SPaul Burton err |= 113eec43a22SPaul Burton __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 1), 114eec43a22SPaul Burton &sc->sc_msaregs[i]); 115eec43a22SPaul Burton } 116eec43a22SPaul Burton err |= __put_user(current->thread.fpu.msacsr, &sc->sc_msa_csr); 117eec43a22SPaul Burton 118eec43a22SPaul Burton return err; 119eec43a22SPaul Burton } 120eec43a22SPaul Burton 121eec43a22SPaul Burton static int copy_msa_from_sigcontext(struct sigcontext __user *sc) 122eec43a22SPaul Burton { 123eec43a22SPaul Burton int i; 124eec43a22SPaul Burton int err = 0; 125eec43a22SPaul Burton u64 val; 126eec43a22SPaul Burton 127eec43a22SPaul Burton for (i = 0; i < NUM_FPU_REGS; i++) { 128eec43a22SPaul Burton err |= __get_user(val, &sc->sc_msaregs[i]); 129eec43a22SPaul Burton set_fpr64(¤t->thread.fpu.fpr[i], 1, val); 130eec43a22SPaul Burton } 131eec43a22SPaul Burton err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr); 132eec43a22SPaul Burton 133eec43a22SPaul Burton return err; 134eec43a22SPaul Burton } 135eec43a22SPaul Burton 136eec43a22SPaul Burton /* 137c3fc4ab3SFranck Bui-Huu * Helper routines 138c3fc4ab3SFranck Bui-Huu */ 139eec43a22SPaul Burton static int protected_save_fp_context(struct sigcontext __user *sc, 140eec43a22SPaul Burton unsigned used_math) 141faea6234SAtsushi Nemoto { 142faea6234SAtsushi Nemoto int err; 143eec43a22SPaul Burton bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA); 144ca750649SLeonid Yegoshin #ifndef CONFIG_EVA 145faea6234SAtsushi Nemoto while (1) { 146faea6234SAtsushi Nemoto lock_fpu_owner(); 147ff3aa5f2SPaul Burton if (is_fpu_owner()) { 148ff3aa5f2SPaul Burton err = save_fp_context(sc); 149eec43a22SPaul Burton if (save_msa && !err) 150eec43a22SPaul Burton err = _save_msa_context(sc); 151faea6234SAtsushi Nemoto unlock_fpu_owner(); 152ff3aa5f2SPaul Burton } else { 153ff3aa5f2SPaul Burton unlock_fpu_owner(); 154ff3aa5f2SPaul Burton err = copy_fp_to_sigcontext(sc); 155eec43a22SPaul Burton if (save_msa && !err) 156eec43a22SPaul Burton err = copy_msa_to_sigcontext(sc); 157ff3aa5f2SPaul Burton } 158faea6234SAtsushi Nemoto if (likely(!err)) 159faea6234SAtsushi Nemoto break; 160faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 161faea6234SAtsushi Nemoto err = __put_user(0, &sc->sc_fpregs[0]) | 162faea6234SAtsushi Nemoto __put_user(0, &sc->sc_fpregs[31]) | 163faea6234SAtsushi Nemoto __put_user(0, &sc->sc_fpc_csr); 164faea6234SAtsushi Nemoto if (err) 165faea6234SAtsushi Nemoto break; /* really bad sigcontext */ 166faea6234SAtsushi Nemoto } 167ca750649SLeonid Yegoshin #else 168ca750649SLeonid Yegoshin /* 169ca750649SLeonid Yegoshin * EVA does not have FPU EVA instructions so saving fpu context directly 170ca750649SLeonid Yegoshin * does not work. 171ca750649SLeonid Yegoshin */ 172ca750649SLeonid Yegoshin disable_msa(); 173ca750649SLeonid Yegoshin lose_fpu(1); 174ca750649SLeonid Yegoshin err = save_fp_context(sc); /* this might fail */ 175ca750649SLeonid Yegoshin if (save_msa && !err) 176ca750649SLeonid Yegoshin err = copy_msa_to_sigcontext(sc); 177ca750649SLeonid Yegoshin #endif 178faea6234SAtsushi Nemoto return err; 179faea6234SAtsushi Nemoto } 180faea6234SAtsushi Nemoto 181eec43a22SPaul Burton static int protected_restore_fp_context(struct sigcontext __user *sc, 182eec43a22SPaul Burton unsigned used_math) 183faea6234SAtsushi Nemoto { 184c726b822SDavid Daney int err, tmp __maybe_unused; 185eec43a22SPaul Burton bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA); 186ca750649SLeonid Yegoshin #ifndef CONFIG_EVA 187faea6234SAtsushi Nemoto while (1) { 188faea6234SAtsushi Nemoto lock_fpu_owner(); 189ff3aa5f2SPaul Burton if (is_fpu_owner()) { 190ff3aa5f2SPaul Burton err = restore_fp_context(sc); 191eec43a22SPaul Burton if (restore_msa && !err) { 192eec43a22SPaul Burton enable_msa(); 193eec43a22SPaul Burton err = _restore_msa_context(sc); 194eec43a22SPaul Burton } else { 195eec43a22SPaul Burton /* signal handler may have used MSA */ 196eec43a22SPaul Burton disable_msa(); 197eec43a22SPaul Burton } 198faea6234SAtsushi Nemoto unlock_fpu_owner(); 199ff3aa5f2SPaul Burton } else { 200ff3aa5f2SPaul Burton unlock_fpu_owner(); 201ff3aa5f2SPaul Burton err = copy_fp_from_sigcontext(sc); 202eec43a22SPaul Burton if (!err && (used_math & USEDMATH_MSA)) 203eec43a22SPaul Burton err = copy_msa_from_sigcontext(sc); 204ff3aa5f2SPaul Burton } 205faea6234SAtsushi Nemoto if (likely(!err)) 206faea6234SAtsushi Nemoto break; 207faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 208faea6234SAtsushi Nemoto err = __get_user(tmp, &sc->sc_fpregs[0]) | 209faea6234SAtsushi Nemoto __get_user(tmp, &sc->sc_fpregs[31]) | 210faea6234SAtsushi Nemoto __get_user(tmp, &sc->sc_fpc_csr); 211faea6234SAtsushi Nemoto if (err) 212faea6234SAtsushi Nemoto break; /* really bad sigcontext */ 213faea6234SAtsushi Nemoto } 214ca750649SLeonid Yegoshin #else 215ca750649SLeonid Yegoshin /* 216ca750649SLeonid Yegoshin * EVA does not have FPU EVA instructions so restoring fpu context 217ca750649SLeonid Yegoshin * directly does not work. 218ca750649SLeonid Yegoshin */ 219ca750649SLeonid Yegoshin enable_msa(); 220ca750649SLeonid Yegoshin lose_fpu(0); 221ca750649SLeonid Yegoshin err = restore_fp_context(sc); /* this might fail */ 222ca750649SLeonid Yegoshin if (restore_msa && !err) 223ca750649SLeonid Yegoshin err = copy_msa_from_sigcontext(sc); 224ca750649SLeonid Yegoshin #endif 225faea6234SAtsushi Nemoto return err; 226faea6234SAtsushi Nemoto } 227faea6234SAtsushi Nemoto 228c3fc4ab3SFranck Bui-Huu int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 229c3fc4ab3SFranck Bui-Huu { 230c3fc4ab3SFranck Bui-Huu int err = 0; 231c3fc4ab3SFranck Bui-Huu int i; 23253dc8028SAtsushi Nemoto unsigned int used_math; 233c3fc4ab3SFranck Bui-Huu 234c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->cp0_epc, &sc->sc_pc); 235c3fc4ab3SFranck Bui-Huu 236c3fc4ab3SFranck Bui-Huu err |= __put_user(0, &sc->sc_regs[0]); 237c3fc4ab3SFranck Bui-Huu for (i = 1; i < 32; i++) 238c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->regs[i], &sc->sc_regs[i]); 239c3fc4ab3SFranck Bui-Huu 2409693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS 2419693a853SFranck Bui-Huu err |= __put_user(regs->acx, &sc->sc_acx); 2429693a853SFranck Bui-Huu #endif 243c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->hi, &sc->sc_mdhi); 244c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->lo, &sc->sc_mdlo); 245c3fc4ab3SFranck Bui-Huu if (cpu_has_dsp) { 246c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi1(), &sc->sc_hi1); 247c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo1(), &sc->sc_lo1); 248c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi2(), &sc->sc_hi2); 249c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo2(), &sc->sc_lo2); 250c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi3(), &sc->sc_hi3); 251c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo3(), &sc->sc_lo3); 252c3fc4ab3SFranck Bui-Huu err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 253c3fc4ab3SFranck Bui-Huu } 254c3fc4ab3SFranck Bui-Huu 255eec43a22SPaul Burton used_math = used_math() ? USEDMATH_FP : 0; 256eec43a22SPaul Burton used_math |= thread_msa_context_live() ? USEDMATH_MSA : 0; 25753dc8028SAtsushi Nemoto err |= __put_user(used_math, &sc->sc_used_math); 258c3fc4ab3SFranck Bui-Huu 25953dc8028SAtsushi Nemoto if (used_math) { 260c3fc4ab3SFranck Bui-Huu /* 261c3fc4ab3SFranck Bui-Huu * Save FPU state to signal context. Signal handler 262c3fc4ab3SFranck Bui-Huu * will "inherit" current FPU state. 263c3fc4ab3SFranck Bui-Huu */ 264eec43a22SPaul Burton err |= protected_save_fp_context(sc, used_math); 265c3fc4ab3SFranck Bui-Huu } 266c3fc4ab3SFranck Bui-Huu return err; 267c3fc4ab3SFranck Bui-Huu } 268c3fc4ab3SFranck Bui-Huu 269c6a2f467SAtsushi Nemoto int fpcsr_pending(unsigned int __user *fpcsr) 270c6a2f467SAtsushi Nemoto { 271c6a2f467SAtsushi Nemoto int err, sig = 0; 272c6a2f467SAtsushi Nemoto unsigned int csr, enabled; 273c6a2f467SAtsushi Nemoto 274c6a2f467SAtsushi Nemoto err = __get_user(csr, fpcsr); 275c6a2f467SAtsushi Nemoto enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); 276c6a2f467SAtsushi Nemoto /* 277c6a2f467SAtsushi Nemoto * If the signal handler set some FPU exceptions, clear it and 278c6a2f467SAtsushi Nemoto * send SIGFPE. 279c6a2f467SAtsushi Nemoto */ 280c6a2f467SAtsushi Nemoto if (csr & enabled) { 281c6a2f467SAtsushi Nemoto csr &= ~enabled; 282c6a2f467SAtsushi Nemoto err |= __put_user(csr, fpcsr); 283c6a2f467SAtsushi Nemoto sig = SIGFPE; 284c6a2f467SAtsushi Nemoto } 285c6a2f467SAtsushi Nemoto return err ?: sig; 286c6a2f467SAtsushi Nemoto } 287c6a2f467SAtsushi Nemoto 288c6a2f467SAtsushi Nemoto static int 289eec43a22SPaul Burton check_and_restore_fp_context(struct sigcontext __user *sc, unsigned used_math) 290c6a2f467SAtsushi Nemoto { 291c6a2f467SAtsushi Nemoto int err, sig; 292c6a2f467SAtsushi Nemoto 293c6a2f467SAtsushi Nemoto err = sig = fpcsr_pending(&sc->sc_fpc_csr); 294c6a2f467SAtsushi Nemoto if (err > 0) 295c6a2f467SAtsushi Nemoto err = 0; 296eec43a22SPaul Burton err |= protected_restore_fp_context(sc, used_math); 297c6a2f467SAtsushi Nemoto return err ?: sig; 298c6a2f467SAtsushi Nemoto } 299c6a2f467SAtsushi Nemoto 300c3fc4ab3SFranck Bui-Huu int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 301c3fc4ab3SFranck Bui-Huu { 302c3fc4ab3SFranck Bui-Huu unsigned int used_math; 303c3fc4ab3SFranck Bui-Huu unsigned long treg; 304c3fc4ab3SFranck Bui-Huu int err = 0; 305c3fc4ab3SFranck Bui-Huu int i; 306c3fc4ab3SFranck Bui-Huu 307c3fc4ab3SFranck Bui-Huu /* Always make any pending restarted system calls return -EINTR */ 308c3fc4ab3SFranck Bui-Huu current_thread_info()->restart_block.fn = do_no_restart_syscall; 309c3fc4ab3SFranck Bui-Huu 310c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->cp0_epc, &sc->sc_pc); 3119693a853SFranck Bui-Huu 3129693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS 3139693a853SFranck Bui-Huu err |= __get_user(regs->acx, &sc->sc_acx); 3149693a853SFranck Bui-Huu #endif 315c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->hi, &sc->sc_mdhi); 316c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->lo, &sc->sc_mdlo); 317c3fc4ab3SFranck Bui-Huu if (cpu_has_dsp) { 318c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); 319c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); 320c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); 321c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); 322c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); 323c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); 324c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); 325c3fc4ab3SFranck Bui-Huu } 326c3fc4ab3SFranck Bui-Huu 327c3fc4ab3SFranck Bui-Huu for (i = 1; i < 32; i++) 328c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->regs[i], &sc->sc_regs[i]); 329c3fc4ab3SFranck Bui-Huu 330c3fc4ab3SFranck Bui-Huu err |= __get_user(used_math, &sc->sc_used_math); 331c3fc4ab3SFranck Bui-Huu conditional_used_math(used_math); 332c3fc4ab3SFranck Bui-Huu 33353dc8028SAtsushi Nemoto if (used_math) { 334c3fc4ab3SFranck Bui-Huu /* restore fpu context if we have used it before */ 335c6a2f467SAtsushi Nemoto if (!err) 336eec43a22SPaul Burton err = check_and_restore_fp_context(sc, used_math); 337c3fc4ab3SFranck Bui-Huu } else { 338eec43a22SPaul Burton /* signal handler may have used FPU or MSA. Disable them. */ 339eec43a22SPaul Burton disable_msa(); 34053dc8028SAtsushi Nemoto lose_fpu(0); 341c3fc4ab3SFranck Bui-Huu } 342c3fc4ab3SFranck Bui-Huu 343c3fc4ab3SFranck Bui-Huu return err; 344c3fc4ab3SFranck Bui-Huu } 345c3fc4ab3SFranck Bui-Huu 346c3fc4ab3SFranck Bui-Huu void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 347c3fc4ab3SFranck Bui-Huu size_t frame_size) 348c3fc4ab3SFranck Bui-Huu { 349c3fc4ab3SFranck Bui-Huu unsigned long sp; 350c3fc4ab3SFranck Bui-Huu 351c3fc4ab3SFranck Bui-Huu /* Default to using normal stack */ 352c3fc4ab3SFranck Bui-Huu sp = regs->regs[29]; 353c3fc4ab3SFranck Bui-Huu 354c3fc4ab3SFranck Bui-Huu /* 355c3fc4ab3SFranck Bui-Huu * FPU emulator may have it's own trampoline active just 356c3fc4ab3SFranck Bui-Huu * above the user stack, 16-bytes before the next lowest 357c3fc4ab3SFranck Bui-Huu * 16 byte boundary. Try to avoid trashing it. 358c3fc4ab3SFranck Bui-Huu */ 359c3fc4ab3SFranck Bui-Huu sp -= 32; 360c3fc4ab3SFranck Bui-Huu 361c3fc4ab3SFranck Bui-Huu /* This is the X/Open sanctioned signal stack switching. */ 362c3fc4ab3SFranck Bui-Huu if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) 363c3fc4ab3SFranck Bui-Huu sp = current->sas_ss_sp + current->sas_ss_size; 364c3fc4ab3SFranck Bui-Huu 365c3fc4ab3SFranck Bui-Huu return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); 366c3fc4ab3SFranck Bui-Huu } 367c3fc4ab3SFranck Bui-Huu 368c3fc4ab3SFranck Bui-Huu /* 3691da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 3701da177e4SLinus Torvalds */ 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 3731910f4abSAl Viro SYSCALL_DEFINE1(sigsuspend, sigset_t __user *, uset) 3741da177e4SLinus Torvalds { 3751910f4abSAl Viro return sys_rt_sigsuspend(uset, sizeof(sigset_t)); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds #endif 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 380dbda6ac0SRalf Baechle SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, 381dbda6ac0SRalf Baechle struct sigaction __user *, oact) 3821da177e4SLinus Torvalds { 3831da177e4SLinus Torvalds struct k_sigaction new_ka, old_ka; 3841da177e4SLinus Torvalds int ret; 3851da177e4SLinus Torvalds int err = 0; 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds if (act) { 3881da177e4SLinus Torvalds old_sigset_t mask; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, act, sizeof(*act))) 3911da177e4SLinus Torvalds return -EFAULT; 3921da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); 3931da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 3941da177e4SLinus Torvalds err |= __get_user(mask, &act->sa_mask.sig[0]); 3951da177e4SLinus Torvalds if (err) 3961da177e4SLinus Torvalds return -EFAULT; 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds siginitset(&new_ka.sa.sa_mask, mask); 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds if (!ret && oact) { 4041da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 4051da177e4SLinus Torvalds return -EFAULT; 4061da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 4071da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); 4081da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 4091da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[1]); 4101da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[2]); 4111da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[3]); 4121da177e4SLinus Torvalds if (err) 4131da177e4SLinus Torvalds return -EFAULT; 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds return ret; 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds #endif 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 421f90080a0SFranck Bui-Huu asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) 4221da177e4SLinus Torvalds { 4239bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 4241da177e4SLinus Torvalds sigset_t blocked; 425c6a2f467SAtsushi Nemoto int sig; 4261da177e4SLinus Torvalds 4279bbf28a3SAtsushi Nemoto frame = (struct sigframe __user *) regs.regs[29]; 4281da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 4291da177e4SLinus Torvalds goto badframe; 4301da177e4SLinus Torvalds if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) 4311da177e4SLinus Torvalds goto badframe; 4321da177e4SLinus Torvalds 4338598f3cdSMatt Fleming set_current_blocked(&blocked); 4341da177e4SLinus Torvalds 435c6a2f467SAtsushi Nemoto sig = restore_sigcontext(®s, &frame->sf_sc); 436c6a2f467SAtsushi Nemoto if (sig < 0) 4371da177e4SLinus Torvalds goto badframe; 438c6a2f467SAtsushi Nemoto else if (sig) 439c6a2f467SAtsushi Nemoto force_sig(sig, current); 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds /* 4421da177e4SLinus Torvalds * Don't let your children do this ... 4431da177e4SLinus Torvalds */ 4441da177e4SLinus Torvalds __asm__ __volatile__( 4451da177e4SLinus Torvalds "move\t$29, %0\n\t" 4461da177e4SLinus Torvalds "j\tsyscall_exit" 4471da177e4SLinus Torvalds :/* no outputs */ 4481da177e4SLinus Torvalds :"r" (®s)); 4491da177e4SLinus Torvalds /* Unreached */ 4501da177e4SLinus Torvalds 4511da177e4SLinus Torvalds badframe: 4521da177e4SLinus Torvalds force_sig(SIGSEGV, current); 4531da177e4SLinus Torvalds } 454e50c0a8fSRalf Baechle #endif /* CONFIG_TRAD_SIGNALS */ 4551da177e4SLinus Torvalds 456f90080a0SFranck Bui-Huu asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) 4571da177e4SLinus Torvalds { 4589bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 4591da177e4SLinus Torvalds sigset_t set; 460c6a2f467SAtsushi Nemoto int sig; 4611da177e4SLinus Torvalds 4629bbf28a3SAtsushi Nemoto frame = (struct rt_sigframe __user *) regs.regs[29]; 4631da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 4641da177e4SLinus Torvalds goto badframe; 4651da177e4SLinus Torvalds if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 4661da177e4SLinus Torvalds goto badframe; 4671da177e4SLinus Torvalds 4688598f3cdSMatt Fleming set_current_blocked(&set); 4691da177e4SLinus Torvalds 470c6a2f467SAtsushi Nemoto sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); 471c6a2f467SAtsushi Nemoto if (sig < 0) 4721da177e4SLinus Torvalds goto badframe; 473c6a2f467SAtsushi Nemoto else if (sig) 474c6a2f467SAtsushi Nemoto force_sig(sig, current); 4751da177e4SLinus Torvalds 476ea536ad4SAl Viro if (restore_altstack(&frame->rs_uc.uc_stack)) 477ea536ad4SAl Viro goto badframe; 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds /* 4801da177e4SLinus Torvalds * Don't let your children do this ... 4811da177e4SLinus Torvalds */ 4821da177e4SLinus Torvalds __asm__ __volatile__( 4831da177e4SLinus Torvalds "move\t$29, %0\n\t" 4841da177e4SLinus Torvalds "j\tsyscall_exit" 4851da177e4SLinus Torvalds :/* no outputs */ 4861da177e4SLinus Torvalds :"r" (®s)); 4871da177e4SLinus Torvalds /* Unreached */ 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds badframe: 4901da177e4SLinus Torvalds force_sig(SIGSEGV, current); 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 494d814c28cSDavid Daney static int setup_frame(void *sig_return, struct k_sigaction *ka, 495d814c28cSDavid Daney struct pt_regs *regs, int signr, sigset_t *set) 4961da177e4SLinus Torvalds { 4979bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 4981da177e4SLinus Torvalds int err = 0; 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 5011da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 5021da177e4SLinus Torvalds goto give_sigsegv; 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->sf_sc); 5051da177e4SLinus Torvalds err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 5061da177e4SLinus Torvalds if (err) 5071da177e4SLinus Torvalds goto give_sigsegv; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /* 5101da177e4SLinus Torvalds * Arguments to signal handler: 5111da177e4SLinus Torvalds * 5121da177e4SLinus Torvalds * a0 = signal number 5131da177e4SLinus Torvalds * a1 = 0 (should be cause) 5141da177e4SLinus Torvalds * a2 = pointer to struct sigcontext 5151da177e4SLinus Torvalds * 5161da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to the 5171da177e4SLinus Torvalds * struct sigframe. 5181da177e4SLinus Torvalds */ 5191da177e4SLinus Torvalds regs->regs[ 4] = signr; 5201da177e4SLinus Torvalds regs->regs[ 5] = 0; 5211da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->sf_sc; 5221da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 523d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 5241da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 5251da177e4SLinus Torvalds 526722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 5271da177e4SLinus Torvalds current->comm, current->pid, 528722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 5297b3e2fc8SRalf Baechle return 0; 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds give_sigsegv: 5321da177e4SLinus Torvalds force_sigsegv(signr, current); 5337b3e2fc8SRalf Baechle return -EFAULT; 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds #endif 5361da177e4SLinus Torvalds 537d814c28cSDavid Daney static int setup_rt_frame(void *sig_return, struct k_sigaction *ka, 538d814c28cSDavid Daney struct pt_regs *regs, int signr, sigset_t *set, 539d814c28cSDavid Daney siginfo_t *info) 5401da177e4SLinus Torvalds { 5419bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 5421da177e4SLinus Torvalds int err = 0; 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds frame = get_sigframe(ka, regs, sizeof(*frame)); 5451da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 5461da177e4SLinus Torvalds goto give_sigsegv; 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds /* Create siginfo. */ 5491da177e4SLinus Torvalds err |= copy_siginfo_to_user(&frame->rs_info, info); 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds /* Create the ucontext. */ 5521da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 5535665a0acSAtsushi Nemoto err |= __put_user(NULL, &frame->rs_uc.uc_link); 554ea536ad4SAl Viro err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); 5551da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 5561da177e4SLinus Torvalds err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds if (err) 5591da177e4SLinus Torvalds goto give_sigsegv; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds /* 5621da177e4SLinus Torvalds * Arguments to signal handler: 5631da177e4SLinus Torvalds * 5641da177e4SLinus Torvalds * a0 = signal number 5651da177e4SLinus Torvalds * a1 = 0 (should be cause) 5661da177e4SLinus Torvalds * a2 = pointer to ucontext 5671da177e4SLinus Torvalds * 5681da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 5691da177e4SLinus Torvalds * the struct rt_sigframe. 5701da177e4SLinus Torvalds */ 5711da177e4SLinus Torvalds regs->regs[ 4] = signr; 5721da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 5731da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 5741da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 575d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 5761da177e4SLinus Torvalds regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 5771da177e4SLinus Torvalds 578722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 5791da177e4SLinus Torvalds current->comm, current->pid, 5801da177e4SLinus Torvalds frame, regs->cp0_epc, regs->regs[31]); 581722bb63dSFranck Bui-Huu 5827b3e2fc8SRalf Baechle return 0; 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds give_sigsegv: 5851da177e4SLinus Torvalds force_sigsegv(signr, current); 5867b3e2fc8SRalf Baechle return -EFAULT; 5871da177e4SLinus Torvalds } 5881da177e4SLinus Torvalds 589151fd6acSRalf Baechle struct mips_abi mips_abi = { 590151fd6acSRalf Baechle #ifdef CONFIG_TRAD_SIGNALS 591151fd6acSRalf Baechle .setup_frame = setup_frame, 592d814c28cSDavid Daney .signal_return_offset = offsetof(struct mips_vdso, signal_trampoline), 593151fd6acSRalf Baechle #endif 594151fd6acSRalf Baechle .setup_rt_frame = setup_rt_frame, 595d814c28cSDavid Daney .rt_signal_return_offset = 596d814c28cSDavid Daney offsetof(struct mips_vdso, rt_signal_trampoline), 597151fd6acSRalf Baechle .restart = __NR_restart_syscall 598151fd6acSRalf Baechle }; 599151fd6acSRalf Baechle 600a610d6e6SAl Viro static void handle_signal(unsigned long sig, siginfo_t *info, 601b7f9a11aSAl Viro struct k_sigaction *ka, struct pt_regs *regs) 6021da177e4SLinus Torvalds { 603b7f9a11aSAl Viro sigset_t *oldset = sigmask_to_save(); 604129bc8f7SRalf Baechle int ret; 605d814c28cSDavid Daney struct mips_abi *abi = current->thread.abi; 60601be057bSDouglas Leung #ifdef CONFIG_CPU_MICROMIPS 60701be057bSDouglas Leung void *vdso; 60801be057bSDouglas Leung unsigned int tmp = (unsigned int)current->mm->context.vdso; 60901be057bSDouglas Leung 61001be057bSDouglas Leung set_isa16_mode(tmp); 61101be057bSDouglas Leung vdso = (void *)tmp; 61201be057bSDouglas Leung #else 613d814c28cSDavid Daney void *vdso = current->mm->context.vdso; 61401be057bSDouglas Leung #endif 615129bc8f7SRalf Baechle 6168f5a00ebSAl Viro if (regs->regs[0]) { 6178f5a00ebSAl Viro switch(regs->regs[2]) { 6181da177e4SLinus Torvalds case ERESTART_RESTARTBLOCK: 6191da177e4SLinus Torvalds case ERESTARTNOHAND: 6201da177e4SLinus Torvalds regs->regs[2] = EINTR; 6211da177e4SLinus Torvalds break; 6221da177e4SLinus Torvalds case ERESTARTSYS: 6231da177e4SLinus Torvalds if (!(ka->sa.sa_flags & SA_RESTART)) { 6241da177e4SLinus Torvalds regs->regs[2] = EINTR; 6251da177e4SLinus Torvalds break; 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds /* fallthrough */ 6288f5a00ebSAl Viro case ERESTARTNOINTR: 6291da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 6308f5a00ebSAl Viro regs->regs[2] = regs->regs[0]; 6318f5a00ebSAl Viro regs->cp0_epc -= 4; 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds regs->regs[0] = 0; /* Don't deal with this again. */ 6358f5a00ebSAl Viro } 6361da177e4SLinus Torvalds 637e50c0a8fSRalf Baechle if (sig_uses_siginfo(ka)) 638d814c28cSDavid Daney ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset, 639d814c28cSDavid Daney ka, regs, sig, oldset, info); 6401da177e4SLinus Torvalds else 641d814c28cSDavid Daney ret = abi->setup_frame(vdso + abi->signal_return_offset, 642d814c28cSDavid Daney ka, regs, sig, oldset); 6431da177e4SLinus Torvalds 644062ab57bSAl Viro if (ret) 645a610d6e6SAl Viro return; 646062ab57bSAl Viro 647efee984cSAl Viro signal_delivered(sig, info, ka, regs, 0); 6481da177e4SLinus Torvalds } 6491da177e4SLinus Torvalds 650151fd6acSRalf Baechle static void do_signal(struct pt_regs *regs) 6511da177e4SLinus Torvalds { 6521da177e4SLinus Torvalds struct k_sigaction ka; 6531da177e4SLinus Torvalds siginfo_t info; 6541da177e4SLinus Torvalds int signr; 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds signr = get_signal_to_deliver(&info, &ka, regs, NULL); 6577b3e2fc8SRalf Baechle if (signr > 0) { 6587b3e2fc8SRalf Baechle /* Whee! Actually deliver the signal. */ 659a610d6e6SAl Viro handle_signal(signr, &info, &ka, regs); 66045887e12SRalf Baechle return; 6617b3e2fc8SRalf Baechle } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds if (regs->regs[0]) { 6649ec9b5acSRalf Baechle switch (regs->regs[2]) { 6659ec9b5acSRalf Baechle case ERESTARTNOHAND: 6669ec9b5acSRalf Baechle case ERESTARTSYS: 6679ec9b5acSRalf Baechle case ERESTARTNOINTR: 6688f5a00ebSAl Viro regs->regs[2] = regs->regs[0]; 6691da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 6708f5a00ebSAl Viro regs->cp0_epc -= 4; 6719ec9b5acSRalf Baechle break; 6729ec9b5acSRalf Baechle 6739ec9b5acSRalf Baechle case ERESTART_RESTARTBLOCK: 674151fd6acSRalf Baechle regs->regs[2] = current->thread.abi->restart; 6751da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 6761da177e4SLinus Torvalds regs->cp0_epc -= 4; 6779ec9b5acSRalf Baechle break; 6781da177e4SLinus Torvalds } 67913fdd31aSRalf Baechle regs->regs[0] = 0; /* Don't deal with this again. */ 6801da177e4SLinus Torvalds } 6817b3e2fc8SRalf Baechle 6827b3e2fc8SRalf Baechle /* 6837b3e2fc8SRalf Baechle * If there's no signal to deliver, we just put the saved sigmask 6847b3e2fc8SRalf Baechle * back 6857b3e2fc8SRalf Baechle */ 68651a7b448SAl Viro restore_saved_sigmask(); 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds /* 6901da177e4SLinus Torvalds * notification of userspace execution resumption 6917b3e2fc8SRalf Baechle * - triggered by the TIF_WORK_MASK flags 6921da177e4SLinus Torvalds */ 6937b3e2fc8SRalf Baechle asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, 6941da177e4SLinus Torvalds __u32 thread_info_flags) 6951da177e4SLinus Torvalds { 6961f717929SRalf Baechle local_irq_enable(); 6971f717929SRalf Baechle 698c3fc5cd5SRalf Baechle user_exit(); 699c3fc5cd5SRalf Baechle 7001da177e4SLinus Torvalds /* deal with pending signal delivery */ 7016fd84c08SAl Viro if (thread_info_flags & _TIF_SIGPENDING) 702151fd6acSRalf Baechle do_signal(regs); 703d0420c83SDavid Howells 704d0420c83SDavid Howells if (thread_info_flags & _TIF_NOTIFY_RESUME) { 705d0420c83SDavid Howells clear_thread_flag(TIF_NOTIFY_RESUME); 706d0420c83SDavid Howells tracehook_notify_resume(regs); 707d0420c83SDavid Howells } 708c3fc5cd5SRalf Baechle 709c3fc5cd5SRalf Baechle user_enter(); 7101da177e4SLinus Torvalds } 711137f6f3eSRalf Baechle 712137f6f3eSRalf Baechle #ifdef CONFIG_SMP 713ca750649SLeonid Yegoshin #ifndef CONFIG_EVA 714137f6f3eSRalf Baechle static int smp_save_fp_context(struct sigcontext __user *sc) 715137f6f3eSRalf Baechle { 716137f6f3eSRalf Baechle return raw_cpu_has_fpu 717137f6f3eSRalf Baechle ? _save_fp_context(sc) 718b2ead528SPaul Burton : copy_fp_to_sigcontext(sc); 719137f6f3eSRalf Baechle } 720137f6f3eSRalf Baechle 721137f6f3eSRalf Baechle static int smp_restore_fp_context(struct sigcontext __user *sc) 722137f6f3eSRalf Baechle { 723137f6f3eSRalf Baechle return raw_cpu_has_fpu 724137f6f3eSRalf Baechle ? _restore_fp_context(sc) 725b2ead528SPaul Burton : copy_fp_from_sigcontext(sc); 726137f6f3eSRalf Baechle } 727ca750649SLeonid Yegoshin #endif /* CONFIG_EVA */ 728137f6f3eSRalf Baechle #endif 729137f6f3eSRalf Baechle 730137f6f3eSRalf Baechle static int signal_setup(void) 731137f6f3eSRalf Baechle { 732ca750649SLeonid Yegoshin #ifndef CONFIG_EVA 733137f6f3eSRalf Baechle #ifdef CONFIG_SMP 734137f6f3eSRalf Baechle /* For now just do the cpu_has_fpu check when the functions are invoked */ 735137f6f3eSRalf Baechle save_fp_context = smp_save_fp_context; 736137f6f3eSRalf Baechle restore_fp_context = smp_restore_fp_context; 737137f6f3eSRalf Baechle #else 738137f6f3eSRalf Baechle if (cpu_has_fpu) { 739137f6f3eSRalf Baechle save_fp_context = _save_fp_context; 740137f6f3eSRalf Baechle restore_fp_context = _restore_fp_context; 741137f6f3eSRalf Baechle } else { 742b2ead528SPaul Burton save_fp_context = copy_fp_from_sigcontext; 743b2ead528SPaul Burton restore_fp_context = copy_fp_to_sigcontext; 744137f6f3eSRalf Baechle } 745ca750649SLeonid Yegoshin #endif /* CONFIG_SMP */ 746ca750649SLeonid Yegoshin #else 747ca750649SLeonid Yegoshin save_fp_context = copy_fp_from_sigcontext;; 748ca750649SLeonid Yegoshin restore_fp_context = copy_fp_to_sigcontext; 749137f6f3eSRalf Baechle #endif 750137f6f3eSRalf Baechle 751137f6f3eSRalf Baechle return 0; 752137f6f3eSRalf Baechle } 753137f6f3eSRalf Baechle 754137f6f3eSRalf Baechle arch_initcall(signal_setup); 755