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 /* 566c3fc4ab3SFranck Bui-Huu * FPU emulator may have it's own trampoline active just 567c3fc4ab3SFranck Bui-Huu * above the user stack, 16-bytes before the next lowest 568c3fc4ab3SFranck Bui-Huu * 16 byte boundary. Try to avoid trashing it. 569c3fc4ab3SFranck Bui-Huu */ 570c3fc4ab3SFranck Bui-Huu sp -= 32; 571c3fc4ab3SFranck Bui-Huu 5727c4f5635SRichard Weinberger sp = sigsp(sp, ksig); 573c3fc4ab3SFranck Bui-Huu 574886ee136SThomas Bogendoerfer return (void __user *)((sp - frame_size) & SIGMASK); 575c3fc4ab3SFranck Bui-Huu } 576c3fc4ab3SFranck Bui-Huu 577c3fc4ab3SFranck Bui-Huu /* 5781da177e4SLinus Torvalds * Atomically swap in the new signal mask, and wait for a signal. 5791da177e4SLinus Torvalds */ 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 5821910f4abSAl Viro SYSCALL_DEFINE1(sigsuspend, sigset_t __user *, uset) 5831da177e4SLinus Torvalds { 5841910f4abSAl Viro return sys_rt_sigsuspend(uset, sizeof(sigset_t)); 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds #endif 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 589dbda6ac0SRalf Baechle SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, 590dbda6ac0SRalf Baechle struct sigaction __user *, oact) 5911da177e4SLinus Torvalds { 5921da177e4SLinus Torvalds struct k_sigaction new_ka, old_ka; 5931da177e4SLinus Torvalds int ret; 5941da177e4SLinus Torvalds int err = 0; 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds if (act) { 5971da177e4SLinus Torvalds old_sigset_t mask; 5981da177e4SLinus Torvalds 59996d4f267SLinus Torvalds if (!access_ok(act, sizeof(*act))) 6001da177e4SLinus Torvalds return -EFAULT; 6011da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); 6021da177e4SLinus Torvalds err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 6031da177e4SLinus Torvalds err |= __get_user(mask, &act->sa_mask.sig[0]); 6041da177e4SLinus Torvalds if (err) 6051da177e4SLinus Torvalds return -EFAULT; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds siginitset(&new_ka.sa.sa_mask, mask); 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds if (!ret && oact) { 61396d4f267SLinus Torvalds if (!access_ok(oact, sizeof(*oact))) 6141da177e4SLinus Torvalds return -EFAULT; 6151da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 6161da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); 6171da177e4SLinus Torvalds err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 6181da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[1]); 6191da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[2]); 6201da177e4SLinus Torvalds err |= __put_user(0, &oact->sa_mask.sig[3]); 6211da177e4SLinus Torvalds if (err) 6221da177e4SLinus Torvalds return -EFAULT; 6231da177e4SLinus Torvalds } 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds return ret; 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds #endif 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 63096a68b14SPaul Burton asmlinkage void sys_sigreturn(void) 6311da177e4SLinus Torvalds { 6329bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 63396a68b14SPaul Burton struct pt_regs *regs; 6341da177e4SLinus Torvalds sigset_t blocked; 635c6a2f467SAtsushi Nemoto int sig; 6361da177e4SLinus Torvalds 63796a68b14SPaul Burton regs = current_pt_regs(); 63896a68b14SPaul Burton frame = (struct sigframe __user *)regs->regs[29]; 63996d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame))) 6401da177e4SLinus Torvalds goto badframe; 6411da177e4SLinus Torvalds if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) 6421da177e4SLinus Torvalds goto badframe; 6431da177e4SLinus Torvalds 6448598f3cdSMatt Fleming set_current_blocked(&blocked); 6451da177e4SLinus Torvalds 64696a68b14SPaul Burton sig = restore_sigcontext(regs, &frame->sf_sc); 647c6a2f467SAtsushi Nemoto if (sig < 0) 6481da177e4SLinus Torvalds goto badframe; 649c6a2f467SAtsushi Nemoto else if (sig) 6503cf5d076SEric W. Biederman force_sig(sig); 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds /* 6531da177e4SLinus Torvalds * Don't let your children do this ... 6541da177e4SLinus Torvalds */ 6551da177e4SLinus Torvalds __asm__ __volatile__( 6561da177e4SLinus Torvalds "move\t$29, %0\n\t" 6571da177e4SLinus Torvalds "j\tsyscall_exit" 6581da177e4SLinus Torvalds : /* no outputs */ 65996a68b14SPaul Burton : "r" (regs)); 6601da177e4SLinus Torvalds /* Unreached */ 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds badframe: 6633cf5d076SEric W. Biederman force_sig(SIGSEGV); 6641da177e4SLinus Torvalds } 665e50c0a8fSRalf Baechle #endif /* CONFIG_TRAD_SIGNALS */ 6661da177e4SLinus Torvalds 66796a68b14SPaul Burton asmlinkage void sys_rt_sigreturn(void) 6681da177e4SLinus Torvalds { 6699bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 67096a68b14SPaul Burton struct pt_regs *regs; 6711da177e4SLinus Torvalds sigset_t set; 672c6a2f467SAtsushi Nemoto int sig; 6731da177e4SLinus Torvalds 67496a68b14SPaul Burton regs = current_pt_regs(); 67596a68b14SPaul Burton frame = (struct rt_sigframe __user *)regs->regs[29]; 67696d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame))) 6771da177e4SLinus Torvalds goto badframe; 6781da177e4SLinus Torvalds if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) 6791da177e4SLinus Torvalds goto badframe; 6801da177e4SLinus Torvalds 6818598f3cdSMatt Fleming set_current_blocked(&set); 6821da177e4SLinus Torvalds 68396a68b14SPaul Burton sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); 684c6a2f467SAtsushi Nemoto if (sig < 0) 6851da177e4SLinus Torvalds goto badframe; 686c6a2f467SAtsushi Nemoto else if (sig) 6873cf5d076SEric W. Biederman force_sig(sig); 6881da177e4SLinus Torvalds 689ea536ad4SAl Viro if (restore_altstack(&frame->rs_uc.uc_stack)) 690ea536ad4SAl Viro goto badframe; 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds /* 6931da177e4SLinus Torvalds * Don't let your children do this ... 6941da177e4SLinus Torvalds */ 6951da177e4SLinus Torvalds __asm__ __volatile__( 6961da177e4SLinus Torvalds "move\t$29, %0\n\t" 6971da177e4SLinus Torvalds "j\tsyscall_exit" 6981da177e4SLinus Torvalds : /* no outputs */ 69996a68b14SPaul Burton : "r" (regs)); 7001da177e4SLinus Torvalds /* Unreached */ 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds badframe: 7033cf5d076SEric W. Biederman force_sig(SIGSEGV); 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds #ifdef CONFIG_TRAD_SIGNALS 70781d103bfSRichard Weinberger static int setup_frame(void *sig_return, struct ksignal *ksig, 70881d103bfSRichard Weinberger struct pt_regs *regs, sigset_t *set) 7091da177e4SLinus Torvalds { 7109bbf28a3SAtsushi Nemoto struct sigframe __user *frame; 7111da177e4SLinus Torvalds int err = 0; 7121da177e4SLinus Torvalds 7137c4f5635SRichard Weinberger frame = get_sigframe(ksig, regs, sizeof(*frame)); 71496d4f267SLinus Torvalds if (!access_ok(frame, sizeof (*frame))) 71581d103bfSRichard Weinberger return -EFAULT; 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->sf_sc); 7181da177e4SLinus Torvalds err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 7191da177e4SLinus Torvalds if (err) 72081d103bfSRichard Weinberger return -EFAULT; 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds /* 7231da177e4SLinus Torvalds * Arguments to signal handler: 7241da177e4SLinus Torvalds * 7251da177e4SLinus Torvalds * a0 = signal number 7261da177e4SLinus Torvalds * a1 = 0 (should be cause) 7271da177e4SLinus Torvalds * a2 = pointer to struct sigcontext 7281da177e4SLinus Torvalds * 7291da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to the 7301da177e4SLinus Torvalds * struct sigframe. 7311da177e4SLinus Torvalds */ 73281d103bfSRichard Weinberger regs->regs[ 4] = ksig->sig; 7331da177e4SLinus Torvalds regs->regs[ 5] = 0; 7341da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->sf_sc; 7351da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 736d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 73781d103bfSRichard Weinberger regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; 7381da177e4SLinus Torvalds 739722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 7401da177e4SLinus Torvalds current->comm, current->pid, 741722bb63dSFranck Bui-Huu frame, regs->cp0_epc, regs->regs[31]); 7427b3e2fc8SRalf Baechle return 0; 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds #endif 7451da177e4SLinus Torvalds 74681d103bfSRichard Weinberger static int setup_rt_frame(void *sig_return, struct ksignal *ksig, 74781d103bfSRichard Weinberger struct pt_regs *regs, sigset_t *set) 7481da177e4SLinus Torvalds { 7499bbf28a3SAtsushi Nemoto struct rt_sigframe __user *frame; 7501da177e4SLinus Torvalds int err = 0; 7511da177e4SLinus Torvalds 7527c4f5635SRichard Weinberger frame = get_sigframe(ksig, regs, sizeof(*frame)); 75396d4f267SLinus Torvalds if (!access_ok(frame, sizeof (*frame))) 75481d103bfSRichard Weinberger return -EFAULT; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds /* Create siginfo. */ 75781d103bfSRichard Weinberger err |= copy_siginfo_to_user(&frame->rs_info, &ksig->info); 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds /* Create the ucontext. */ 7601da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 7615665a0acSAtsushi Nemoto err |= __put_user(NULL, &frame->rs_uc.uc_link); 762ea536ad4SAl Viro err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); 7631da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 7641da177e4SLinus Torvalds err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds if (err) 76781d103bfSRichard Weinberger return -EFAULT; 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds /* 7701da177e4SLinus Torvalds * Arguments to signal handler: 7711da177e4SLinus Torvalds * 7721da177e4SLinus Torvalds * a0 = signal number 7731da177e4SLinus Torvalds * a1 = 0 (should be cause) 7741da177e4SLinus Torvalds * a2 = pointer to ucontext 7751da177e4SLinus Torvalds * 7761da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 7771da177e4SLinus Torvalds * the struct rt_sigframe. 7781da177e4SLinus Torvalds */ 77981d103bfSRichard Weinberger regs->regs[ 4] = ksig->sig; 7801da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 7811da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 7821da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 783d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 78481d103bfSRichard Weinberger regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; 7851da177e4SLinus Torvalds 786722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 7871da177e4SLinus Torvalds current->comm, current->pid, 7881da177e4SLinus Torvalds frame, regs->cp0_epc, regs->regs[31]); 789722bb63dSFranck Bui-Huu 7907b3e2fc8SRalf Baechle return 0; 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds 793151fd6acSRalf Baechle struct mips_abi mips_abi = { 794151fd6acSRalf Baechle #ifdef CONFIG_TRAD_SIGNALS 795151fd6acSRalf Baechle .setup_frame = setup_frame, 796151fd6acSRalf Baechle #endif 797151fd6acSRalf Baechle .setup_rt_frame = setup_rt_frame, 79877856100SPaul Burton .restart = __NR_restart_syscall, 79977856100SPaul Burton 80077856100SPaul Burton .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), 80177856100SPaul Burton .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), 80277856100SPaul Burton .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), 803ebb5e78cSAlex Smith 804ebb5e78cSAlex Smith .vdso = &vdso_image, 805151fd6acSRalf Baechle }; 806151fd6acSRalf Baechle 80781d103bfSRichard Weinberger static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) 8081da177e4SLinus Torvalds { 809b7f9a11aSAl Viro sigset_t *oldset = sigmask_to_save(); 810129bc8f7SRalf Baechle int ret; 811d814c28cSDavid Daney struct mips_abi *abi = current->thread.abi; 812d814c28cSDavid Daney void *vdso = current->mm->context.vdso; 813129bc8f7SRalf Baechle 814432c6bacSPaul Burton /* 815432c6bacSPaul Burton * If we were emulating a delay slot instruction, exit that frame such 816432c6bacSPaul Burton * that addresses in the sigframe are as expected for userland and we 817432c6bacSPaul Burton * don't have a problem if we reuse the thread's frame for an 818432c6bacSPaul Burton * instruction within the signal handler. 819432c6bacSPaul Burton */ 820432c6bacSPaul Burton dsemul_thread_rollback(regs); 821432c6bacSPaul Burton 8228f5a00ebSAl Viro if (regs->regs[0]) { 8238f5a00ebSAl Viro switch(regs->regs[2]) { 8241da177e4SLinus Torvalds case ERESTART_RESTARTBLOCK: 8251da177e4SLinus Torvalds case ERESTARTNOHAND: 8261da177e4SLinus Torvalds regs->regs[2] = EINTR; 8271da177e4SLinus Torvalds break; 8281da177e4SLinus Torvalds case ERESTARTSYS: 82981d103bfSRichard Weinberger if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { 8301da177e4SLinus Torvalds regs->regs[2] = EINTR; 8311da177e4SLinus Torvalds break; 8321da177e4SLinus Torvalds } 833c9b02990SLiangliang Huang fallthrough; 8348f5a00ebSAl Viro case ERESTARTNOINTR: 8351da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 8368f5a00ebSAl Viro regs->regs[2] = regs->regs[0]; 8378f5a00ebSAl Viro regs->cp0_epc -= 4; 8381da177e4SLinus Torvalds } 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds regs->regs[0] = 0; /* Don't deal with this again. */ 8418f5a00ebSAl Viro } 8421da177e4SLinus Torvalds 843662d855cSPaul Burton rseq_signal_deliver(ksig, regs); 8449ea141adSPaul Burton 8457939469dSLeonid Yegoshin if (sig_uses_siginfo(&ksig->ka, abi)) 846ebb5e78cSAlex Smith ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn, 84781d103bfSRichard Weinberger ksig, regs, oldset); 8481da177e4SLinus Torvalds else 849ebb5e78cSAlex Smith ret = abi->setup_frame(vdso + abi->vdso->off_sigreturn, 850ebb5e78cSAlex Smith ksig, regs, oldset); 8511da177e4SLinus Torvalds 85281d103bfSRichard Weinberger signal_setup_done(ret, ksig, 0); 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds 855151fd6acSRalf Baechle static void do_signal(struct pt_regs *regs) 8561da177e4SLinus Torvalds { 85781d103bfSRichard Weinberger struct ksignal ksig; 8581da177e4SLinus Torvalds 85981d103bfSRichard Weinberger if (get_signal(&ksig)) { 8607b3e2fc8SRalf Baechle /* Whee! Actually deliver the signal. */ 86181d103bfSRichard Weinberger handle_signal(&ksig, regs); 86245887e12SRalf Baechle return; 8637b3e2fc8SRalf Baechle } 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds if (regs->regs[0]) { 8669ec9b5acSRalf Baechle switch (regs->regs[2]) { 8679ec9b5acSRalf Baechle case ERESTARTNOHAND: 8689ec9b5acSRalf Baechle case ERESTARTSYS: 8699ec9b5acSRalf Baechle case ERESTARTNOINTR: 8708f5a00ebSAl Viro regs->regs[2] = regs->regs[0]; 8711da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 8728f5a00ebSAl Viro regs->cp0_epc -= 4; 8739ec9b5acSRalf Baechle break; 8749ec9b5acSRalf Baechle 8759ec9b5acSRalf Baechle case ERESTART_RESTARTBLOCK: 876151fd6acSRalf Baechle regs->regs[2] = current->thread.abi->restart; 8771da177e4SLinus Torvalds regs->regs[7] = regs->regs[26]; 8781da177e4SLinus Torvalds regs->cp0_epc -= 4; 8799ec9b5acSRalf Baechle break; 8801da177e4SLinus Torvalds } 88113fdd31aSRalf Baechle regs->regs[0] = 0; /* Don't deal with this again. */ 8821da177e4SLinus Torvalds } 8837b3e2fc8SRalf Baechle 8847b3e2fc8SRalf Baechle /* 8857b3e2fc8SRalf Baechle * If there's no signal to deliver, we just put the saved sigmask 8867b3e2fc8SRalf Baechle * back 8877b3e2fc8SRalf Baechle */ 88851a7b448SAl Viro restore_saved_sigmask(); 8891da177e4SLinus Torvalds } 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds /* 8921da177e4SLinus Torvalds * notification of userspace execution resumption 8937b3e2fc8SRalf Baechle * - triggered by the TIF_WORK_MASK flags 8941da177e4SLinus Torvalds */ 8957b3e2fc8SRalf Baechle asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, 8961da177e4SLinus Torvalds __u32 thread_info_flags) 8971da177e4SLinus Torvalds { 8981f717929SRalf Baechle local_irq_enable(); 8991f717929SRalf Baechle 900c3fc5cd5SRalf Baechle user_exit(); 901c3fc5cd5SRalf Baechle 90240e084a5SRalf Baechle if (thread_info_flags & _TIF_UPROBE) 90340e084a5SRalf Baechle uprobe_notify_resume(regs); 90440e084a5SRalf Baechle 9051da177e4SLinus Torvalds /* deal with pending signal delivery */ 9066fd84c08SAl Viro if (thread_info_flags & _TIF_SIGPENDING) 907151fd6acSRalf Baechle do_signal(regs); 908d0420c83SDavid Howells 909d0420c83SDavid Howells if (thread_info_flags & _TIF_NOTIFY_RESUME) { 910d0420c83SDavid Howells clear_thread_flag(TIF_NOTIFY_RESUME); 911d0420c83SDavid Howells tracehook_notify_resume(regs); 912662d855cSPaul Burton rseq_handle_notify_resume(NULL, regs); 913d0420c83SDavid Howells } 914c3fc5cd5SRalf Baechle 915c3fc5cd5SRalf Baechle user_enter(); 9161da177e4SLinus Torvalds } 917137f6f3eSRalf Baechle 9184eec81d7SPaul Burton #if defined(CONFIG_SMP) && defined(CONFIG_MIPS_FP_SUPPORT) 9192db9ca0aSPaul Burton static int smp_save_fp_context(void __user *sc) 920137f6f3eSRalf Baechle { 921137f6f3eSRalf Baechle return raw_cpu_has_fpu 9222db9ca0aSPaul Burton ? save_hw_fp_context(sc) 923b2ead528SPaul Burton : copy_fp_to_sigcontext(sc); 924137f6f3eSRalf Baechle } 925137f6f3eSRalf Baechle 9262db9ca0aSPaul Burton static int smp_restore_fp_context(void __user *sc) 927137f6f3eSRalf Baechle { 928137f6f3eSRalf Baechle return raw_cpu_has_fpu 9292db9ca0aSPaul Burton ? restore_hw_fp_context(sc) 930b2ead528SPaul Burton : copy_fp_from_sigcontext(sc); 931137f6f3eSRalf Baechle } 932137f6f3eSRalf Baechle #endif 933137f6f3eSRalf Baechle 934137f6f3eSRalf Baechle static int signal_setup(void) 935137f6f3eSRalf Baechle { 936f1fe2d21SPaul Burton /* 937f1fe2d21SPaul Burton * The offset from sigcontext to extended context should be the same 938f1fe2d21SPaul Burton * regardless of the type of signal, such that userland can always know 939f1fe2d21SPaul Burton * where to look if it wishes to find the extended context structures. 940f1fe2d21SPaul Burton */ 941f1fe2d21SPaul Burton BUILD_BUG_ON((offsetof(struct sigframe, sf_extcontext) - 942f1fe2d21SPaul Burton offsetof(struct sigframe, sf_sc)) != 943f1fe2d21SPaul Burton (offsetof(struct rt_sigframe, rs_uc.uc_extcontext) - 944f1fe2d21SPaul Burton offsetof(struct rt_sigframe, rs_uc.uc_mcontext))); 945f1fe2d21SPaul Burton 9464eec81d7SPaul Burton #if defined(CONFIG_SMP) && defined(CONFIG_MIPS_FP_SUPPORT) 947137f6f3eSRalf Baechle /* For now just do the cpu_has_fpu check when the functions are invoked */ 948137f6f3eSRalf Baechle save_fp_context = smp_save_fp_context; 949137f6f3eSRalf Baechle restore_fp_context = smp_restore_fp_context; 950137f6f3eSRalf Baechle #else 951137f6f3eSRalf Baechle if (cpu_has_fpu) { 9522db9ca0aSPaul Burton save_fp_context = save_hw_fp_context; 9532db9ca0aSPaul Burton restore_fp_context = restore_hw_fp_context; 954137f6f3eSRalf Baechle } else { 95514fa12dfSPaul Burton save_fp_context = copy_fp_to_sigcontext; 95614fa12dfSPaul Burton restore_fp_context = copy_fp_from_sigcontext; 957137f6f3eSRalf Baechle } 958ca750649SLeonid Yegoshin #endif /* CONFIG_SMP */ 959137f6f3eSRalf Baechle 960137f6f3eSRalf Baechle return 0; 961137f6f3eSRalf Baechle } 962137f6f3eSRalf Baechle 963137f6f3eSRalf Baechle arch_initcall(signal_setup); 964