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