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; 55c4ad6ea9SGustavo A. R. Silva unsigned long long sf_extcontext[]; 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 654eec81d7SPaul Burton #ifdef CONFIG_MIPS_FP_SUPPORT 664eec81d7SPaul Burton 671da177e4SLinus Torvalds /* 68b2ead528SPaul Burton * Thread saved context copy to/from a signal context presumed to be on the 69b2ead528SPaul Burton * user stack, and therefore accessed with appropriate macros from uaccess.h. 70b2ead528SPaul Burton */ 712db9ca0aSPaul Burton static int copy_fp_to_sigcontext(void __user *sc) 72b2ead528SPaul Burton { 732db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 742db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 752db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 76b2ead528SPaul Burton int i; 77b2ead528SPaul Burton int err = 0; 786f0aba63SPaul Burton int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; 79b2ead528SPaul Burton 806f0aba63SPaul Burton for (i = 0; i < NUM_FPU_REGS; i += inc) { 81b2ead528SPaul Burton err |= 82b2ead528SPaul Burton __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), 832db9ca0aSPaul Burton &fpregs[i]); 84b2ead528SPaul Burton } 852db9ca0aSPaul Burton err |= __put_user(current->thread.fpu.fcr31, csr); 86b2ead528SPaul Burton 87b2ead528SPaul Burton return err; 88b2ead528SPaul Burton } 89b2ead528SPaul Burton 902db9ca0aSPaul Burton static int copy_fp_from_sigcontext(void __user *sc) 91b2ead528SPaul Burton { 922db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 932db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 942db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 95b2ead528SPaul Burton int i; 96b2ead528SPaul Burton int err = 0; 976f0aba63SPaul Burton int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; 98b2ead528SPaul Burton u64 fpr_val; 99b2ead528SPaul Burton 1006f0aba63SPaul Burton for (i = 0; i < NUM_FPU_REGS; i += inc) { 1012db9ca0aSPaul Burton err |= __get_user(fpr_val, &fpregs[i]); 102b2ead528SPaul Burton set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); 103b2ead528SPaul Burton } 1042db9ca0aSPaul Burton err |= __get_user(current->thread.fpu.fcr31, csr); 105b2ead528SPaul Burton 106b2ead528SPaul Burton return err; 107b2ead528SPaul Burton } 108b2ead528SPaul Burton 1094eec81d7SPaul Burton #else /* !CONFIG_MIPS_FP_SUPPORT */ 1104eec81d7SPaul Burton 1114eec81d7SPaul Burton static int copy_fp_to_sigcontext(void __user *sc) 1124eec81d7SPaul Burton { 1134eec81d7SPaul Burton return 0; 1144eec81d7SPaul Burton } 1154eec81d7SPaul Burton 1164eec81d7SPaul Burton static int copy_fp_from_sigcontext(void __user *sc) 1174eec81d7SPaul Burton { 1184eec81d7SPaul Burton return 0; 1194eec81d7SPaul Burton } 1204eec81d7SPaul Burton 1214eec81d7SPaul Burton #endif /* !CONFIG_MIPS_FP_SUPPORT */ 1224eec81d7SPaul Burton 123b2ead528SPaul Burton /* 1242db9ca0aSPaul Burton * Wrappers for the assembly _{save,restore}_fp_context functions. 1252db9ca0aSPaul Burton */ 1262db9ca0aSPaul Burton static int save_hw_fp_context(void __user *sc) 1272db9ca0aSPaul Burton { 1282db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 1292db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 1302db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 1312db9ca0aSPaul Burton 1322db9ca0aSPaul Burton return _save_fp_context(fpregs, csr); 1332db9ca0aSPaul Burton } 1342db9ca0aSPaul Burton 1352db9ca0aSPaul Burton static int restore_hw_fp_context(void __user *sc) 1362db9ca0aSPaul Burton { 1372db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 1382db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 1392db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 1402db9ca0aSPaul Burton 1412db9ca0aSPaul Burton return _restore_fp_context(fpregs, csr); 1422db9ca0aSPaul Burton } 1432db9ca0aSPaul Burton 1442db9ca0aSPaul Burton /* 145bf82cb30SPaul Burton * Extended context handling. 146bf82cb30SPaul Burton */ 147bf82cb30SPaul Burton 148bf82cb30SPaul Burton static inline void __user *sc_to_extcontext(void __user *sc) 149bf82cb30SPaul Burton { 150bf82cb30SPaul Burton struct ucontext __user *uc; 151bf82cb30SPaul Burton 152bf82cb30SPaul Burton /* 153bf82cb30SPaul Burton * We can just pretend the sigcontext is always embedded in a struct 154bf82cb30SPaul Burton * ucontext here, because the offset from sigcontext to extended 155bf82cb30SPaul Burton * context is the same in the struct sigframe case. 156bf82cb30SPaul Burton */ 157bf82cb30SPaul Burton uc = container_of(sc, struct ucontext, uc_mcontext); 158bf82cb30SPaul Burton return &uc->uc_extcontext; 159bf82cb30SPaul Burton } 160bf82cb30SPaul Burton 1614eec81d7SPaul Burton #ifdef CONFIG_CPU_HAS_MSA 1624eec81d7SPaul Burton 163bf82cb30SPaul Burton static int save_msa_extcontext(void __user *buf) 164bf82cb30SPaul Burton { 165bf82cb30SPaul Burton struct msa_extcontext __user *msa = buf; 166bf82cb30SPaul Burton uint64_t val; 167bf82cb30SPaul Burton int i, err; 168bf82cb30SPaul Burton 169bf82cb30SPaul Burton if (!thread_msa_context_live()) 170bf82cb30SPaul Burton return 0; 171bf82cb30SPaul Burton 172bf82cb30SPaul Burton /* 173bf82cb30SPaul Burton * Ensure that we can't lose the live MSA context between checking 174bf82cb30SPaul Burton * for it & writing it to memory. 175bf82cb30SPaul Burton */ 176bf82cb30SPaul Burton preempt_disable(); 177bf82cb30SPaul Burton 178bf82cb30SPaul Burton if (is_msa_enabled()) { 179bf82cb30SPaul Burton /* 180bf82cb30SPaul Burton * There are no EVA versions of the vector register load/store 181bf82cb30SPaul Burton * instructions, so MSA context has to be saved to kernel memory 182bf82cb30SPaul Burton * and then copied to user memory. The save to kernel memory 183bf82cb30SPaul Burton * should already have been done when handling scalar FP 184bf82cb30SPaul Burton * context. 185bf82cb30SPaul Burton */ 18697f2645fSMasahiro Yamada BUG_ON(IS_ENABLED(CONFIG_EVA)); 187bf82cb30SPaul Burton 188bf82cb30SPaul Burton err = __put_user(read_msa_csr(), &msa->csr); 189bf82cb30SPaul Burton err |= _save_msa_all_upper(&msa->wr); 190bf82cb30SPaul Burton 191bf82cb30SPaul Burton preempt_enable(); 192bf82cb30SPaul Burton } else { 193bf82cb30SPaul Burton preempt_enable(); 194bf82cb30SPaul Burton 195bf82cb30SPaul Burton err = __put_user(current->thread.fpu.msacsr, &msa->csr); 196bf82cb30SPaul Burton 197bf82cb30SPaul Burton for (i = 0; i < NUM_FPU_REGS; i++) { 198bf82cb30SPaul Burton val = get_fpr64(¤t->thread.fpu.fpr[i], 1); 199bf82cb30SPaul Burton err |= __put_user(val, &msa->wr[i]); 200bf82cb30SPaul Burton } 201bf82cb30SPaul Burton } 202bf82cb30SPaul Burton 203bf82cb30SPaul Burton err |= __put_user(MSA_EXTCONTEXT_MAGIC, &msa->ext.magic); 204bf82cb30SPaul Burton err |= __put_user(sizeof(*msa), &msa->ext.size); 205bf82cb30SPaul Burton 206bf82cb30SPaul Burton return err ? -EFAULT : sizeof(*msa); 207bf82cb30SPaul Burton } 208bf82cb30SPaul Burton 209bf82cb30SPaul Burton static int restore_msa_extcontext(void __user *buf, unsigned int size) 210bf82cb30SPaul Burton { 211bf82cb30SPaul Burton struct msa_extcontext __user *msa = buf; 212bf82cb30SPaul Burton unsigned long long val; 213bf82cb30SPaul Burton unsigned int csr; 214bf82cb30SPaul Burton int i, err; 215bf82cb30SPaul Burton 216bf82cb30SPaul Burton if (size != sizeof(*msa)) 217bf82cb30SPaul Burton return -EINVAL; 218bf82cb30SPaul Burton 219bf82cb30SPaul Burton err = get_user(csr, &msa->csr); 220bf82cb30SPaul Burton if (err) 221bf82cb30SPaul Burton return err; 222bf82cb30SPaul Burton 223bf82cb30SPaul Burton preempt_disable(); 224bf82cb30SPaul Burton 225bf82cb30SPaul Burton if (is_msa_enabled()) { 226bf82cb30SPaul Burton /* 227bf82cb30SPaul Burton * There are no EVA versions of the vector register load/store 228bf82cb30SPaul Burton * instructions, so MSA context has to be copied to kernel 229bf82cb30SPaul Burton * memory and later loaded to registers. The same is true of 230bf82cb30SPaul Burton * scalar FP context, so FPU & MSA should have already been 231bf82cb30SPaul Burton * disabled whilst handling scalar FP context. 232bf82cb30SPaul Burton */ 23397f2645fSMasahiro Yamada BUG_ON(IS_ENABLED(CONFIG_EVA)); 234bf82cb30SPaul Burton 235bf82cb30SPaul Burton write_msa_csr(csr); 236bf82cb30SPaul Burton err |= _restore_msa_all_upper(&msa->wr); 237bf82cb30SPaul Burton preempt_enable(); 238bf82cb30SPaul Burton } else { 239bf82cb30SPaul Burton preempt_enable(); 240bf82cb30SPaul Burton 241bf82cb30SPaul Burton current->thread.fpu.msacsr = csr; 242bf82cb30SPaul Burton 243bf82cb30SPaul Burton for (i = 0; i < NUM_FPU_REGS; i++) { 244bf82cb30SPaul Burton err |= __get_user(val, &msa->wr[i]); 245bf82cb30SPaul Burton set_fpr64(¤t->thread.fpu.fpr[i], 1, val); 246bf82cb30SPaul Burton } 247bf82cb30SPaul Burton } 248bf82cb30SPaul Burton 249bf82cb30SPaul Burton return err; 250bf82cb30SPaul Burton } 251bf82cb30SPaul Burton 2524eec81d7SPaul Burton #else /* !CONFIG_CPU_HAS_MSA */ 2534eec81d7SPaul Burton 2544eec81d7SPaul Burton static int save_msa_extcontext(void __user *buf) 2554eec81d7SPaul Burton { 2564eec81d7SPaul Burton return 0; 2574eec81d7SPaul Burton } 2584eec81d7SPaul Burton 2594eec81d7SPaul Burton static int restore_msa_extcontext(void __user *buf, unsigned int size) 2604eec81d7SPaul Burton { 2614eec81d7SPaul Burton return SIGSYS; 2624eec81d7SPaul Burton } 2634eec81d7SPaul Burton 2644eec81d7SPaul Burton #endif /* !CONFIG_CPU_HAS_MSA */ 2654eec81d7SPaul Burton 266bf82cb30SPaul Burton static int save_extcontext(void __user *buf) 267bf82cb30SPaul Burton { 268bf82cb30SPaul Burton int sz; 269bf82cb30SPaul Burton 270bf82cb30SPaul Burton sz = save_msa_extcontext(buf); 271bf82cb30SPaul Burton if (sz < 0) 272bf82cb30SPaul Burton return sz; 273bf82cb30SPaul Burton buf += sz; 274bf82cb30SPaul Burton 275bf82cb30SPaul Burton /* If no context was saved then trivially return */ 276bf82cb30SPaul Burton if (!sz) 277bf82cb30SPaul Burton return 0; 278bf82cb30SPaul Burton 279bf82cb30SPaul Burton /* Write the end marker */ 280bf82cb30SPaul Burton if (__put_user(END_EXTCONTEXT_MAGIC, (u32 *)buf)) 281bf82cb30SPaul Burton return -EFAULT; 282bf82cb30SPaul Burton 283bf82cb30SPaul Burton sz += sizeof(((struct extcontext *)NULL)->magic); 284bf82cb30SPaul Burton return sz; 285bf82cb30SPaul Burton } 286bf82cb30SPaul Burton 287bf82cb30SPaul Burton static int restore_extcontext(void __user *buf) 288bf82cb30SPaul Burton { 289bf82cb30SPaul Burton struct extcontext ext; 290bf82cb30SPaul Burton int err; 291bf82cb30SPaul Burton 292bf82cb30SPaul Burton while (1) { 293bf82cb30SPaul Burton err = __get_user(ext.magic, (unsigned int *)buf); 294bf82cb30SPaul Burton if (err) 295bf82cb30SPaul Burton return err; 296bf82cb30SPaul Burton 297bf82cb30SPaul Burton if (ext.magic == END_EXTCONTEXT_MAGIC) 298bf82cb30SPaul Burton return 0; 299bf82cb30SPaul Burton 300bf82cb30SPaul Burton err = __get_user(ext.size, (unsigned int *)(buf 301bf82cb30SPaul Burton + offsetof(struct extcontext, size))); 302bf82cb30SPaul Burton if (err) 303bf82cb30SPaul Burton return err; 304bf82cb30SPaul Burton 305bf82cb30SPaul Burton switch (ext.magic) { 306bf82cb30SPaul Burton case MSA_EXTCONTEXT_MAGIC: 307bf82cb30SPaul Burton err = restore_msa_extcontext(buf, ext.size); 308bf82cb30SPaul Burton break; 309bf82cb30SPaul Burton 310bf82cb30SPaul Burton default: 311bf82cb30SPaul Burton err = -EINVAL; 312bf82cb30SPaul Burton break; 313bf82cb30SPaul Burton } 314bf82cb30SPaul Burton 315bf82cb30SPaul Burton if (err) 316bf82cb30SPaul Burton return err; 317bf82cb30SPaul Burton 318bf82cb30SPaul Burton buf += ext.size; 319bf82cb30SPaul Burton } 320bf82cb30SPaul Burton } 321bf82cb30SPaul Burton 322bf82cb30SPaul Burton /* 323c3fc4ab3SFranck Bui-Huu * Helper routines 324c3fc4ab3SFranck Bui-Huu */ 325d02a40afSPaul Burton int protected_save_fp_context(void __user *sc) 326faea6234SAtsushi Nemoto { 3272db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 3282db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 3292db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 33064243c2aSPaul Burton uint32_t __user *used_math = sc + abi->off_sc_used_math; 331bf82cb30SPaul Burton unsigned int used, ext_sz; 332faea6234SAtsushi Nemoto int err; 333689ee856SPaul Burton 3340d071fa3SPaul Burton used = used_math() ? USED_FP : 0; 335bf82cb30SPaul Burton if (!used) 336bf82cb30SPaul Burton goto fp_done; 337bf82cb30SPaul Burton 3380d071fa3SPaul Burton if (!test_thread_flag(TIF_32BIT_FPREGS)) 3390d071fa3SPaul Burton used |= USED_FR1; 3400d071fa3SPaul Burton if (test_thread_flag(TIF_HYBRID_FPREGS)) 3410d071fa3SPaul Burton used |= USED_HYBRID_FPRS; 34264243c2aSPaul Burton 343689ee856SPaul Burton /* 344689ee856SPaul Burton * EVA does not have userland equivalents of ldc1 or sdc1, so 345689ee856SPaul Burton * save to the kernel FP context & copy that to userland below. 346689ee856SPaul Burton */ 34797f2645fSMasahiro Yamada if (IS_ENABLED(CONFIG_EVA)) 348689ee856SPaul Burton lose_fpu(1); 349689ee856SPaul Burton 350faea6234SAtsushi Nemoto while (1) { 351faea6234SAtsushi Nemoto lock_fpu_owner(); 352ff3aa5f2SPaul Burton if (is_fpu_owner()) { 353ff3aa5f2SPaul Burton err = save_fp_context(sc); 354faea6234SAtsushi Nemoto unlock_fpu_owner(); 355ff3aa5f2SPaul Burton } else { 356ff3aa5f2SPaul Burton unlock_fpu_owner(); 357ff3aa5f2SPaul Burton err = copy_fp_to_sigcontext(sc); 358ff3aa5f2SPaul Burton } 359faea6234SAtsushi Nemoto if (likely(!err)) 360faea6234SAtsushi Nemoto break; 361faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 3622db9ca0aSPaul Burton err = __put_user(0, &fpregs[0]) | 3632db9ca0aSPaul Burton __put_user(0, &fpregs[31]) | 3642db9ca0aSPaul Burton __put_user(0, csr); 365faea6234SAtsushi Nemoto if (err) 366bf82cb30SPaul Burton return err; /* really bad sigcontext */ 367faea6234SAtsushi Nemoto } 368689ee856SPaul Burton 369bf82cb30SPaul Burton fp_done: 370bf82cb30SPaul Burton ext_sz = err = save_extcontext(sc_to_extcontext(sc)); 371bf82cb30SPaul Burton if (err < 0) 372faea6234SAtsushi Nemoto return err; 373bf82cb30SPaul Burton used |= ext_sz ? USED_EXTCONTEXT : 0; 374bf82cb30SPaul Burton 375bf82cb30SPaul Burton return __put_user(used, used_math); 376faea6234SAtsushi Nemoto } 377faea6234SAtsushi Nemoto 378d02a40afSPaul Burton int protected_restore_fp_context(void __user *sc) 379faea6234SAtsushi Nemoto { 3802db9ca0aSPaul Burton struct mips_abi *abi = current->thread.abi; 3812db9ca0aSPaul Burton uint64_t __user *fpregs = sc + abi->off_sc_fpregs; 3822db9ca0aSPaul Burton uint32_t __user *csr = sc + abi->off_sc_fpc_csr; 38364243c2aSPaul Burton uint32_t __user *used_math = sc + abi->off_sc_used_math; 38464243c2aSPaul Burton unsigned int used; 385bf82cb30SPaul Burton int err, sig = 0, tmp __maybe_unused; 38664243c2aSPaul Burton 38764243c2aSPaul Burton err = __get_user(used, used_math); 3880d071fa3SPaul Burton conditional_used_math(used & USED_FP); 38964243c2aSPaul Burton 39064243c2aSPaul Burton /* 39164243c2aSPaul Burton * The signal handler may have used FPU; give it up if the program 39264243c2aSPaul Burton * doesn't want it following sigreturn. 39364243c2aSPaul Burton */ 394bf82cb30SPaul Burton if (err || !(used & USED_FP)) 39564243c2aSPaul Burton lose_fpu(0); 396bf82cb30SPaul Burton if (err) 39764243c2aSPaul Burton return err; 398bf82cb30SPaul Burton if (!(used & USED_FP)) 399bf82cb30SPaul Burton goto fp_done; 40064243c2aSPaul Burton 40164243c2aSPaul Burton err = sig = fpcsr_pending(csr); 40264243c2aSPaul Burton if (err < 0) 40364243c2aSPaul Burton return err; 404689ee856SPaul Burton 405689ee856SPaul Burton /* 406689ee856SPaul Burton * EVA does not have userland equivalents of ldc1 or sdc1, so we 407689ee856SPaul Burton * disable the FPU here such that the code below simply copies to 408689ee856SPaul Burton * the kernel FP context. 409689ee856SPaul Burton */ 41097f2645fSMasahiro Yamada if (IS_ENABLED(CONFIG_EVA)) 411689ee856SPaul Burton lose_fpu(0); 412689ee856SPaul Burton 413faea6234SAtsushi Nemoto while (1) { 414faea6234SAtsushi Nemoto lock_fpu_owner(); 415ff3aa5f2SPaul Burton if (is_fpu_owner()) { 416ff3aa5f2SPaul Burton err = restore_fp_context(sc); 417faea6234SAtsushi Nemoto unlock_fpu_owner(); 418ff3aa5f2SPaul Burton } else { 419ff3aa5f2SPaul Burton unlock_fpu_owner(); 420ff3aa5f2SPaul Burton err = copy_fp_from_sigcontext(sc); 421ff3aa5f2SPaul Burton } 422faea6234SAtsushi Nemoto if (likely(!err)) 423faea6234SAtsushi Nemoto break; 424faea6234SAtsushi Nemoto /* touch the sigcontext and try again */ 4252db9ca0aSPaul Burton err = __get_user(tmp, &fpregs[0]) | 4262db9ca0aSPaul Burton __get_user(tmp, &fpregs[31]) | 4272db9ca0aSPaul Burton __get_user(tmp, csr); 428faea6234SAtsushi Nemoto if (err) 429faea6234SAtsushi Nemoto break; /* really bad sigcontext */ 430faea6234SAtsushi Nemoto } 431689ee856SPaul Burton 432bf82cb30SPaul Burton fp_done: 4336533af4dSPaul Burton if (!err && (used & USED_EXTCONTEXT)) 4346533af4dSPaul Burton err = restore_extcontext(sc_to_extcontext(sc)); 435bf82cb30SPaul Burton 43664243c2aSPaul Burton return err ?: sig; 437faea6234SAtsushi Nemoto } 438faea6234SAtsushi Nemoto 439c3fc4ab3SFranck Bui-Huu int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 440c3fc4ab3SFranck Bui-Huu { 441c3fc4ab3SFranck Bui-Huu int err = 0; 442c3fc4ab3SFranck Bui-Huu int i; 443c3fc4ab3SFranck Bui-Huu 444c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->cp0_epc, &sc->sc_pc); 445c3fc4ab3SFranck Bui-Huu 446c3fc4ab3SFranck Bui-Huu err |= __put_user(0, &sc->sc_regs[0]); 447c3fc4ab3SFranck Bui-Huu for (i = 1; i < 32; i++) 448c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->regs[i], &sc->sc_regs[i]); 449c3fc4ab3SFranck Bui-Huu 4509693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS 4519693a853SFranck Bui-Huu err |= __put_user(regs->acx, &sc->sc_acx); 4529693a853SFranck Bui-Huu #endif 453c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->hi, &sc->sc_mdhi); 454c3fc4ab3SFranck Bui-Huu err |= __put_user(regs->lo, &sc->sc_mdlo); 455c3fc4ab3SFranck Bui-Huu if (cpu_has_dsp) { 456c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi1(), &sc->sc_hi1); 457c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo1(), &sc->sc_lo1); 458c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi2(), &sc->sc_hi2); 459c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo2(), &sc->sc_lo2); 460c3fc4ab3SFranck Bui-Huu err |= __put_user(mfhi3(), &sc->sc_hi3); 461c3fc4ab3SFranck Bui-Huu err |= __put_user(mflo3(), &sc->sc_lo3); 462c3fc4ab3SFranck Bui-Huu err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 463c3fc4ab3SFranck Bui-Huu } 464c3fc4ab3SFranck Bui-Huu 465c3fc4ab3SFranck Bui-Huu 466c3fc4ab3SFranck Bui-Huu /* 467c3fc4ab3SFranck Bui-Huu * Save FPU state to signal context. Signal handler 468c3fc4ab3SFranck Bui-Huu * will "inherit" current FPU state. 469c3fc4ab3SFranck Bui-Huu */ 47016f77de8SPaul Burton err |= protected_save_fp_context(sc); 47164243c2aSPaul Burton 472c3fc4ab3SFranck Bui-Huu return err; 473c3fc4ab3SFranck Bui-Huu } 474c3fc4ab3SFranck Bui-Huu 475bf82cb30SPaul Burton static size_t extcontext_max_size(void) 476bf82cb30SPaul Burton { 477bf82cb30SPaul Burton size_t sz = 0; 478bf82cb30SPaul Burton 479bf82cb30SPaul Burton /* 480bf82cb30SPaul Burton * The assumption here is that between this point & the point at which 481bf82cb30SPaul Burton * the extended context is saved the size of the context should only 482bf82cb30SPaul Burton * ever be able to shrink (if the task is preempted), but never grow. 483bf82cb30SPaul Burton * That is, what this function returns is an upper bound on the size of 484bf82cb30SPaul Burton * the extended context for the current task at the current time. 485bf82cb30SPaul Burton */ 486bf82cb30SPaul Burton 487bf82cb30SPaul Burton if (thread_msa_context_live()) 488bf82cb30SPaul Burton sz += sizeof(struct msa_extcontext); 489bf82cb30SPaul Burton 490bf82cb30SPaul Burton /* If any context is saved then we'll append the end marker */ 491bf82cb30SPaul Burton if (sz) 492bf82cb30SPaul Burton sz += sizeof(((struct extcontext *)NULL)->magic); 493bf82cb30SPaul Burton 494bf82cb30SPaul Burton return sz; 495bf82cb30SPaul Burton } 496bf82cb30SPaul Burton 497c6a2f467SAtsushi Nemoto int fpcsr_pending(unsigned int __user *fpcsr) 498c6a2f467SAtsushi Nemoto { 499c6a2f467SAtsushi Nemoto int err, sig = 0; 500c6a2f467SAtsushi Nemoto unsigned int csr, enabled; 501c6a2f467SAtsushi Nemoto 502c6a2f467SAtsushi Nemoto err = __get_user(csr, fpcsr); 503c6a2f467SAtsushi Nemoto enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); 504c6a2f467SAtsushi Nemoto /* 505c6a2f467SAtsushi Nemoto * If the signal handler set some FPU exceptions, clear it and 506c6a2f467SAtsushi Nemoto * send SIGFPE. 507c6a2f467SAtsushi Nemoto */ 508c6a2f467SAtsushi Nemoto if (csr & enabled) { 509c6a2f467SAtsushi Nemoto csr &= ~enabled; 510c6a2f467SAtsushi Nemoto err |= __put_user(csr, fpcsr); 511c6a2f467SAtsushi Nemoto sig = SIGFPE; 512c6a2f467SAtsushi Nemoto } 513c6a2f467SAtsushi Nemoto return err ?: sig; 514c6a2f467SAtsushi Nemoto } 515c6a2f467SAtsushi Nemoto 516c3fc4ab3SFranck Bui-Huu int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 517c3fc4ab3SFranck Bui-Huu { 518c3fc4ab3SFranck Bui-Huu unsigned long treg; 519c3fc4ab3SFranck Bui-Huu int err = 0; 520c3fc4ab3SFranck Bui-Huu int i; 521c3fc4ab3SFranck Bui-Huu 522c3fc4ab3SFranck Bui-Huu /* Always make any pending restarted system calls return -EINTR */ 523f56141e3SAndy Lutomirski current->restart_block.fn = do_no_restart_syscall; 524c3fc4ab3SFranck Bui-Huu 525c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->cp0_epc, &sc->sc_pc); 5269693a853SFranck Bui-Huu 5279693a853SFranck Bui-Huu #ifdef CONFIG_CPU_HAS_SMARTMIPS 5289693a853SFranck Bui-Huu err |= __get_user(regs->acx, &sc->sc_acx); 5299693a853SFranck Bui-Huu #endif 530c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->hi, &sc->sc_mdhi); 531c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->lo, &sc->sc_mdlo); 532c3fc4ab3SFranck Bui-Huu if (cpu_has_dsp) { 533c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); 534c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); 535c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); 536c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); 537c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); 538c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); 539c3fc4ab3SFranck Bui-Huu err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); 540c3fc4ab3SFranck Bui-Huu } 541c3fc4ab3SFranck Bui-Huu 542c3fc4ab3SFranck Bui-Huu for (i = 1; i < 32; i++) 543c3fc4ab3SFranck Bui-Huu err |= __get_user(regs->regs[i], &sc->sc_regs[i]); 544c3fc4ab3SFranck Bui-Huu 54564243c2aSPaul Burton return err ?: protected_restore_fp_context(sc); 546c3fc4ab3SFranck Bui-Huu } 547c3fc4ab3SFranck Bui-Huu 548886ee136SThomas Bogendoerfer #ifdef CONFIG_WAR_ICACHE_REFILLS 549886ee136SThomas Bogendoerfer #define SIGMASK ~(cpu_icache_line_size()-1) 550886ee136SThomas Bogendoerfer #else 551886ee136SThomas Bogendoerfer #define SIGMASK ALMASK 552886ee136SThomas Bogendoerfer #endif 553886ee136SThomas Bogendoerfer 5547c4f5635SRichard Weinberger void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, 555c3fc4ab3SFranck Bui-Huu size_t frame_size) 556c3fc4ab3SFranck Bui-Huu { 557c3fc4ab3SFranck Bui-Huu unsigned long sp; 558c3fc4ab3SFranck Bui-Huu 559bf82cb30SPaul Burton /* Leave space for potential extended context */ 560bf82cb30SPaul Burton frame_size += extcontext_max_size(); 561bf82cb30SPaul Burton 562c3fc4ab3SFranck Bui-Huu /* Default to using normal stack */ 563c3fc4ab3SFranck Bui-Huu sp = regs->regs[29]; 564c3fc4ab3SFranck Bui-Huu 565c3fc4ab3SFranck Bui-Huu /* 566*0ebd37a2STiezhu Yang * If we are on the alternate signal stack and would overflow it, don't. 567*0ebd37a2STiezhu Yang * Return an always-bogus address instead so we will die with SIGSEGV. 568*0ebd37a2STiezhu Yang */ 569*0ebd37a2STiezhu Yang if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) 570*0ebd37a2STiezhu Yang return (void __user __force *)(-1UL); 571*0ebd37a2STiezhu Yang 572*0ebd37a2STiezhu Yang /* 573c3fc4ab3SFranck Bui-Huu * FPU emulator may have it's own trampoline active just 574c3fc4ab3SFranck Bui-Huu * above the user stack, 16-bytes before the next lowest 575c3fc4ab3SFranck Bui-Huu * 16 byte boundary. Try to avoid trashing it. 576c3fc4ab3SFranck Bui-Huu */ 577c3fc4ab3SFranck Bui-Huu sp -= 32; 578c3fc4ab3SFranck Bui-Huu 5797c4f5635SRichard Weinberger sp = sigsp(sp, ksig); 580c3fc4ab3SFranck Bui-Huu 581886ee136SThomas Bogendoerfer return (void __user *)((sp - frame_size) & SIGMASK); 582c3fc4ab3SFranck Bui-Huu } 583c3fc4ab3SFranck Bui-Huu 584c3fc4ab3SFranck Bui-Huu /* 5851da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 5861da177e4SLinus Torvalds */ 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 5891910f4abSAl Viro SYSCALL_DEFINE1(sigsuspend, sigset_t __user *, uset) 5901da177e4SLinus Torvalds { 5911910f4abSAl Viro return sys_rt_sigsuspend(uset, sizeof(sigset_t)); 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds #endif 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 596dbda6ac0SRalf Baechle SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, 597dbda6ac0SRalf Baechle struct sigaction __user *, oact) 5981da177e4SLinus Torvalds { 5991da177e4SLinus Torvalds struct k_sigaction new_ka, old_ka; 6001da177e4SLinus Torvalds int ret; 6011da177e4SLinus Torvalds int err = 0; 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds if (act) { 6041da177e4SLinus Torvalds old_sigset_t mask; 6051da177e4SLinus Torvalds 60696d4f267SLinus Torvalds if (!access_ok(act, sizeof(*act))) 6071da177e4SLinus Torvalds return -EFAULT; 6081da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); 6091da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 6101da177e4SLinus Torvalds err |= __get_user(mask, &act->sa_mask.sig[0]); 6111da177e4SLinus Torvalds if (err) 6121da177e4SLinus Torvalds return -EFAULT; 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds siginitset(&new_ka.sa.sa_mask, mask); 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds if (!ret && oact) { 62096d4f267SLinus Torvalds if (!access_ok(oact, sizeof(*oact))) 6211da177e4SLinus Torvalds return -EFAULT; 6221da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 6231da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); 6241da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 6251da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[1]); 6261da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[2]); 6271da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[3]); 6281da177e4SLinus Torvalds if (err) 6291da177e4SLinus Torvalds return -EFAULT; 6301da177e4SLinus Torvalds } 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds return ret; 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds #endif 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 63796a68b14SPaul Burton asmlinkage void sys_sigreturn(void) 6381da177e4SLinus Torvalds { 6399bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 64096a68b14SPaul Burton struct pt_regs *regs; 6411da177e4SLinus Torvalds sigset_t blocked; 642c6a2f467SAtsushi Nemoto int sig; 6431da177e4SLinus Torvalds 64496a68b14SPaul Burton regs = current_pt_regs(); 64596a68b14SPaul Burton frame = (struct sigframe __user *)regs->regs[29]; 64696d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame))) 6471da177e4SLinus Torvalds goto badframe; 6481da177e4SLinus Torvalds if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) 6491da177e4SLinus Torvalds goto badframe; 6501da177e4SLinus Torvalds 6518598f3cdSMatt Fleming set_current_blocked(&blocked); 6521da177e4SLinus Torvalds 65396a68b14SPaul Burton sig = restore_sigcontext(regs, &frame->sf_sc); 654c6a2f467SAtsushi Nemoto if (sig < 0) 6551da177e4SLinus Torvalds goto badframe; 656c6a2f467SAtsushi Nemoto else if (sig) 6573cf5d076SEric W. Biederman force_sig(sig); 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds /* 6601da177e4SLinus Torvalds * Don't let your children do this ... 6611da177e4SLinus Torvalds */ 6621da177e4SLinus Torvalds __asm__ __volatile__( 6631da177e4SLinus Torvalds "move\t$29, %0\n\t" 6641da177e4SLinus Torvalds "j\tsyscall_exit" 6651da177e4SLinus Torvalds : /* no outputs */ 66696a68b14SPaul Burton : "r" (regs)); 6671da177e4SLinus Torvalds /* Unreached */ 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds badframe: 6703cf5d076SEric W. Biederman force_sig(SIGSEGV); 6711da177e4SLinus Torvalds } 672e50c0a8fSRalf Baechle #endif /* CONFIG_TRAD_SIGNALS */ 6731da177e4SLinus Torvalds 67496a68b14SPaul Burton asmlinkage void sys_rt_sigreturn(void) 6751da177e4SLinus Torvalds { 6769bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 67796a68b14SPaul Burton struct pt_regs *regs; 6781da177e4SLinus Torvalds sigset_t set; 679c6a2f467SAtsushi Nemoto int sig; 6801da177e4SLinus Torvalds 68196a68b14SPaul Burton regs = current_pt_regs(); 68296a68b14SPaul Burton frame = (struct rt_sigframe __user *)regs->regs[29]; 68396d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame))) 6841da177e4SLinus Torvalds goto badframe; 6851da177e4SLinus Torvalds if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 6861da177e4SLinus Torvalds goto badframe; 6871da177e4SLinus Torvalds 6888598f3cdSMatt Fleming set_current_blocked(&set); 6891da177e4SLinus Torvalds 69096a68b14SPaul Burton sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); 691c6a2f467SAtsushi Nemoto if (sig < 0) 6921da177e4SLinus Torvalds goto badframe; 693c6a2f467SAtsushi Nemoto else if (sig) 6943cf5d076SEric W. Biederman force_sig(sig); 6951da177e4SLinus Torvalds 696ea536ad4SAl Viro if (restore_altstack(&frame->rs_uc.uc_stack)) 697ea536ad4SAl Viro goto badframe; 6981da177e4SLinus Torvalds 6991da177e4SLinus Torvalds /* 7001da177e4SLinus Torvalds * Don't let your children do this ... 7011da177e4SLinus Torvalds */ 7021da177e4SLinus Torvalds __asm__ __volatile__( 7031da177e4SLinus Torvalds "move\t$29, %0\n\t" 7041da177e4SLinus Torvalds "j\tsyscall_exit" 7051da177e4SLinus Torvalds : /* no outputs */ 70696a68b14SPaul Burton : "r" (regs)); 7071da177e4SLinus Torvalds /* Unreached */ 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds badframe: 7103cf5d076SEric W. Biederman force_sig(SIGSEGV); 7111da177e4SLinus Torvalds } 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 71481d103bfSRichard Weinberger static int setup_frame(void *sig_return, struct ksignal *ksig, 71581d103bfSRichard Weinberger struct pt_regs *regs, sigset_t *set) 7161da177e4SLinus Torvalds { 7179bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 7181da177e4SLinus Torvalds int err = 0; 7191da177e4SLinus Torvalds 7207c4f5635SRichard Weinberger frame = get_sigframe(ksig, regs, sizeof(*frame)); 72196d4f267SLinus Torvalds if (!access_ok(frame, sizeof (*frame))) 72281d103bfSRichard Weinberger return -EFAULT; 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->sf_sc); 7251da177e4SLinus Torvalds err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 7261da177e4SLinus Torvalds if (err) 72781d103bfSRichard Weinberger return -EFAULT; 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds /* 7301da177e4SLinus Torvalds * Arguments to signal handler: 7311da177e4SLinus Torvalds * 7321da177e4SLinus Torvalds * a0 = signal number 7331da177e4SLinus Torvalds * a1 = 0 (should be cause) 7341da177e4SLinus Torvalds * a2 = pointer to struct sigcontext 7351da177e4SLinus Torvalds * 7361da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to the 7371da177e4SLinus Torvalds * struct sigframe. 7381da177e4SLinus Torvalds */ 73981d103bfSRichard Weinberger regs->regs[ 4] = ksig->sig; 7401da177e4SLinus Torvalds regs->regs[ 5] = 0; 7411da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->sf_sc; 7421da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 743d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 74481d103bfSRichard Weinberger regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; 7451da177e4SLinus Torvalds 746722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 7471da177e4SLinus Torvalds current->comm, current->pid, 748722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 7497b3e2fc8SRalf Baechle return 0; 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds #endif 7521da177e4SLinus Torvalds 75381d103bfSRichard Weinberger static int setup_rt_frame(void *sig_return, struct ksignal *ksig, 75481d103bfSRichard Weinberger struct pt_regs *regs, sigset_t *set) 7551da177e4SLinus Torvalds { 7569bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 7571da177e4SLinus Torvalds int err = 0; 7581da177e4SLinus Torvalds 7597c4f5635SRichard Weinberger frame = get_sigframe(ksig, regs, sizeof(*frame)); 76096d4f267SLinus Torvalds if (!access_ok(frame, sizeof (*frame))) 76181d103bfSRichard Weinberger return -EFAULT; 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds /* Create siginfo. */ 76481d103bfSRichard Weinberger err |= copy_siginfo_to_user(&frame->rs_info, &ksig->info); 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds /* Create the ucontext. */ 7671da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 7685665a0acSAtsushi Nemoto err |= __put_user(NULL, &frame->rs_uc.uc_link); 769ea536ad4SAl Viro err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); 7701da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 7711da177e4SLinus Torvalds err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds if (err) 77481d103bfSRichard Weinberger return -EFAULT; 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds /* 7771da177e4SLinus Torvalds * Arguments to signal handler: 7781da177e4SLinus Torvalds * 7791da177e4SLinus Torvalds * a0 = signal number 7801da177e4SLinus Torvalds * a1 = 0 (should be cause) 7811da177e4SLinus Torvalds * a2 = pointer to ucontext 7821da177e4SLinus Torvalds * 7831da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 7841da177e4SLinus Torvalds * the struct rt_sigframe. 7851da177e4SLinus Torvalds */ 78681d103bfSRichard Weinberger regs->regs[ 4] = ksig->sig; 7871da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 7881da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 7891da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 790d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 79181d103bfSRichard Weinberger regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; 7921da177e4SLinus Torvalds 793722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 7941da177e4SLinus Torvalds current->comm, current->pid, 7951da177e4SLinus Torvalds frame, regs->cp0_epc, regs->regs[31]); 796722bb63dSFranck Bui-Huu 7977b3e2fc8SRalf Baechle return 0; 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 800151fd6acSRalf Baechle struct mips_abi mips_abi = { 801151fd6acSRalf Baechle #ifdef CONFIG_TRAD_SIGNALS 802151fd6acSRalf Baechle .setup_frame = setup_frame, 803151fd6acSRalf Baechle #endif 804151fd6acSRalf Baechle .setup_rt_frame = setup_rt_frame, 80577856100SPaul Burton .restart = __NR_restart_syscall, 80677856100SPaul Burton 80777856100SPaul Burton .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), 80877856100SPaul Burton .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), 80977856100SPaul Burton .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), 810ebb5e78cSAlex Smith 811ebb5e78cSAlex Smith .vdso = &vdso_image, 812151fd6acSRalf Baechle }; 813151fd6acSRalf Baechle 81481d103bfSRichard Weinberger static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) 8151da177e4SLinus Torvalds { 816b7f9a11aSAl Viro sigset_t *oldset = sigmask_to_save(); 817129bc8f7SRalf Baechle int ret; 818d814c28cSDavid Daney struct mips_abi *abi = current->thread.abi; 819d814c28cSDavid Daney void *vdso = current->mm->context.vdso; 820129bc8f7SRalf Baechle 821432c6bacSPaul Burton /* 822432c6bacSPaul Burton * If we were emulating a delay slot instruction, exit that frame such 823432c6bacSPaul Burton * that addresses in the sigframe are as expected for userland and we 824432c6bacSPaul Burton * don't have a problem if we reuse the thread's frame for an 825432c6bacSPaul Burton * instruction within the signal handler. 826432c6bacSPaul Burton */ 827432c6bacSPaul Burton dsemul_thread_rollback(regs); 828432c6bacSPaul Burton 8298f5a00ebSAl Viro if (regs->regs[0]) { 8308f5a00ebSAl Viro switch(regs->regs[2]) { 8311da177e4SLinus Torvalds case ERESTART_RESTARTBLOCK: 8321da177e4SLinus Torvalds case ERESTARTNOHAND: 8331da177e4SLinus Torvalds regs->regs[2] = EINTR; 8341da177e4SLinus Torvalds break; 8351da177e4SLinus Torvalds case ERESTARTSYS: 83681d103bfSRichard Weinberger if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { 8371da177e4SLinus Torvalds regs->regs[2] = EINTR; 8381da177e4SLinus Torvalds break; 8391da177e4SLinus Torvalds } 840c9b02990SLiangliang Huang fallthrough; 8418f5a00ebSAl Viro case ERESTARTNOINTR: 8421da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 8438f5a00ebSAl Viro regs->regs[2] = regs->regs[0]; 8448f5a00ebSAl Viro regs->cp0_epc -= 4; 8451da177e4SLinus Torvalds } 8461da177e4SLinus Torvalds 8471da177e4SLinus Torvalds regs->regs[0] = 0; /* Don't deal with this again. */ 8488f5a00ebSAl Viro } 8491da177e4SLinus Torvalds 850662d855cSPaul Burton rseq_signal_deliver(ksig, regs); 8519ea141adSPaul Burton 8527939469dSLeonid Yegoshin if (sig_uses_siginfo(&ksig->ka, abi)) 853ebb5e78cSAlex Smith ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn, 85481d103bfSRichard Weinberger ksig, regs, oldset); 8551da177e4SLinus Torvalds else 856ebb5e78cSAlex Smith ret = abi->setup_frame(vdso + abi->vdso->off_sigreturn, 857ebb5e78cSAlex Smith ksig, regs, oldset); 8581da177e4SLinus Torvalds 85981d103bfSRichard Weinberger signal_setup_done(ret, ksig, 0); 8601da177e4SLinus Torvalds } 8611da177e4SLinus Torvalds 862151fd6acSRalf Baechle static void do_signal(struct pt_regs *regs) 8631da177e4SLinus Torvalds { 86481d103bfSRichard Weinberger struct ksignal ksig; 8651da177e4SLinus Torvalds 86681d103bfSRichard Weinberger if (get_signal(&ksig)) { 8677b3e2fc8SRalf Baechle /* Whee! Actually deliver the signal. */ 86881d103bfSRichard Weinberger handle_signal(&ksig, regs); 86945887e12SRalf Baechle return; 8707b3e2fc8SRalf Baechle } 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds if (regs->regs[0]) { 8739ec9b5acSRalf Baechle switch (regs->regs[2]) { 8749ec9b5acSRalf Baechle case ERESTARTNOHAND: 8759ec9b5acSRalf Baechle case ERESTARTSYS: 8769ec9b5acSRalf Baechle case ERESTARTNOINTR: 8778f5a00ebSAl Viro regs->regs[2] = regs->regs[0]; 8781da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 8798f5a00ebSAl Viro regs->cp0_epc -= 4; 8809ec9b5acSRalf Baechle break; 8819ec9b5acSRalf Baechle 8829ec9b5acSRalf Baechle case ERESTART_RESTARTBLOCK: 883151fd6acSRalf Baechle regs->regs[2] = current->thread.abi->restart; 8841da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 8851da177e4SLinus Torvalds regs->cp0_epc -= 4; 8869ec9b5acSRalf Baechle break; 8871da177e4SLinus Torvalds } 88813fdd31aSRalf Baechle regs->regs[0] = 0; /* Don't deal with this again. */ 8891da177e4SLinus Torvalds } 8907b3e2fc8SRalf Baechle 8917b3e2fc8SRalf Baechle /* 8927b3e2fc8SRalf Baechle * If there's no signal to deliver, we just put the saved sigmask 8937b3e2fc8SRalf Baechle * back 8947b3e2fc8SRalf Baechle */ 89551a7b448SAl Viro restore_saved_sigmask(); 8961da177e4SLinus Torvalds } 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds /* 8991da177e4SLinus Torvalds * notification of userspace execution resumption 9007b3e2fc8SRalf Baechle * - triggered by the TIF_WORK_MASK flags 9011da177e4SLinus Torvalds */ 9027b3e2fc8SRalf Baechle asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, 9031da177e4SLinus Torvalds __u32 thread_info_flags) 9041da177e4SLinus Torvalds { 9051f717929SRalf Baechle local_irq_enable(); 9061f717929SRalf Baechle 907c3fc5cd5SRalf Baechle user_exit(); 908c3fc5cd5SRalf Baechle 90940e084a5SRalf Baechle if (thread_info_flags & _TIF_UPROBE) 91040e084a5SRalf Baechle uprobe_notify_resume(regs); 91140e084a5SRalf Baechle 9121da177e4SLinus Torvalds /* deal with pending signal delivery */ 913f45c184bSJens Axboe if (thread_info_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) 914151fd6acSRalf Baechle do_signal(regs); 915d0420c83SDavid Howells 916a68de80fSSean Christopherson if (thread_info_flags & _TIF_NOTIFY_RESUME) 917d0420c83SDavid Howells tracehook_notify_resume(regs); 918c3fc5cd5SRalf Baechle 919c3fc5cd5SRalf Baechle user_enter(); 9201da177e4SLinus Torvalds } 921137f6f3eSRalf Baechle 9224eec81d7SPaul Burton #if defined(CONFIG_SMP) && defined(CONFIG_MIPS_FP_SUPPORT) 9232db9ca0aSPaul Burton static int smp_save_fp_context(void __user *sc) 924137f6f3eSRalf Baechle { 925137f6f3eSRalf Baechle return raw_cpu_has_fpu 9262db9ca0aSPaul Burton ? save_hw_fp_context(sc) 927b2ead528SPaul Burton : copy_fp_to_sigcontext(sc); 928137f6f3eSRalf Baechle } 929137f6f3eSRalf Baechle 9302db9ca0aSPaul Burton static int smp_restore_fp_context(void __user *sc) 931137f6f3eSRalf Baechle { 932137f6f3eSRalf Baechle return raw_cpu_has_fpu 9332db9ca0aSPaul Burton ? restore_hw_fp_context(sc) 934b2ead528SPaul Burton : copy_fp_from_sigcontext(sc); 935137f6f3eSRalf Baechle } 936137f6f3eSRalf Baechle #endif 937137f6f3eSRalf Baechle 938137f6f3eSRalf Baechle static int signal_setup(void) 939137f6f3eSRalf Baechle { 940f1fe2d21SPaul Burton /* 941f1fe2d21SPaul Burton * The offset from sigcontext to extended context should be the same 942f1fe2d21SPaul Burton * regardless of the type of signal, such that userland can always know 943f1fe2d21SPaul Burton * where to look if it wishes to find the extended context structures. 944f1fe2d21SPaul Burton */ 945f1fe2d21SPaul Burton BUILD_BUG_ON((offsetof(struct sigframe, sf_extcontext) - 946f1fe2d21SPaul Burton offsetof(struct sigframe, sf_sc)) != 947f1fe2d21SPaul Burton (offsetof(struct rt_sigframe, rs_uc.uc_extcontext) - 948f1fe2d21SPaul Burton offsetof(struct rt_sigframe, rs_uc.uc_mcontext))); 949f1fe2d21SPaul Burton 9504eec81d7SPaul Burton #if defined(CONFIG_SMP) && defined(CONFIG_MIPS_FP_SUPPORT) 951137f6f3eSRalf Baechle /* For now just do the cpu_has_fpu check when the functions are invoked */ 952137f6f3eSRalf Baechle save_fp_context = smp_save_fp_context; 953137f6f3eSRalf Baechle restore_fp_context = smp_restore_fp_context; 954137f6f3eSRalf Baechle #else 955137f6f3eSRalf Baechle if (cpu_has_fpu) { 9562db9ca0aSPaul Burton save_fp_context = save_hw_fp_context; 9572db9ca0aSPaul Burton restore_fp_context = restore_hw_fp_context; 958137f6f3eSRalf Baechle } else { 95914fa12dfSPaul Burton save_fp_context = copy_fp_to_sigcontext; 96014fa12dfSPaul Burton restore_fp_context = copy_fp_from_sigcontext; 961137f6f3eSRalf Baechle } 962ca750649SLeonid Yegoshin #endif /* CONFIG_SMP */ 963137f6f3eSRalf Baechle 964137f6f3eSRalf Baechle return 0; 965137f6f3eSRalf Baechle } 966137f6f3eSRalf Baechle 967137f6f3eSRalf Baechle arch_initcall(signal_setup); 968