aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r--arch/mips/kernel/signal32.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 19bbef001959..151fd2f0893a 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -181,6 +181,7 @@ static int setup_sigcontext32(struct pt_regs *regs,
181{ 181{
182 int err = 0; 182 int err = 0;
183 int i; 183 int i;
184 u32 used_math;
184 185
185 err |= __put_user(regs->cp0_epc, &sc->sc_pc); 186 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
186 187
@@ -200,26 +201,34 @@ static int setup_sigcontext32(struct pt_regs *regs,
200 err |= __put_user(mflo3(), &sc->sc_lo3); 201 err |= __put_user(mflo3(), &sc->sc_lo3);
201 } 202 }
202 203
203 err |= __put_user(!!used_math(), &sc->sc_used_math); 204 used_math = !!used_math();
205 err |= __put_user(used_math, &sc->sc_used_math);
204 206
205 if (used_math()) { 207 if (used_math) {
206 /* 208 /*
207 * Save FPU state to signal context. Signal handler 209 * Save FPU state to signal context. Signal handler
208 * will "inherit" current FPU state. 210 * will "inherit" current FPU state.
209 */ 211 */
210 preempt_disable(); 212 own_fpu(1);
211 213 enable_fp_in_kernel();
212 if (!is_fpu_owner()) {
213 own_fpu();
214 restore_fp(current);
215 }
216 err |= save_fp_context32(sc); 214 err |= save_fp_context32(sc);
217 215 disable_fp_in_kernel();
218 preempt_enable();
219 } 216 }
220 return err; 217 return err;
221} 218}
222 219
220static int
221check_and_restore_fp_context32(struct sigcontext32 __user *sc)
222{
223 int err, sig;
224
225 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
226 if (err > 0)
227 err = 0;
228 err |= restore_fp_context32(sc);
229 return err ?: sig;
230}
231
223static int restore_sigcontext32(struct pt_regs *regs, 232static int restore_sigcontext32(struct pt_regs *regs,
224 struct sigcontext32 __user *sc) 233 struct sigcontext32 __user *sc)
225{ 234{
@@ -250,19 +259,18 @@ static int restore_sigcontext32(struct pt_regs *regs,
250 err |= __get_user(used_math, &sc->sc_used_math); 259 err |= __get_user(used_math, &sc->sc_used_math);
251 conditional_used_math(used_math); 260 conditional_used_math(used_math);
252 261
253 preempt_disable(); 262 if (used_math) {
254
255 if (used_math()) {
256 /* restore fpu context if we have used it before */ 263 /* restore fpu context if we have used it before */
257 own_fpu(); 264 own_fpu(0);
258 err |= restore_fp_context32(sc); 265 enable_fp_in_kernel();
266 if (!err)
267 err = check_and_restore_fp_context32(sc);
268 disable_fp_in_kernel();
259 } else { 269 } else {
260 /* signal handler may have used FPU. Give it up. */ 270 /* signal handler may have used FPU. Give it up. */
261 lose_fpu(); 271 lose_fpu(0);
262 } 272 }
263 273
264 preempt_enable();
265
266 return err; 274 return err;
267} 275}
268 276
@@ -508,6 +516,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
508{ 516{
509 struct sigframe32 __user *frame; 517 struct sigframe32 __user *frame;
510 sigset_t blocked; 518 sigset_t blocked;
519 int sig;
511 520
512 frame = (struct sigframe32 __user *) regs.regs[29]; 521 frame = (struct sigframe32 __user *) regs.regs[29];
513 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 522 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -521,8 +530,11 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
521 recalc_sigpending(); 530 recalc_sigpending();
522 spin_unlock_irq(&current->sighand->siglock); 531 spin_unlock_irq(&current->sighand->siglock);
523 532
524 if (restore_sigcontext32(&regs, &frame->sf_sc)) 533 sig = restore_sigcontext32(&regs, &frame->sf_sc);
534 if (sig < 0)
525 goto badframe; 535 goto badframe;
536 else if (sig)
537 force_sig(sig, current);
526 538
527 /* 539 /*
528 * Don't let your children do this ... 540 * Don't let your children do this ...
@@ -545,6 +557,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
545 sigset_t set; 557 sigset_t set;
546 stack_t st; 558 stack_t st;
547 s32 sp; 559 s32 sp;
560 int sig;
548 561
549 frame = (struct rt_sigframe32 __user *) regs.regs[29]; 562 frame = (struct rt_sigframe32 __user *) regs.regs[29];
550 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 563 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -558,8 +571,11 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
558 recalc_sigpending(); 571 recalc_sigpending();
559 spin_unlock_irq(&current->sighand->siglock); 572 spin_unlock_irq(&current->sighand->siglock);
560 573
561 if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext)) 574 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
575 if (sig < 0)
562 goto badframe; 576 goto badframe;
577 else if (sig)
578 force_sig(sig, current);
563 579
564 /* The ucontext contains a stack32_t, so we must convert! */ 580 /* The ucontext contains a stack32_t, so we must convert! */
565 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) 581 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))