diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2007-03-10 01:03:48 +0900 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-03-17 01:03:25 +0000 |
commit | c6a2f4679331206ef5d353fc9a6cda2fa4aef8c6 (patch) | |
tree | 9634ba2d5b6c6c97f4301b28088c68254201bf74 /arch/mips/kernel/signal32.c | |
parent | f1dbf8e718ef0ddb196a28bcc71925ac7da881af (diff) | |
download | blackbird-op-linux-c6a2f4679331206ef5d353fc9a6cda2fa4aef8c6.tar.gz blackbird-op-linux-c6a2f4679331206ef5d353fc9a6cda2fa4aef8c6.zip |
[MIPS] Check FCSR for pending interrupts, alternative version
Commit 6d6671066a311703bca1b91645bb1e04cc983387 is incomplete and misses
non-r4k CPUs. This patch reverts the commit and fixes in other way.
o Do FCSR checking in caller of restore_fp_context.
o Send SIGFPE if the signal handler set any FPU exception bits.
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r-- | arch/mips/kernel/signal32.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 19bbef001959..20013b6fe725 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -220,6 +220,18 @@ static int setup_sigcontext32(struct pt_regs *regs, return err; } +static int +check_and_restore_fp_context32(struct sigcontext32 __user *sc) +{ + int err, sig; + + err = sig = fpcsr_pending(&sc->sc_fpc_csr); + if (err > 0) + err = 0; + err |= restore_fp_context32(sc); + return err ?: sig; +} + static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { @@ -255,7 +267,8 @@ static int restore_sigcontext32(struct pt_regs *regs, if (used_math()) { /* restore fpu context if we have used it before */ own_fpu(); - err |= restore_fp_context32(sc); + if (!err) + err = check_and_restore_fp_context32(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); @@ -508,6 +521,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) { struct sigframe32 __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -521,8 +535,11 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext32(®s, &frame->sf_sc)) + sig = restore_sigcontext32(®s, &frame->sf_sc); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); /* * Don't let your children do this ... @@ -545,6 +562,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) sigset_t set; stack_t st; s32 sp; + int sig; frame = (struct rt_sigframe32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -558,8 +576,11 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); /* The ucontext contains a stack32_t, so we must convert! */ if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) |