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