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> 2440e084a5SRalf Baechle #include <linux/uprobes.h> 251da177e4SLinus Torvalds #include <linux/compiler.h> 26dbda6ac0SRalf Baechle #include <linux/syscalls.h> 27faea6234SAtsushi Nemoto #include <linux/uaccess.h> 28733e5e4bSDavid Howells #include <linux/tracehook.h> 291da177e4SLinus Torvalds 30e50c0a8fSRalf Baechle #include <asm/abi.h> 311da177e4SLinus Torvalds #include <asm/asm.h> 321da177e4SLinus Torvalds #include <linux/bitops.h> 331da177e4SLinus Torvalds #include <asm/cacheflush.h> 341da177e4SLinus Torvalds #include <asm/fpu.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> 39b81947c6SDavid Howells #include <asm/dsp.h> 4001be057bSDouglas Leung #include <asm/inst.h> 41bf82cb30SPaul Burton #include <asm/msa.h> 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds #include "signal-common.h" 441da177e4SLinus Torvalds 452db9ca0aSPaul Burton static int (*save_fp_context)(void __user *sc); 462db9ca0aSPaul Burton static int (*restore_fp_context)(void __user *sc); 47137f6f3eSRalf Baechle 4866680583SRalf Baechle struct sigframe { 4966680583SRalf Baechle u32 sf_ass[4]; /* argument save space for o32 */ 50d814c28cSDavid Daney u32 sf_pad[2]; /* Was: signal trampoline */ 51f1fe2d21SPaul Burton 52f1fe2d21SPaul Burton /* Matches struct ucontext from its uc_mcontext field onwards */ 5366680583SRalf Baechle struct sigcontext sf_sc; 5466680583SRalf Baechle sigset_t sf_mask; 55f1fe2d21SPaul Burton unsigned long long sf_extcontext[0]; 5666680583SRalf Baechle }; 5766680583SRalf Baechle 58c0b9bae9SFranck Bui-Huu struct rt_sigframe { 59c0b9bae9SFranck Bui-Huu u32 rs_ass[4]; /* argument save space for o32 */ 60d814c28cSDavid Daney u32 rs_pad[2]; /* Was: signal trampoline */ 61c0b9bae9SFranck Bui-Huu struct siginfo rs_info; 62c0b9bae9SFranck Bui-Huu struct ucontext rs_uc; 63c0b9bae9SFranck Bui-Huu }; 64c0b9bae9SFranck Bui-Huu 651da177e4SLinus Torvalds /* 66b2ead528SPaul Burton * Thread saved context copy to/from a signal context presumed to be on the 67b2ead528SPaul Burton * user stack, and therefore accessed with appropriate macros from uaccess.h. 68b2ead528SPaul Burton */ 692db9ca0aSPaul Burton static int copy_fp_to_sigcontext(void __user *sc) 70b2ead528SPaul Burton { 712db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 722db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 732db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 74b2ead528SPaul Burton int i; 75b2ead528SPaul Burton int err = 0; 766f0aba63SPaul Burton int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; 77b2ead528SPaul Burton 786f0aba63SPaul Burton for (i = 0; i < NUM_FPU_REGS; i += inc) { 79b2ead528SPaul Burton err |= 80b2ead528SPaul Burton __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), 812db9ca0aSPaul Burton &fpregs[i]); 82b2ead528SPaul Burton } 832db9ca0aSPaul Burton err |= __put_user(current->thread.fpu.fcr31, csr); 84b2ead528SPaul Burton 85b2ead528SPaul Burton return err; 86b2ead528SPaul Burton } 87b2ead528SPaul Burton 882db9ca0aSPaul Burton static int copy_fp_from_sigcontext(void __user *sc) 89b2ead528SPaul Burton { 902db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 912db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 922db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 93b2ead528SPaul Burton int i; 94b2ead528SPaul Burton int err = 0; 956f0aba63SPaul Burton int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; 96b2ead528SPaul Burton u64 fpr_val; 97b2ead528SPaul Burton 986f0aba63SPaul Burton for (i = 0; i < NUM_FPU_REGS; i += inc) { 992db9ca0aSPaul Burton err |= __get_user(fpr_val, &fpregs[i]); 100b2ead528SPaul Burton set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); 101b2ead528SPaul Burton } 1022db9ca0aSPaul Burton err |= __get_user(current->thread.fpu.fcr31, csr); 103b2ead528SPaul Burton 104b2ead528SPaul Burton return err; 105b2ead528SPaul Burton } 106b2ead528SPaul Burton 107b2ead528SPaul Burton /* 1082db9ca0aSPaul Burton * Wrappers for the assembly _{save,restore}_fp_context functions. 1092db9ca0aSPaul Burton */ 1102db9ca0aSPaul Burton static int save_hw_fp_context(void __user *sc) 1112db9ca0aSPaul Burton { 1122db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 1132db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 1142db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 1152db9ca0aSPaul Burton 1162db9ca0aSPaul Burton return _save_fp_context(fpregs, csr); 1172db9ca0aSPaul Burton } 1182db9ca0aSPaul Burton 1192db9ca0aSPaul Burton static int restore_hw_fp_context(void __user *sc) 1202db9ca0aSPaul Burton { 1212db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 1222db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 1232db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 1242db9ca0aSPaul Burton 1252db9ca0aSPaul Burton return _restore_fp_context(fpregs, csr); 1262db9ca0aSPaul Burton } 1272db9ca0aSPaul Burton 1282db9ca0aSPaul Burton /* 129bf82cb30SPaul Burton * Extended context handling. 130bf82cb30SPaul Burton */ 131bf82cb30SPaul Burton 132bf82cb30SPaul Burton static inline void __user *sc_to_extcontext(void __user *sc) 133bf82cb30SPaul Burton { 134bf82cb30SPaul Burton struct ucontext __user *uc; 135bf82cb30SPaul Burton 136bf82cb30SPaul Burton /* 137bf82cb30SPaul Burton * We can just pretend the sigcontext is always embedded in a struct 138bf82cb30SPaul Burton * ucontext here, because the offset from sigcontext to extended 139bf82cb30SPaul Burton * context is the same in the struct sigframe case. 140bf82cb30SPaul Burton */ 141bf82cb30SPaul Burton uc = container_of(sc, struct ucontext, uc_mcontext); 142bf82cb30SPaul Burton return &uc->uc_extcontext; 143bf82cb30SPaul Burton } 144bf82cb30SPaul Burton 145bf82cb30SPaul Burton static int save_msa_extcontext(void __user *buf) 146bf82cb30SPaul Burton { 147bf82cb30SPaul Burton struct msa_extcontext __user *msa = buf; 148bf82cb30SPaul Burton uint64_t val; 149bf82cb30SPaul Burton int i, err; 150bf82cb30SPaul Burton 151bf82cb30SPaul Burton if (!thread_msa_context_live()) 152bf82cb30SPaul Burton return 0; 153bf82cb30SPaul Burton 154bf82cb30SPaul Burton /* 155bf82cb30SPaul Burton * Ensure that we can't lose the live MSA context between checking 156bf82cb30SPaul Burton * for it & writing it to memory. 157bf82cb30SPaul Burton */ 158bf82cb30SPaul Burton preempt_disable(); 159bf82cb30SPaul Burton 160bf82cb30SPaul Burton if (is_msa_enabled()) { 161bf82cb30SPaul Burton /* 162bf82cb30SPaul Burton * There are no EVA versions of the vector register load/store 163bf82cb30SPaul Burton * instructions, so MSA context has to be saved to kernel memory 164bf82cb30SPaul Burton * and then copied to user memory. The save to kernel memory 165bf82cb30SPaul Burton * should already have been done when handling scalar FP 166bf82cb30SPaul Burton * context. 167bf82cb30SPaul Burton */ 168bf82cb30SPaul Burton BUG_ON(config_enabled(CONFIG_EVA)); 169bf82cb30SPaul Burton 170bf82cb30SPaul Burton err = __put_user(read_msa_csr(), &msa->csr); 171bf82cb30SPaul Burton err |= _save_msa_all_upper(&msa->wr); 172bf82cb30SPaul Burton 173bf82cb30SPaul Burton preempt_enable(); 174bf82cb30SPaul Burton } else { 175bf82cb30SPaul Burton preempt_enable(); 176bf82cb30SPaul Burton 177bf82cb30SPaul Burton err = __put_user(current->thread.fpu.msacsr, &msa->csr); 178bf82cb30SPaul Burton 179bf82cb30SPaul Burton for (i = 0; i < NUM_FPU_REGS; i++) { 180bf82cb30SPaul Burton val = get_fpr64(¤t->thread.fpu.fpr[i], 1); 181bf82cb30SPaul Burton err |= __put_user(val, &msa->wr[i]); 182bf82cb30SPaul Burton } 183bf82cb30SPaul Burton } 184bf82cb30SPaul Burton 185bf82cb30SPaul Burton err |= __put_user(MSA_EXTCONTEXT_MAGIC, &msa->ext.magic); 186bf82cb30SPaul Burton err |= __put_user(sizeof(*msa), &msa->ext.size); 187bf82cb30SPaul Burton 188bf82cb30SPaul Burton return err ? -EFAULT : sizeof(*msa); 189bf82cb30SPaul Burton } 190bf82cb30SPaul Burton 191bf82cb30SPaul Burton static int restore_msa_extcontext(void __user *buf, unsigned int size) 192bf82cb30SPaul Burton { 193bf82cb30SPaul Burton struct msa_extcontext __user *msa = buf; 194bf82cb30SPaul Burton unsigned long long val; 195bf82cb30SPaul Burton unsigned int csr; 196bf82cb30SPaul Burton int i, err; 197bf82cb30SPaul Burton 1986533af4dSPaul Burton if (!config_enabled(CONFIG_CPU_HAS_MSA)) 1996533af4dSPaul Burton return SIGSYS; 2006533af4dSPaul Burton 201bf82cb30SPaul Burton if (size != sizeof(*msa)) 202bf82cb30SPaul Burton return -EINVAL; 203bf82cb30SPaul Burton 204bf82cb30SPaul Burton err = get_user(csr, &msa->csr); 205bf82cb30SPaul Burton if (err) 206bf82cb30SPaul Burton return err; 207bf82cb30SPaul Burton 208bf82cb30SPaul Burton preempt_disable(); 209bf82cb30SPaul Burton 210bf82cb30SPaul Burton if (is_msa_enabled()) { 211bf82cb30SPaul Burton /* 212bf82cb30SPaul Burton * There are no EVA versions of the vector register load/store 213bf82cb30SPaul Burton * instructions, so MSA context has to be copied to kernel 214bf82cb30SPaul Burton * memory and later loaded to registers. The same is true of 215bf82cb30SPaul Burton * scalar FP context, so FPU & MSA should have already been 216bf82cb30SPaul Burton * disabled whilst handling scalar FP context. 217bf82cb30SPaul Burton */ 218bf82cb30SPaul Burton BUG_ON(config_enabled(CONFIG_EVA)); 219bf82cb30SPaul Burton 220bf82cb30SPaul Burton write_msa_csr(csr); 221bf82cb30SPaul Burton err |= _restore_msa_all_upper(&msa->wr); 222bf82cb30SPaul Burton preempt_enable(); 223bf82cb30SPaul Burton } else { 224bf82cb30SPaul Burton preempt_enable(); 225bf82cb30SPaul Burton 226bf82cb30SPaul Burton current->thread.fpu.msacsr = csr; 227bf82cb30SPaul Burton 228bf82cb30SPaul Burton for (i = 0; i < NUM_FPU_REGS; i++) { 229bf82cb30SPaul Burton err |= __get_user(val, &msa->wr[i]); 230bf82cb30SPaul Burton set_fpr64(¤t->thread.fpu.fpr[i], 1, val); 231bf82cb30SPaul Burton } 232bf82cb30SPaul Burton } 233bf82cb30SPaul Burton 234bf82cb30SPaul Burton return err; 235bf82cb30SPaul Burton } 236bf82cb30SPaul Burton 237bf82cb30SPaul Burton static int save_extcontext(void __user *buf) 238bf82cb30SPaul Burton { 239bf82cb30SPaul Burton int sz; 240bf82cb30SPaul Burton 241bf82cb30SPaul Burton sz = save_msa_extcontext(buf); 242bf82cb30SPaul Burton if (sz < 0) 243bf82cb30SPaul Burton return sz; 244bf82cb30SPaul Burton buf += sz; 245bf82cb30SPaul Burton 246bf82cb30SPaul Burton /* If no context was saved then trivially return */ 247bf82cb30SPaul Burton if (!sz) 248bf82cb30SPaul Burton return 0; 249bf82cb30SPaul Burton 250bf82cb30SPaul Burton /* Write the end marker */ 251bf82cb30SPaul Burton if (__put_user(END_EXTCONTEXT_MAGIC, (u32 *)buf)) 252bf82cb30SPaul Burton return -EFAULT; 253bf82cb30SPaul Burton 254bf82cb30SPaul Burton sz += sizeof(((struct extcontext *)NULL)->magic); 255bf82cb30SPaul Burton return sz; 256bf82cb30SPaul Burton } 257bf82cb30SPaul Burton 258bf82cb30SPaul Burton static int restore_extcontext(void __user *buf) 259bf82cb30SPaul Burton { 260bf82cb30SPaul Burton struct extcontext ext; 261bf82cb30SPaul Burton int err; 262bf82cb30SPaul Burton 263bf82cb30SPaul Burton while (1) { 264bf82cb30SPaul Burton err = __get_user(ext.magic, (unsigned int *)buf); 265bf82cb30SPaul Burton if (err) 266bf82cb30SPaul Burton return err; 267bf82cb30SPaul Burton 268bf82cb30SPaul Burton if (ext.magic == END_EXTCONTEXT_MAGIC) 269bf82cb30SPaul Burton return 0; 270bf82cb30SPaul Burton 271bf82cb30SPaul Burton err = __get_user(ext.size, (unsigned int *)(buf 272bf82cb30SPaul Burton + offsetof(struct extcontext, size))); 273bf82cb30SPaul Burton if (err) 274bf82cb30SPaul Burton return err; 275bf82cb30SPaul Burton 276bf82cb30SPaul Burton switch (ext.magic) { 277bf82cb30SPaul Burton case MSA_EXTCONTEXT_MAGIC: 278bf82cb30SPaul Burton err = restore_msa_extcontext(buf, ext.size); 279bf82cb30SPaul Burton break; 280bf82cb30SPaul Burton 281bf82cb30SPaul Burton default: 282bf82cb30SPaul Burton err = -EINVAL; 283bf82cb30SPaul Burton break; 284bf82cb30SPaul Burton } 285bf82cb30SPaul Burton 286bf82cb30SPaul Burton if (err) 287bf82cb30SPaul Burton return err; 288bf82cb30SPaul Burton 289bf82cb30SPaul Burton buf += ext.size; 290bf82cb30SPaul Burton } 291bf82cb30SPaul Burton } 292bf82cb30SPaul Burton 293bf82cb30SPaul Burton /* 294c3fc4ab3SFranck Bui-Huu * Helper routines 295c3fc4ab3SFranck Bui-Huu */ 296d02a40afSPaul Burton int protected_save_fp_context(void __user *sc) 297faea6234SAtsushi Nemoto { 2982db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 2992db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 3002db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 30164243c2aSPaul Burton uint32_t __user *used_math = sc + abi->off_sc_used_math; 302bf82cb30SPaul Burton unsigned int used, ext_sz; 303faea6234SAtsushi Nemoto int err; 304689ee856SPaul Burton 3050d071fa3SPaul Burton used = used_math() ? USED_FP : 0; 306bf82cb30SPaul Burton if (!used) 307bf82cb30SPaul Burton goto fp_done; 308bf82cb30SPaul Burton 3090d071fa3SPaul Burton if (!test_thread_flag(TIF_32BIT_FPREGS)) 3100d071fa3SPaul Burton used |= USED_FR1; 3110d071fa3SPaul Burton if (test_thread_flag(TIF_HYBRID_FPREGS)) 3120d071fa3SPaul Burton used |= USED_HYBRID_FPRS; 31364243c2aSPaul Burton 314689ee856SPaul Burton /* 315689ee856SPaul Burton * EVA does not have userland equivalents of ldc1 or sdc1, so 316689ee856SPaul Burton * save to the kernel FP context & copy that to userland below. 317689ee856SPaul Burton */ 318689ee856SPaul Burton if (config_enabled(CONFIG_EVA)) 319689ee856SPaul Burton lose_fpu(1); 320689ee856SPaul Burton 321faea6234SAtsushi Nemoto while (1) { 322faea6234SAtsushi Nemoto lock_fpu_owner(); 323ff3aa5f2SPaul Burton if (is_fpu_owner()) { 324ff3aa5f2SPaul Burton err = save_fp_context(sc); 325faea6234SAtsushi Nemoto unlock_fpu_owner(); 326ff3aa5f2SPaul Burton } else { 327ff3aa5f2SPaul Burton unlock_fpu_owner(); 328ff3aa5f2SPaul Burton err = copy_fp_to_sigcontext(sc); 329ff3aa5f2SPaul Burton } 330faea6234SAtsushi Nemoto if (likely(!err)) 331faea6234SAtsushi Nemoto break; 332faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 3332db9ca0aSPaul Burton err = __put_user(0, &fpregs[0]) | 3342db9ca0aSPaul Burton __put_user(0, &fpregs[31]) | 3352db9ca0aSPaul Burton __put_user(0, csr); 336faea6234SAtsushi Nemoto if (err) 337bf82cb30SPaul Burton return err; /* really bad sigcontext */ 338faea6234SAtsushi Nemoto } 339689ee856SPaul Burton 340bf82cb30SPaul Burton fp_done: 341bf82cb30SPaul Burton ext_sz = err = save_extcontext(sc_to_extcontext(sc)); 342bf82cb30SPaul Burton if (err < 0) 343faea6234SAtsushi Nemoto return err; 344bf82cb30SPaul Burton used |= ext_sz ? USED_EXTCONTEXT : 0; 345bf82cb30SPaul Burton 346bf82cb30SPaul Burton return __put_user(used, used_math); 347faea6234SAtsushi Nemoto } 348faea6234SAtsushi Nemoto 349d02a40afSPaul Burton int protected_restore_fp_context(void __user *sc) 350faea6234SAtsushi Nemoto { 3512db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 3522db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 3532db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 35464243c2aSPaul Burton uint32_t __user *used_math = sc + abi->off_sc_used_math; 35564243c2aSPaul Burton unsigned int used; 356bf82cb30SPaul Burton int err, sig = 0, tmp __maybe_unused; 35764243c2aSPaul Burton 35864243c2aSPaul Burton err = __get_user(used, used_math); 3590d071fa3SPaul Burton conditional_used_math(used & USED_FP); 36064243c2aSPaul Burton 36164243c2aSPaul Burton /* 36264243c2aSPaul Burton * The signal handler may have used FPU; give it up if the program 36364243c2aSPaul Burton * doesn't want it following sigreturn. 36464243c2aSPaul Burton */ 365bf82cb30SPaul Burton if (err || !(used & USED_FP)) 36664243c2aSPaul Burton lose_fpu(0); 367bf82cb30SPaul Burton if (err) 36864243c2aSPaul Burton return err; 369bf82cb30SPaul Burton if (!(used & USED_FP)) 370bf82cb30SPaul Burton goto fp_done; 37164243c2aSPaul Burton 37264243c2aSPaul Burton err = sig = fpcsr_pending(csr); 37364243c2aSPaul Burton if (err < 0) 37464243c2aSPaul Burton return err; 375689ee856SPaul Burton 376689ee856SPaul Burton /* 377689ee856SPaul Burton * EVA does not have userland equivalents of ldc1 or sdc1, so we 378689ee856SPaul Burton * disable the FPU here such that the code below simply copies to 379689ee856SPaul Burton * the kernel FP context. 380689ee856SPaul Burton */ 381689ee856SPaul Burton if (config_enabled(CONFIG_EVA)) 382689ee856SPaul Burton lose_fpu(0); 383689ee856SPaul Burton 384faea6234SAtsushi Nemoto while (1) { 385faea6234SAtsushi Nemoto lock_fpu_owner(); 386ff3aa5f2SPaul Burton if (is_fpu_owner()) { 387ff3aa5f2SPaul Burton err = restore_fp_context(sc); 388faea6234SAtsushi Nemoto unlock_fpu_owner(); 389ff3aa5f2SPaul Burton } else { 390ff3aa5f2SPaul Burton unlock_fpu_owner(); 391ff3aa5f2SPaul Burton err = copy_fp_from_sigcontext(sc); 392ff3aa5f2SPaul Burton } 393faea6234SAtsushi Nemoto if (likely(!err)) 394faea6234SAtsushi Nemoto break; 395faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 3962db9ca0aSPaul Burton err = __get_user(tmp, &fpregs[0]) | 3972db9ca0aSPaul Burton __get_user(tmp, &fpregs[31]) | 3982db9ca0aSPaul Burton __get_user(tmp, csr); 399faea6234SAtsushi Nemoto if (err) 400faea6234SAtsushi Nemoto break; /* really bad sigcontext */ 401faea6234SAtsushi Nemoto } 402689ee856SPaul Burton 403bf82cb30SPaul Burton fp_done: 4046533af4dSPaul Burton if (!err && (used & USED_EXTCONTEXT)) 4056533af4dSPaul Burton err = restore_extcontext(sc_to_extcontext(sc)); 406bf82cb30SPaul Burton 40764243c2aSPaul Burton return err ?: sig; 408faea6234SAtsushi Nemoto } 409faea6234SAtsushi Nemoto 410c3fc4ab3SFranck Bui-Huu int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 411c3fc4ab3SFranck Bui-Huu { 412c3fc4ab3SFranck Bui-Huu int err = 0; 413c3fc4ab3SFranck Bui-Huu int i; 414c3fc4ab3SFranck Bui-Huu 415c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->cp0_epc, &sc->sc_pc); 416c3fc4ab3SFranck Bui-Huu 417c3fc4ab3SFranck Bui-Huu err |= __put_user(0, &sc->sc_regs[0]); 418c3fc4ab3SFranck Bui-Huu for (i = 1; i < 32; i++) 419c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->regs[i], &sc->sc_regs[i]); 420c3fc4ab3SFranck Bui-Huu 4219693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS 4229693a853SFranck Bui-Huu err |= __put_user(regs->acx, &sc->sc_acx); 4239693a853SFranck Bui-Huu #endif 424c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->hi, &sc->sc_mdhi); 425c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->lo, &sc->sc_mdlo); 426c3fc4ab3SFranck Bui-Huu if (cpu_has_dsp) { 427c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi1(), &sc->sc_hi1); 428c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo1(), &sc->sc_lo1); 429c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi2(), &sc->sc_hi2); 430c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo2(), &sc->sc_lo2); 431c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi3(), &sc->sc_hi3); 432c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo3(), &sc->sc_lo3); 433c3fc4ab3SFranck Bui-Huu err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 434c3fc4ab3SFranck Bui-Huu } 435c3fc4ab3SFranck Bui-Huu 436c3fc4ab3SFranck Bui-Huu 437c3fc4ab3SFranck Bui-Huu /* 438c3fc4ab3SFranck Bui-Huu * Save FPU state to signal context. Signal handler 439c3fc4ab3SFranck Bui-Huu * will "inherit" current FPU state. 440c3fc4ab3SFranck Bui-Huu */ 44116f77de8SPaul Burton err |= protected_save_fp_context(sc); 44264243c2aSPaul Burton 443c3fc4ab3SFranck Bui-Huu return err; 444c3fc4ab3SFranck Bui-Huu } 445c3fc4ab3SFranck Bui-Huu 446bf82cb30SPaul Burton static size_t extcontext_max_size(void) 447bf82cb30SPaul Burton { 448bf82cb30SPaul Burton size_t sz = 0; 449bf82cb30SPaul Burton 450bf82cb30SPaul Burton /* 451bf82cb30SPaul Burton * The assumption here is that between this point & the point at which 452bf82cb30SPaul Burton * the extended context is saved the size of the context should only 453bf82cb30SPaul Burton * ever be able to shrink (if the task is preempted), but never grow. 454bf82cb30SPaul Burton * That is, what this function returns is an upper bound on the size of 455bf82cb30SPaul Burton * the extended context for the current task at the current time. 456bf82cb30SPaul Burton */ 457bf82cb30SPaul Burton 458bf82cb30SPaul Burton if (thread_msa_context_live()) 459bf82cb30SPaul Burton sz += sizeof(struct msa_extcontext); 460bf82cb30SPaul Burton 461bf82cb30SPaul Burton /* If any context is saved then we'll append the end marker */ 462bf82cb30SPaul Burton if (sz) 463bf82cb30SPaul Burton sz += sizeof(((struct extcontext *)NULL)->magic); 464bf82cb30SPaul Burton 465bf82cb30SPaul Burton return sz; 466bf82cb30SPaul Burton } 467bf82cb30SPaul Burton 468c6a2f467SAtsushi Nemoto int fpcsr_pending(unsigned int __user *fpcsr) 469c6a2f467SAtsushi Nemoto { 470c6a2f467SAtsushi Nemoto int err, sig = 0; 471c6a2f467SAtsushi Nemoto unsigned int csr, enabled; 472c6a2f467SAtsushi Nemoto 473c6a2f467SAtsushi Nemoto err = __get_user(csr, fpcsr); 474c6a2f467SAtsushi Nemoto enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); 475c6a2f467SAtsushi Nemoto /* 476c6a2f467SAtsushi Nemoto * If the signal handler set some FPU exceptions, clear it and 477c6a2f467SAtsushi Nemoto * send SIGFPE. 478c6a2f467SAtsushi Nemoto */ 479c6a2f467SAtsushi Nemoto if (csr & enabled) { 480c6a2f467SAtsushi Nemoto csr &= ~enabled; 481c6a2f467SAtsushi Nemoto err |= __put_user(csr, fpcsr); 482c6a2f467SAtsushi Nemoto sig = SIGFPE; 483c6a2f467SAtsushi Nemoto } 484c6a2f467SAtsushi Nemoto return err ?: sig; 485c6a2f467SAtsushi Nemoto } 486c6a2f467SAtsushi Nemoto 487c3fc4ab3SFranck Bui-Huu int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 488c3fc4ab3SFranck Bui-Huu { 489c3fc4ab3SFranck Bui-Huu unsigned long treg; 490c3fc4ab3SFranck Bui-Huu int err = 0; 491c3fc4ab3SFranck Bui-Huu int i; 492c3fc4ab3SFranck Bui-Huu 493c3fc4ab3SFranck Bui-Huu /* Always make any pending restarted system calls return -EINTR */ 494f56141e3SAndy Lutomirski current->restart_block.fn = do_no_restart_syscall; 495c3fc4ab3SFranck Bui-Huu 496c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->cp0_epc, &sc->sc_pc); 4979693a853SFranck Bui-Huu 4989693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS 4999693a853SFranck Bui-Huu err |= __get_user(regs->acx, &sc->sc_acx); 5009693a853SFranck Bui-Huu #endif 501c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->hi, &sc->sc_mdhi); 502c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->lo, &sc->sc_mdlo); 503c3fc4ab3SFranck Bui-Huu if (cpu_has_dsp) { 504c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); 505c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); 506c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); 507c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); 508c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); 509c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); 510c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); 511c3fc4ab3SFranck Bui-Huu } 512c3fc4ab3SFranck Bui-Huu 513c3fc4ab3SFranck Bui-Huu for (i = 1; i < 32; i++) 514c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->regs[i], &sc->sc_regs[i]); 515c3fc4ab3SFranck Bui-Huu 51664243c2aSPaul Burton return err ?: protected_restore_fp_context(sc); 517c3fc4ab3SFranck Bui-Huu } 518c3fc4ab3SFranck Bui-Huu 5197c4f5635SRichard Weinberger void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, 520c3fc4ab3SFranck Bui-Huu size_t frame_size) 521c3fc4ab3SFranck Bui-Huu { 522c3fc4ab3SFranck Bui-Huu unsigned long sp; 523c3fc4ab3SFranck Bui-Huu 524bf82cb30SPaul Burton /* Leave space for potential extended context */ 525bf82cb30SPaul Burton frame_size += extcontext_max_size(); 526bf82cb30SPaul Burton 527c3fc4ab3SFranck Bui-Huu /* Default to using normal stack */ 528c3fc4ab3SFranck Bui-Huu sp = regs->regs[29]; 529c3fc4ab3SFranck Bui-Huu 530c3fc4ab3SFranck Bui-Huu /* 531c3fc4ab3SFranck Bui-Huu * FPU emulator may have it's own trampoline active just 532c3fc4ab3SFranck Bui-Huu * above the user stack, 16-bytes before the next lowest 533c3fc4ab3SFranck Bui-Huu * 16 byte boundary. Try to avoid trashing it. 534c3fc4ab3SFranck Bui-Huu */ 535c3fc4ab3SFranck Bui-Huu sp -= 32; 536c3fc4ab3SFranck Bui-Huu 5377c4f5635SRichard Weinberger sp = sigsp(sp, ksig); 538c3fc4ab3SFranck Bui-Huu 539c3fc4ab3SFranck Bui-Huu return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); 540c3fc4ab3SFranck Bui-Huu } 541c3fc4ab3SFranck Bui-Huu 542c3fc4ab3SFranck Bui-Huu /* 5431da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 5441da177e4SLinus Torvalds */ 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 5471910f4abSAl Viro SYSCALL_DEFINE1(sigsuspend, sigset_t __user *, uset) 5481da177e4SLinus Torvalds { 5491910f4abSAl Viro return sys_rt_sigsuspend(uset, sizeof(sigset_t)); 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds #endif 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 554dbda6ac0SRalf Baechle SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, 555dbda6ac0SRalf Baechle struct sigaction __user *, oact) 5561da177e4SLinus Torvalds { 5571da177e4SLinus Torvalds struct k_sigaction new_ka, old_ka; 5581da177e4SLinus Torvalds int ret; 5591da177e4SLinus Torvalds int err = 0; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds if (act) { 5621da177e4SLinus Torvalds old_sigset_t mask; 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, act, sizeof(*act))) 5651da177e4SLinus Torvalds return -EFAULT; 5661da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); 5671da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 5681da177e4SLinus Torvalds err |= __get_user(mask, &act->sa_mask.sig[0]); 5691da177e4SLinus Torvalds if (err) 5701da177e4SLinus Torvalds return -EFAULT; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds siginitset(&new_ka.sa.sa_mask, mask); 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds if (!ret && oact) { 5781da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 5791da177e4SLinus Torvalds return -EFAULT; 5801da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 5811da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); 5821da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 5831da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[1]); 5841da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[2]); 5851da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[3]); 5861da177e4SLinus Torvalds if (err) 5871da177e4SLinus Torvalds return -EFAULT; 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds return ret; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds #endif 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 595f90080a0SFranck Bui-Huu asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) 5961da177e4SLinus Torvalds { 5979bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 5981da177e4SLinus Torvalds sigset_t blocked; 599c6a2f467SAtsushi Nemoto int sig; 6001da177e4SLinus Torvalds 6019bbf28a3SAtsushi Nemoto frame = (struct sigframe __user *) regs.regs[29]; 6021da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 6031da177e4SLinus Torvalds goto badframe; 6041da177e4SLinus Torvalds if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) 6051da177e4SLinus Torvalds goto badframe; 6061da177e4SLinus Torvalds 6078598f3cdSMatt Fleming set_current_blocked(&blocked); 6081da177e4SLinus Torvalds 609c6a2f467SAtsushi Nemoto sig = restore_sigcontext(®s, &frame->sf_sc); 610c6a2f467SAtsushi Nemoto if (sig < 0) 6111da177e4SLinus Torvalds goto badframe; 612c6a2f467SAtsushi Nemoto else if (sig) 613c6a2f467SAtsushi Nemoto force_sig(sig, current); 6141da177e4SLinus Torvalds 6151da177e4SLinus Torvalds /* 6161da177e4SLinus Torvalds * Don't let your children do this ... 6171da177e4SLinus Torvalds */ 6181da177e4SLinus Torvalds __asm__ __volatile__( 6191da177e4SLinus Torvalds "move\t$29, %0\n\t" 6201da177e4SLinus Torvalds "j\tsyscall_exit" 6211da177e4SLinus Torvalds :/* no outputs */ 6221da177e4SLinus Torvalds :"r" (®s)); 6231da177e4SLinus Torvalds /* Unreached */ 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds badframe: 6261da177e4SLinus Torvalds force_sig(SIGSEGV, current); 6271da177e4SLinus Torvalds } 628e50c0a8fSRalf Baechle #endif /* CONFIG_TRAD_SIGNALS */ 6291da177e4SLinus Torvalds 630f90080a0SFranck Bui-Huu asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) 6311da177e4SLinus Torvalds { 6329bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 6331da177e4SLinus Torvalds sigset_t set; 634c6a2f467SAtsushi Nemoto int sig; 6351da177e4SLinus Torvalds 6369bbf28a3SAtsushi Nemoto frame = (struct rt_sigframe __user *) regs.regs[29]; 6371da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 6381da177e4SLinus Torvalds goto badframe; 6391da177e4SLinus Torvalds if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 6401da177e4SLinus Torvalds goto badframe; 6411da177e4SLinus Torvalds 6428598f3cdSMatt Fleming set_current_blocked(&set); 6431da177e4SLinus Torvalds 644c6a2f467SAtsushi Nemoto sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); 645c6a2f467SAtsushi Nemoto if (sig < 0) 6461da177e4SLinus Torvalds goto badframe; 647c6a2f467SAtsushi Nemoto else if (sig) 648c6a2f467SAtsushi Nemoto force_sig(sig, current); 6491da177e4SLinus Torvalds 650ea536ad4SAl Viro if (restore_altstack(&frame->rs_uc.uc_stack)) 651ea536ad4SAl Viro goto badframe; 6521da177e4SLinus Torvalds 6531da177e4SLinus Torvalds /* 6541da177e4SLinus Torvalds * Don't let your children do this ... 6551da177e4SLinus Torvalds */ 6561da177e4SLinus Torvalds __asm__ __volatile__( 6571da177e4SLinus Torvalds "move\t$29, %0\n\t" 6581da177e4SLinus Torvalds "j\tsyscall_exit" 6591da177e4SLinus Torvalds :/* no outputs */ 6601da177e4SLinus Torvalds :"r" (®s)); 6611da177e4SLinus Torvalds /* Unreached */ 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds badframe: 6641da177e4SLinus Torvalds force_sig(SIGSEGV, current); 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 66881d103bfSRichard Weinberger static int setup_frame(void *sig_return, struct ksignal *ksig, 66981d103bfSRichard Weinberger struct pt_regs *regs, sigset_t *set) 6701da177e4SLinus Torvalds { 6719bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 6721da177e4SLinus Torvalds int err = 0; 6731da177e4SLinus Torvalds 6747c4f5635SRichard Weinberger frame = get_sigframe(ksig, regs, sizeof(*frame)); 6751da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 67681d103bfSRichard Weinberger return -EFAULT; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->sf_sc); 6791da177e4SLinus Torvalds err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 6801da177e4SLinus Torvalds if (err) 68181d103bfSRichard Weinberger return -EFAULT; 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds /* 6841da177e4SLinus Torvalds * Arguments to signal handler: 6851da177e4SLinus Torvalds * 6861da177e4SLinus Torvalds * a0 = signal number 6871da177e4SLinus Torvalds * a1 = 0 (should be cause) 6881da177e4SLinus Torvalds * a2 = pointer to struct sigcontext 6891da177e4SLinus Torvalds * 6901da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to the 6911da177e4SLinus Torvalds * struct sigframe. 6921da177e4SLinus Torvalds */ 69381d103bfSRichard Weinberger regs->regs[ 4] = ksig->sig; 6941da177e4SLinus Torvalds regs->regs[ 5] = 0; 6951da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->sf_sc; 6961da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 697d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 69881d103bfSRichard Weinberger regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; 6991da177e4SLinus Torvalds 700722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 7011da177e4SLinus Torvalds current->comm, current->pid, 702722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 7037b3e2fc8SRalf Baechle return 0; 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds #endif 7061da177e4SLinus Torvalds 70781d103bfSRichard Weinberger static int setup_rt_frame(void *sig_return, struct ksignal *ksig, 70881d103bfSRichard Weinberger struct pt_regs *regs, sigset_t *set) 7091da177e4SLinus Torvalds { 7109bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 7111da177e4SLinus Torvalds int err = 0; 7121da177e4SLinus Torvalds 7137c4f5635SRichard Weinberger frame = get_sigframe(ksig, regs, sizeof(*frame)); 7141da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 71581d103bfSRichard Weinberger return -EFAULT; 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds /* Create siginfo. */ 71881d103bfSRichard Weinberger err |= copy_siginfo_to_user(&frame->rs_info, &ksig->info); 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds /* Create the ucontext. */ 7211da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 7225665a0acSAtsushi Nemoto err |= __put_user(NULL, &frame->rs_uc.uc_link); 723ea536ad4SAl Viro err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); 7241da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 7251da177e4SLinus Torvalds err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds if (err) 72881d103bfSRichard Weinberger return -EFAULT; 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds /* 7311da177e4SLinus Torvalds * Arguments to signal handler: 7321da177e4SLinus Torvalds * 7331da177e4SLinus Torvalds * a0 = signal number 7341da177e4SLinus Torvalds * a1 = 0 (should be cause) 7351da177e4SLinus Torvalds * a2 = pointer to ucontext 7361da177e4SLinus Torvalds * 7371da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 7381da177e4SLinus Torvalds * the struct rt_sigframe. 7391da177e4SLinus Torvalds */ 74081d103bfSRichard Weinberger regs->regs[ 4] = ksig->sig; 7411da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 7421da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 7431da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 744d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 74581d103bfSRichard Weinberger regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; 7461da177e4SLinus Torvalds 747722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 7481da177e4SLinus Torvalds current->comm, current->pid, 7491da177e4SLinus Torvalds frame, regs->cp0_epc, regs->regs[31]); 750722bb63dSFranck Bui-Huu 7517b3e2fc8SRalf Baechle return 0; 7521da177e4SLinus Torvalds } 7531da177e4SLinus Torvalds 754151fd6acSRalf Baechle struct mips_abi mips_abi = { 755151fd6acSRalf Baechle #ifdef CONFIG_TRAD_SIGNALS 756151fd6acSRalf Baechle .setup_frame = setup_frame, 757151fd6acSRalf Baechle #endif 758151fd6acSRalf Baechle .setup_rt_frame = setup_rt_frame, 75977856100SPaul Burton .restart = __NR_restart_syscall, 76077856100SPaul Burton 76177856100SPaul Burton .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), 76277856100SPaul Burton .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), 76377856100SPaul Burton .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), 764ebb5e78cSAlex Smith 765ebb5e78cSAlex Smith .vdso = &vdso_image, 766151fd6acSRalf Baechle }; 767151fd6acSRalf Baechle 76881d103bfSRichard Weinberger static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) 7691da177e4SLinus Torvalds { 770b7f9a11aSAl Viro sigset_t *oldset = sigmask_to_save(); 771129bc8f7SRalf Baechle int ret; 772d814c28cSDavid Daney struct mips_abi *abi = current->thread.abi; 77301be057bSDouglas Leung #ifdef CONFIG_CPU_MICROMIPS 77401be057bSDouglas Leung void *vdso; 7752fabc7d2SMaciej W. Rozycki unsigned long tmp = (unsigned long)current->mm->context.vdso; 77601be057bSDouglas Leung 77701be057bSDouglas Leung set_isa16_mode(tmp); 77801be057bSDouglas Leung vdso = (void *)tmp; 77901be057bSDouglas Leung #else 780d814c28cSDavid Daney void *vdso = current->mm->context.vdso; 78101be057bSDouglas Leung #endif 782129bc8f7SRalf Baechle 7838f5a00ebSAl Viro if (regs->regs[0]) { 7848f5a00ebSAl Viro switch(regs->regs[2]) { 7851da177e4SLinus Torvalds case ERESTART_RESTARTBLOCK: 7861da177e4SLinus Torvalds case ERESTARTNOHAND: 7871da177e4SLinus Torvalds regs->regs[2] = EINTR; 7881da177e4SLinus Torvalds break; 7891da177e4SLinus Torvalds case ERESTARTSYS: 79081d103bfSRichard Weinberger if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { 7911da177e4SLinus Torvalds regs->regs[2] = EINTR; 7921da177e4SLinus Torvalds break; 7931da177e4SLinus Torvalds } 7941da177e4SLinus Torvalds /* fallthrough */ 7958f5a00ebSAl Viro case ERESTARTNOINTR: 7961da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 7978f5a00ebSAl Viro regs->regs[2] = regs->regs[0]; 7988f5a00ebSAl Viro regs->cp0_epc -= 4; 7991da177e4SLinus Torvalds } 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds regs->regs[0] = 0; /* Don't deal with this again. */ 8028f5a00ebSAl Viro } 8031da177e4SLinus Torvalds 8047939469dSLeonid Yegoshin if (sig_uses_siginfo(&ksig->ka, abi)) 805ebb5e78cSAlex Smith ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn, 80681d103bfSRichard Weinberger ksig, regs, oldset); 8071da177e4SLinus Torvalds else 808ebb5e78cSAlex Smith ret = abi->setup_frame(vdso + abi->vdso->off_sigreturn, 809ebb5e78cSAlex Smith ksig, regs, oldset); 8101da177e4SLinus Torvalds 81181d103bfSRichard Weinberger signal_setup_done(ret, ksig, 0); 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds 814151fd6acSRalf Baechle static void do_signal(struct pt_regs *regs) 8151da177e4SLinus Torvalds { 81681d103bfSRichard Weinberger struct ksignal ksig; 8171da177e4SLinus Torvalds 81881d103bfSRichard Weinberger if (get_signal(&ksig)) { 8197b3e2fc8SRalf Baechle /* Whee! Actually deliver the signal. */ 82081d103bfSRichard Weinberger handle_signal(&ksig, regs); 82145887e12SRalf Baechle return; 8227b3e2fc8SRalf Baechle } 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds if (regs->regs[0]) { 8259ec9b5acSRalf Baechle switch (regs->regs[2]) { 8269ec9b5acSRalf Baechle case ERESTARTNOHAND: 8279ec9b5acSRalf Baechle case ERESTARTSYS: 8289ec9b5acSRalf Baechle case ERESTARTNOINTR: 8298f5a00ebSAl Viro regs->regs[2] = regs->regs[0]; 8301da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 8318f5a00ebSAl Viro regs->cp0_epc -= 4; 8329ec9b5acSRalf Baechle break; 8339ec9b5acSRalf Baechle 8349ec9b5acSRalf Baechle case ERESTART_RESTARTBLOCK: 835151fd6acSRalf Baechle regs->regs[2] = current->thread.abi->restart; 8361da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 8371da177e4SLinus Torvalds regs->cp0_epc -= 4; 8389ec9b5acSRalf Baechle break; 8391da177e4SLinus Torvalds } 84013fdd31aSRalf Baechle regs->regs[0] = 0; /* Don't deal with this again. */ 8411da177e4SLinus Torvalds } 8427b3e2fc8SRalf Baechle 8437b3e2fc8SRalf Baechle /* 8447b3e2fc8SRalf Baechle * If there's no signal to deliver, we just put the saved sigmask 8457b3e2fc8SRalf Baechle * back 8467b3e2fc8SRalf Baechle */ 84751a7b448SAl Viro restore_saved_sigmask(); 8481da177e4SLinus Torvalds } 8491da177e4SLinus Torvalds 8501da177e4SLinus Torvalds /* 8511da177e4SLinus Torvalds * notification of userspace execution resumption 8527b3e2fc8SRalf Baechle * - triggered by the TIF_WORK_MASK flags 8531da177e4SLinus Torvalds */ 8547b3e2fc8SRalf Baechle asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, 8551da177e4SLinus Torvalds __u32 thread_info_flags) 8561da177e4SLinus Torvalds { 8571f717929SRalf Baechle local_irq_enable(); 8581f717929SRalf Baechle 859c3fc5cd5SRalf Baechle user_exit(); 860c3fc5cd5SRalf Baechle 86140e084a5SRalf Baechle if (thread_info_flags & _TIF_UPROBE) 86240e084a5SRalf Baechle uprobe_notify_resume(regs); 86340e084a5SRalf Baechle 8641da177e4SLinus Torvalds /* deal with pending signal delivery */ 8656fd84c08SAl Viro if (thread_info_flags & _TIF_SIGPENDING) 866151fd6acSRalf Baechle do_signal(regs); 867d0420c83SDavid Howells 868d0420c83SDavid Howells if (thread_info_flags & _TIF_NOTIFY_RESUME) { 869d0420c83SDavid Howells clear_thread_flag(TIF_NOTIFY_RESUME); 870d0420c83SDavid Howells tracehook_notify_resume(regs); 871d0420c83SDavid Howells } 872c3fc5cd5SRalf Baechle 873c3fc5cd5SRalf Baechle user_enter(); 8741da177e4SLinus Torvalds } 875137f6f3eSRalf Baechle 876137f6f3eSRalf Baechle #ifdef CONFIG_SMP 8772db9ca0aSPaul Burton static int smp_save_fp_context(void __user *sc) 878137f6f3eSRalf Baechle { 879137f6f3eSRalf Baechle return raw_cpu_has_fpu 8802db9ca0aSPaul Burton ? save_hw_fp_context(sc) 881b2ead528SPaul Burton : copy_fp_to_sigcontext(sc); 882137f6f3eSRalf Baechle } 883137f6f3eSRalf Baechle 8842db9ca0aSPaul Burton static int smp_restore_fp_context(void __user *sc) 885137f6f3eSRalf Baechle { 886137f6f3eSRalf Baechle return raw_cpu_has_fpu 8872db9ca0aSPaul Burton ? restore_hw_fp_context(sc) 888b2ead528SPaul Burton : copy_fp_from_sigcontext(sc); 889137f6f3eSRalf Baechle } 890137f6f3eSRalf Baechle #endif 891137f6f3eSRalf Baechle 892137f6f3eSRalf Baechle static int signal_setup(void) 893137f6f3eSRalf Baechle { 894f1fe2d21SPaul Burton /* 895f1fe2d21SPaul Burton * The offset from sigcontext to extended context should be the same 896f1fe2d21SPaul Burton * regardless of the type of signal, such that userland can always know 897f1fe2d21SPaul Burton * where to look if it wishes to find the extended context structures. 898f1fe2d21SPaul Burton */ 899f1fe2d21SPaul Burton BUILD_BUG_ON((offsetof(struct sigframe, sf_extcontext) - 900f1fe2d21SPaul Burton offsetof(struct sigframe, sf_sc)) != 901f1fe2d21SPaul Burton (offsetof(struct rt_sigframe, rs_uc.uc_extcontext) - 902f1fe2d21SPaul Burton offsetof(struct rt_sigframe, rs_uc.uc_mcontext))); 903f1fe2d21SPaul Burton 904137f6f3eSRalf Baechle #ifdef CONFIG_SMP 905137f6f3eSRalf Baechle /* For now just do the cpu_has_fpu check when the functions are invoked */ 906137f6f3eSRalf Baechle save_fp_context = smp_save_fp_context; 907137f6f3eSRalf Baechle restore_fp_context = smp_restore_fp_context; 908137f6f3eSRalf Baechle #else 909137f6f3eSRalf Baechle if (cpu_has_fpu) { 9102db9ca0aSPaul Burton save_fp_context = save_hw_fp_context; 9112db9ca0aSPaul Burton restore_fp_context = restore_hw_fp_context; 912137f6f3eSRalf Baechle } else { 91314fa12dfSPaul Burton save_fp_context = copy_fp_to_sigcontext; 91414fa12dfSPaul Burton restore_fp_context = copy_fp_from_sigcontext; 915137f6f3eSRalf Baechle } 916ca750649SLeonid Yegoshin #endif /* CONFIG_SMP */ 917137f6f3eSRalf Baechle 918137f6f3eSRalf Baechle return 0; 919137f6f3eSRalf Baechle } 920137f6f3eSRalf Baechle 921137f6f3eSRalf Baechle arch_initcall(signal_setup); 922