diff options
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r-- | arch/mips/kernel/signal32.c | 56 |
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 | ||
220 | static int | ||
221 | check_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 | |||
223 | static int restore_sigcontext32(struct pt_regs *regs, | 232 | static 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(¤t->sighand->siglock); | 531 | spin_unlock_irq(¤t->sighand->siglock); |
523 | 532 | ||
524 | if (restore_sigcontext32(®s, &frame->sf_sc)) | 533 | sig = restore_sigcontext32(®s, &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(¤t->sighand->siglock); | 572 | spin_unlock_irq(¤t->sighand->siglock); |
560 | 573 | ||
561 | if (restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext)) | 574 | sig = restore_sigcontext32(®s, &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)) |