* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. [not found] <S20038814AbXBEQMb/20070205161231Z+24864@ftp.linux-mips.org> @ 2007-02-07 4:38 ` Atsushi Nemoto 2007-02-07 11:09 ` Ralf Baechle 0 siblings, 1 reply; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-07 4:38 UTC (permalink / raw) To: linux-mips On Mon, 05 Feb 2007 16:12:26 +0000, linux-mips@linux-mips.org wrote: > Author: Chris Dearman <chris@mips.com> Thu Feb 1 19:54:13 2007 +0000 > Comitter: Ralf Baechle <ralf@linux-mips.org> Mon Feb 5 15:56:18 2007 +0000 > Commit: a9e080c2c615bc4e9d9987330c0be35ea5226eed > Gitweb: http://www.linux-mips.org/g/linux/a9e080c2 > Branch: master > > Signed-off-by: Chris Dearman <chris@mips.com> > Signed-off-by: Ralf Baechle <ralf@linux-mips.org> > > --- > > arch/mips/kernel/r4k_fpu.S | 16 ++++++++++++++++ > 1 files changed, 16 insertions(+), 0 deletions(-) r2300_fpu.S and r6000_fpu.S should be fixed too? Also, fpu_emulator_restore_context() should check FCSR too? (it should not harm FPU-less CPU, but on MIPS_MT, FCSR value restored by fpu emulator might be used for real FPU, right?) --- Atsushi Nemoto ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-07 4:38 ` [MIPS] Check FCSR for pending interrupts before restoring from a context Atsushi Nemoto @ 2007-02-07 11:09 ` Ralf Baechle 2007-02-07 16:22 ` Atsushi Nemoto 0 siblings, 1 reply; 14+ messages in thread From: Ralf Baechle @ 2007-02-07 11:09 UTC (permalink / raw) To: Atsushi Nemoto; +Cc: linux-mips On Wed, Feb 07, 2007 at 01:38:09PM +0900, Atsushi Nemoto wrote: > > arch/mips/kernel/r4k_fpu.S | 16 ++++++++++++++++ > > 1 files changed, 16 insertions(+), 0 deletions(-) > > r2300_fpu.S and r6000_fpu.S should be fixed too? > > Also, fpu_emulator_restore_context() should check FCSR too? (it should > not harm FPU-less CPU, but on MIPS_MT, FCSR value restored by fpu > emulator might be used for real FPU, right?) Correct in all points. Ralf ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-07 11:09 ` Ralf Baechle @ 2007-02-07 16:22 ` Atsushi Nemoto 2007-02-07 17:29 ` Maciej W. Rozycki 0 siblings, 1 reply; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-07 16:22 UTC (permalink / raw) To: ralf; +Cc: linux-mips On Wed, 7 Feb 2007 11:09:29 +0000, Ralf Baechle <ralf@linux-mips.org> wrote: > > r2300_fpu.S and r6000_fpu.S should be fixed too? > > > > Also, fpu_emulator_restore_context() should check FCSR too? (it should > > not harm FPU-less CPU, but on MIPS_MT, FCSR value restored by fpu > > emulator might be used for real FPU, right?) > > Correct in all points. If the format of FCSR was common to all CPU (I hope so), we can do check it in caller of fp_restore_context(), in C language. BTW, why R6000 does not use r4k_fpu.S? --- Atsushi Nemoto ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-07 16:22 ` Atsushi Nemoto @ 2007-02-07 17:29 ` Maciej W. Rozycki 2007-02-08 3:02 ` Atsushi Nemoto 0 siblings, 1 reply; 14+ messages in thread From: Maciej W. Rozycki @ 2007-02-07 17:29 UTC (permalink / raw) To: Atsushi Nemoto; +Cc: ralf, linux-mips On Thu, 8 Feb 2007, Atsushi Nemoto wrote: > If the format of FCSR was common to all CPU (I hope so), we can do > check it in caller of fp_restore_context(), in C language. The R3010, etc. use bits 23 and 17:0 the same way as the R4000 and MIPS architecture processors do. The other bits are unused and hardwired to zeroes. Maciej ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-07 17:29 ` Maciej W. Rozycki @ 2007-02-08 3:02 ` Atsushi Nemoto 2007-02-08 15:23 ` Atsushi Nemoto 0 siblings, 1 reply; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-08 3:02 UTC (permalink / raw) To: macro; +Cc: ralf, linux-mips On Wed, 7 Feb 2007 17:29:02 +0000 (GMT), "Maciej W. Rozycki" <macro@linux-mips.org> wrote: > > If the format of FCSR was common to all CPU (I hope so), we can do > > check it in caller of fp_restore_context(), in C language. > > The R3010, etc. use bits 23 and 17:0 the same way as the R4000 and MIPS > architecture processors do. The other bits are unused and hardwired to > zeroes. So we can do it in C, but it will conflicts with Franck's signal cleanup patchset. I hope his patchset applied first. Also I wonder SIGSEGV is correct behavior on this case. SIGFPE? --- Atsushi Nemoto ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-08 3:02 ` Atsushi Nemoto @ 2007-02-08 15:23 ` Atsushi Nemoto 2007-02-08 16:30 ` Franck Bui-Huu 0 siblings, 1 reply; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-08 15:23 UTC (permalink / raw) To: linux-mips; +Cc: ralf, macro, vagabon.xyz On Thu, 08 Feb 2007 12:02:19 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote: > So we can do it in C, but it will conflicts with Franck's signal > cleanup patchset. I hope his patchset applied first. > > Also I wonder SIGSEGV is correct behavior on this case. SIGFPE? And I found that if signal handler set FPU_CSR_UNI_X, kernel complains "FP exception in kernel code" ... Here is a first cut. Changes in r4k_fpu.S can be reverted, and after Franck's patchset applied, this patch can be a bit smaller. Please review. Note that calling __get_user(), __put_user() might lose FPU ownership. But restore_fp_context() already has this breakage. I already sent two alternative patches to fix this longstanding issue ("[PATCH] rewrite restore_fp_context/save_fp_context" and "[PATCH 2/3] Allow CpU exception in kernel partially"). diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index b1f09d5..0811298 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -66,6 +66,38 @@ out: } static inline int +fpcsr_pending(unsigned int __user *fpcsr) +{ + int err, sig = 0; + unsigned int csr, enabled; + + err = __get_user(csr, fpcsr); + enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); + /* + * If the signal handler set some FPU exceptions, clear it and + * send SIGFPE. + */ + if (csr & enabled) { + csr &= ~enabled; + err |= __put_user(csr, fpcsr); + sig = SIGFPE; + } + return err ?: sig; +} + +static inline int +check_and_restore_fp_context(struct sigcontext __user *sc) +{ + int err, sig; + + err = sig = fpcsr_pending(&sc->sc_fpc_csr); + if (err > 0) + err = 0; + err |= restore_fp_context(sc); + return err ?: sig; +} + +static inline int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int used_math; @@ -112,7 +144,8 @@ restore_sigcontext(struct pt_regs *regs, if (used_math()) { /* restore fpu context if we have used it before */ own_fpu(); - err |= restore_fp_context(sc); + if (!err) + err = check_and_restore_fp_context(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9a44053..31d8ec0 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -190,6 +190,7 @@ _sys_sigreturn(nabi_no_regargs struct pt { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -203,8 +204,12 @@ _sys_sigreturn(nabi_no_regargs struct pt recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->sf_sc)) + sig = restore_sigcontext(®s, &frame->sf_sc); goto badframe; + if (sig < 0) + goto badframe; + else if (sig) + force_sig(sig, current); /* * Don't let your children do this ... @@ -228,6 +233,7 @@ _sys_rt_sigreturn(nabi_no_regargs struct struct rt_sigframe __user *frame; sigset_t set; stack_t st; + int sig; frame = (struct rt_sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -241,8 +247,11 @@ _sys_rt_sigreturn(nabi_no_regargs struct recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) goto badframe; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index c86a5dd..51eb21d 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -326,6 +326,38 @@ asmlinkage int sys32_sigaltstack(nabi_no return ret; } +static inline int +fpcsr_pending(unsigned int __user *fpcsr) +{ + int err, sig = 0; + unsigned int csr, enabled; + + err = __get_user(csr, fpcsr); + enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); + /* + * If the signal handler set some FPU exceptions, clear it and + * send SIGFPE. + */ + if (csr & enabled) { + csr &= ~enabled; + err |= __put_user(csr, fpcsr); + sig = SIGFPE; + } + return err ?: sig; +} + +static inline int +check_and_restore_fp_context32(struct sigcontext32 __user *sc) +{ + int err, sig; + + sig = fpcsr_pending(&sc->sc_fpc_csr); + if (sig < 0) + err = sig; + err |= restore_fp_context32(sc); + return err ?: sig; +} + static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { u32 used_math; @@ -372,7 +404,8 @@ static int restore_sigcontext32(struct p 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_context(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); @@ -469,6 +502,7 @@ _sys32_sigreturn(nabi_no_regargs struct { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -482,8 +516,11 @@ _sys32_sigreturn(nabi_no_regargs struct 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 ... ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-08 15:23 ` Atsushi Nemoto @ 2007-02-08 16:30 ` Franck Bui-Huu 2007-02-08 16:54 ` Atsushi Nemoto 2007-02-08 17:03 ` Atsushi Nemoto 0 siblings, 2 replies; 14+ messages in thread From: Franck Bui-Huu @ 2007-02-08 16:30 UTC (permalink / raw) To: Atsushi Nemoto; +Cc: linux-mips, ralf, macro On 2/8/07, Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote: > On Thu, 08 Feb 2007 12:02:19 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote: > Here is a first cut. Changes in r4k_fpu.S can be reverted, and after > Franck's patchset applied, this patch can be a bit smaller. Please > review. > yes this's going to conflict a lot with the patchset I sent... [snip] > +static inline int > restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) > { > unsigned int used_math; > @@ -112,7 +144,8 @@ restore_sigcontext(struct pt_regs *regs, > if (used_math()) { sorry for the stupid question but I don't know fpu code...Here used_math() function is used as condition whereas used_math local is already defined. Are we sure we want to use the function here ? -- Franck ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-08 16:30 ` Franck Bui-Huu @ 2007-02-08 16:54 ` Atsushi Nemoto 2007-02-09 4:03 ` Atsushi Nemoto 2007-02-08 17:03 ` Atsushi Nemoto 1 sibling, 1 reply; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-08 16:54 UTC (permalink / raw) To: vagabon.xyz; +Cc: linux-mips, ralf, macro On Thu, 8 Feb 2007 17:30:29 +0100, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote: > yes this's going to conflict a lot with the patchset I sent... Here is a patch can be applied on top of your patchset. Subject: Check FCSR for pending interrupts, alternative version The commit 6d6671066a311703bca1b91645bb1e04cc983387 is incomplete and misses non-r4k CPUs. This patch reverts the commit and fixes in other way. * Do FCSR checking in caller of restore_fp_context. * Send SIGFPE if the signal handler set any FPU exception bits. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> --- arch/mips/kernel/r4k_fpu.S | 16 ------------ arch/mips/kernel/signal-common.h | 3 ++ arch/mips/kernel/signal.c | 46 ++++++++++++++++++++++++++++++++++--- arch/mips/kernel/signal32.c | 27 +++++++++++++++++++-- 4 files changed, 70 insertions(+), 22 deletions(-) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 59c1577..dbd42ad 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -114,14 +114,6 @@ LEAF(_save_fp_context32) */ LEAF(_restore_fp_context) EX lw t0, SC_FPC_CSR(a0) - - /* Fail if the CSR has exceptions pending */ - srl t1, t0, 5 - and t1, t0 - andi t1, 0x1f << 7 - bnez t1, fault - nop - #ifdef CONFIG_64BIT EX ldc1 $f1, SC_FPREGS+8(a0) EX ldc1 $f3, SC_FPREGS+24(a0) @@ -165,14 +157,6 @@ LEAF(_restore_fp_context) LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ EX lw t0, SC32_FPC_CSR(a0) - - /* Fail if the CSR has exceptions pending */ - srl t1, t0, 5 - and t1, t0 - andi t1, 0x1f << 7 - bnez t1, fault - nop - EX ldc1 $f0, SC32_FPREGS+0(a0) EX ldc1 $f2, SC32_FPREGS+16(a0) EX ldc1 $f4, SC32_FPREGS+32(a0) diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 9a8abd6..1f24288 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -61,4 +61,7 @@ extern void __user *get_sigframe(struct */ extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); +/* Check and clear pending FPU exceptions in saved CSR */ +extern int fpcsr_pending(unsigned int __user *fpcsr); + #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 8dfb7b1..d7531d5 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -103,6 +103,37 @@ int setup_sigcontext(struct pt_regs *reg return err; } +int fpcsr_pending(unsigned int __user *fpcsr) +{ + int err, sig = 0; + unsigned int csr, enabled; + + err = __get_user(csr, fpcsr); + enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); + /* + * If the signal handler set some FPU exceptions, clear it and + * send SIGFPE. + */ + if (csr & enabled) { + csr &= ~enabled; + err |= __put_user(csr, fpcsr); + sig = SIGFPE; + } + return err ?: sig; +} + +static int +check_and_restore_fp_context(struct sigcontext __user *sc) +{ + int err, sig; + + err = sig = fpcsr_pending(&sc->sc_fpc_csr); + if (err > 0) + err = 0; + err |= restore_fp_context(sc); + return err ?: sig; +} + int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int used_math; @@ -137,7 +168,8 @@ int restore_sigcontext(struct pt_regs *r if (used_math()) { /* restore fpu context if we have used it before */ own_fpu(); - err |= restore_fp_context(sc); + if (!err) + err = check_and_restore_fp_context(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); @@ -307,6 +339,7 @@ asmlinkage void sys_sigreturn(nabi_no_re { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -320,8 +353,11 @@ asmlinkage void sys_sigreturn(nabi_no_re recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->sf_sc)) + sig = restore_sigcontext(®s, &frame->sf_sc); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); /* * Don't let your children do this ... @@ -343,6 +379,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no struct rt_sigframe __user *frame; sigset_t set; stack_t st; + int sig; frame = (struct rt_sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -356,8 +393,11 @@ asmlinkage void sys_rt_sigreturn(nabi_no recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) goto badframe; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 183fc7e..c37ff65 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -207,6 +207,18 @@ static int setup_sigcontext32(struct pt_ return err; } +static int +check_and_restore_fp_context32(struct sigcontext32 __user *sc) +{ + int err, sig; + + sig = fpcsr_pending(&sc->sc_fpc_csr); + if (sig < 0) + err = sig; + err |= restore_fp_context32(sc); + return err ?: sig; +} + static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { @@ -242,7 +254,8 @@ static int restore_sigcontext32(struct p 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(); @@ -495,6 +508,7 @@ asmlinkage void sys32_sigreturn(nabi_no_ { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -508,8 +522,11 @@ asmlinkage void sys32_sigreturn(nabi_no_ 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 ... @@ -532,6 +549,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_ 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))) @@ -545,8 +563,11 @@ asmlinkage void sys32_rt_sigreturn(nabi_ 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)) ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-08 16:54 ` Atsushi Nemoto @ 2007-02-09 4:03 ` Atsushi Nemoto 2007-02-14 8:04 ` Atsushi Nemoto 0 siblings, 1 reply; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-09 4:03 UTC (permalink / raw) To: vagabon.xyz; +Cc: linux-mips, ralf, macro On Fri, 09 Feb 2007 01:54:05 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote: > Here is a patch can be applied on top of your patchset. I missed n32 part. Revised. Subject: Check FCSR for pending interrupts, alternative version The commit 6d6671066a311703bca1b91645bb1e04cc983387 is incomplete and misses non-r4k CPUs. This patch reverts the commit and fixes in other way. * Do FCSR checking in caller of restore_fp_context. * Send SIGFPE if the signal handler set any FPU exception bits. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> --- arch/mips/kernel/r4k_fpu.S | 16 ------------ arch/mips/kernel/signal-common.h | 3 ++ arch/mips/kernel/signal.c | 46 ++++++++++++++++++++++++++++++++++--- arch/mips/kernel/signal32.c | 27 +++++++++++++++++++-- arch/mips/kernel/signal_n32.c | 6 ++++ 5 files changed, 75 insertions(+), 23 deletions(-) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 59c1577..dbd42ad 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -114,14 +114,6 @@ LEAF(_save_fp_context32) */ LEAF(_restore_fp_context) EX lw t0, SC_FPC_CSR(a0) - - /* Fail if the CSR has exceptions pending */ - srl t1, t0, 5 - and t1, t0 - andi t1, 0x1f << 7 - bnez t1, fault - nop - #ifdef CONFIG_64BIT EX ldc1 $f1, SC_FPREGS+8(a0) EX ldc1 $f3, SC_FPREGS+24(a0) @@ -165,14 +157,6 @@ LEAF(_restore_fp_context) LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ EX lw t0, SC32_FPC_CSR(a0) - - /* Fail if the CSR has exceptions pending */ - srl t1, t0, 5 - and t1, t0 - andi t1, 0x1f << 7 - bnez t1, fault - nop - EX ldc1 $f0, SC32_FPREGS+0(a0) EX ldc1 $f2, SC32_FPREGS+16(a0) EX ldc1 $f4, SC32_FPREGS+32(a0) diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 9a8abd6..1f24288 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -61,4 +61,7 @@ extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, */ extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); +/* Check and clear pending FPU exceptions in saved CSR */ +extern int fpcsr_pending(unsigned int __user *fpcsr); + #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 8dfb7b1..d7531d5 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -103,6 +103,37 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) return err; } +int fpcsr_pending(unsigned int __user *fpcsr) +{ + int err, sig = 0; + unsigned int csr, enabled; + + err = __get_user(csr, fpcsr); + enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); + /* + * If the signal handler set some FPU exceptions, clear it and + * send SIGFPE. + */ + if (csr & enabled) { + csr &= ~enabled; + err |= __put_user(csr, fpcsr); + sig = SIGFPE; + } + return err ?: sig; +} + +static int +check_and_restore_fp_context(struct sigcontext __user *sc) +{ + int err, sig; + + err = sig = fpcsr_pending(&sc->sc_fpc_csr); + if (err > 0) + err = 0; + err |= restore_fp_context(sc); + return err ?: sig; +} + int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int used_math; @@ -137,7 +168,8 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) if (used_math()) { /* restore fpu context if we have used it before */ own_fpu(); - err |= restore_fp_context(sc); + if (!err) + err = check_and_restore_fp_context(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); @@ -307,6 +339,7 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -320,8 +353,11 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->sf_sc)) + sig = restore_sigcontext(®s, &frame->sf_sc); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); /* * Don't let your children do this ... @@ -343,6 +379,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) struct rt_sigframe __user *frame; sigset_t set; stack_t st; + int sig; frame = (struct rt_sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -356,8 +393,11 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) goto badframe; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 183fc7e..c37ff65 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -207,6 +207,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; + + sig = fpcsr_pending(&sc->sc_fpc_csr); + if (sig < 0) + err = sig; + err |= restore_fp_context32(sc); + return err ?: sig; +} + static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { @@ -242,7 +254,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(); @@ -495,6 +508,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -508,8 +522,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 ... @@ -532,6 +549,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))) @@ -545,8 +563,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)) diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 57456e6..01c6627 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -123,6 +123,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) sigset_t set; stack_t st; s32 sp; + int sig; frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -136,8 +137,11 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext(®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)) ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-09 4:03 ` Atsushi Nemoto @ 2007-02-14 8:04 ` Atsushi Nemoto 2007-02-14 8:34 ` Franck Bui-Huu 2007-02-15 18:02 ` Atsushi Nemoto 0 siblings, 2 replies; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-14 8:04 UTC (permalink / raw) To: vagabon.xyz; +Cc: linux-mips, ralf, macro Revised again. Fix check_and_restore_fp_context32 and rediff against current git. Subject: Check FCSR for pending interrupts, alternative version The commit 6d6671066a311703bca1b91645bb1e04cc983387 is incomplete and misses non-r4k CPUs. This patch reverts the commit and fixes in other way. * Do FCSR checking in caller of restore_fp_context. * Send SIGFPE if the signal handler set any FPU exception bits. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> --- arch/mips/kernel/r4k_fpu.S | 16 ------------ arch/mips/kernel/signal-common.h | 3 ++ arch/mips/kernel/signal.c | 46 ++++++++++++++++++++++++++++++++++--- arch/mips/kernel/signal32.c | 27 +++++++++++++++++++-- arch/mips/kernel/signal_n32.c | 6 ++++ 5 files changed, 75 insertions(+), 23 deletions(-) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 59c1577..dbd42ad 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -114,14 +114,6 @@ LEAF(_save_fp_context32) */ LEAF(_restore_fp_context) EX lw t0, SC_FPC_CSR(a0) - - /* Fail if the CSR has exceptions pending */ - srl t1, t0, 5 - and t1, t0 - andi t1, 0x1f << 7 - bnez t1, fault - nop - #ifdef CONFIG_64BIT EX ldc1 $f1, SC_FPREGS+8(a0) EX ldc1 $f3, SC_FPREGS+24(a0) @@ -165,14 +157,6 @@ LEAF(_restore_fp_context) LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ EX lw t0, SC32_FPC_CSR(a0) - - /* Fail if the CSR has exceptions pending */ - srl t1, t0, 5 - and t1, t0 - andi t1, 0x1f << 7 - bnez t1, fault - nop - EX ldc1 $f0, SC32_FPREGS+0(a0) EX ldc1 $f2, SC32_FPREGS+16(a0) EX ldc1 $f4, SC32_FPREGS+32(a0) diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index fdbdbdc..297dfcb 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -31,4 +31,7 @@ extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, */ extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); +/* Check and clear pending FPU exceptions in saved CSR */ +extern int fpcsr_pending(unsigned int __user *fpcsr); + #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index b2e9ab1..2420ed6 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -121,6 +121,37 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) return err; } +int fpcsr_pending(unsigned int __user *fpcsr) +{ + int err, sig = 0; + unsigned int csr, enabled; + + err = __get_user(csr, fpcsr); + enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); + /* + * If the signal handler set some FPU exceptions, clear it and + * send SIGFPE. + */ + if (csr & enabled) { + csr &= ~enabled; + err |= __put_user(csr, fpcsr); + sig = SIGFPE; + } + return err ?: sig; +} + +static int +check_and_restore_fp_context(struct sigcontext __user *sc) +{ + int err, sig; + + err = sig = fpcsr_pending(&sc->sc_fpc_csr); + if (err > 0) + err = 0; + err |= restore_fp_context(sc); + return err ?: sig; +} + int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int used_math; @@ -155,7 +186,8 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) if (used_math()) { /* restore fpu context if we have used it before */ own_fpu(); - err |= restore_fp_context(sc); + if (!err) + err = check_and_restore_fp_context(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); @@ -325,6 +357,7 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -338,8 +371,11 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->sf_sc)) + sig = restore_sigcontext(®s, &frame->sf_sc); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); /* * Don't let your children do this ... @@ -361,6 +397,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) struct rt_sigframe __user *frame; sigset_t set; stack_t st; + int sig; frame = (struct rt_sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -374,8 +411,11 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) goto badframe; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index dd4e518..813279d 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)) diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 7ca2a07..26ca944 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -126,6 +126,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) sigset_t set; stack_t st; s32 sp; + int sig; frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -139,8 +140,11 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext(®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)) ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-14 8:04 ` Atsushi Nemoto @ 2007-02-14 8:34 ` Franck Bui-Huu 2007-02-14 16:05 ` Atsushi Nemoto 2007-02-15 18:02 ` Atsushi Nemoto 1 sibling, 1 reply; 14+ messages in thread From: Franck Bui-Huu @ 2007-02-14 8:34 UTC (permalink / raw) To: Atsushi Nemoto; +Cc: linux-mips, ralf, macro Hi Atsushi, On 2/14/07, Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote: > Revised again. Fix check_and_restore_fp_context32 and rediff against > current git. > > > Subject: Check FCSR for pending interrupts, alternative version > [snip] > diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h > index fdbdbdc..297dfcb 100644 > --- a/arch/mips/kernel/signal-common.h > +++ b/arch/mips/kernel/signal-common.h > @@ -31,4 +31,7 @@ extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, > */ > extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); > > +/* Check and clear pending FPU exceptions in saved CSR */ > +extern int fpcsr_pending(unsigned int __user *fpcsr); > + Just my 2 cents: This looks like the wrong place for this fpu prototype. I mean shouldn't it belong to a fpu header file or something else ? -- Franck ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-14 8:34 ` Franck Bui-Huu @ 2007-02-14 16:05 ` Atsushi Nemoto 0 siblings, 0 replies; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-14 16:05 UTC (permalink / raw) To: vagabon.xyz; +Cc: linux-mips, ralf, macro On Wed, 14 Feb 2007 09:34:53 +0100, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote: > > +/* Check and clear pending FPU exceptions in saved CSR */ > > +extern int fpcsr_pending(unsigned int __user *fpcsr); > > + > > Just my 2 cents: This looks like the wrong place for this fpu > prototype. I mean shouldn't it belong to a fpu header file or > something else ? Well, this is a helper function for signal so signal-common.h is not so bad, I think. And adding to kernel/signal-common.h looks less intrusive than adding to include/asm-mips/fpu.h, in my impression. --- Atsushi Nemoto ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-14 8:04 ` Atsushi Nemoto 2007-02-14 8:34 ` Franck Bui-Huu @ 2007-02-15 18:02 ` Atsushi Nemoto 1 sibling, 0 replies; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-15 18:02 UTC (permalink / raw) To: vagabon.xyz; +Cc: linux-mips, ralf, macro On Wed, 14 Feb 2007 17:04:20 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> wrote: > Subject: Check FCSR for pending interrupts, alternative version > > The commit 6d6671066a311703bca1b91645bb1e04cc983387 is incomplete and > misses non-r4k CPUs. This patch reverts the commit and fixes in other > way. > > * Do FCSR checking in caller of restore_fp_context. > * Send SIGFPE if the signal handler set any FPU exception bits. And this is for 2.6.20-stable tree. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> --- arch/mips/kernel/r4k_fpu.S | 16 -------------- arch/mips/kernel/signal-common.h | 35 ++++++++++++++++++++++++++++++- arch/mips/kernel/signal.c | 12 +++++++++- arch/mips/kernel/signal32.c | 41 +++++++++++++++++++++++++++++++++++-- arch/mips/kernel/signal_n32.c | 6 ++++- 5 files changed, 88 insertions(+), 22 deletions(-) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 59c1577..dbd42ad 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -114,14 +114,6 @@ LEAF(_save_fp_context32) */ LEAF(_restore_fp_context) EX lw t0, SC_FPC_CSR(a0) - - /* Fail if the CSR has exceptions pending */ - srl t1, t0, 5 - and t1, t0 - andi t1, 0x1f << 7 - bnez t1, fault - nop - #ifdef CONFIG_64BIT EX ldc1 $f1, SC_FPREGS+8(a0) EX ldc1 $f3, SC_FPREGS+24(a0) @@ -165,14 +157,6 @@ LEAF(_restore_fp_context) LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ EX lw t0, SC32_FPC_CSR(a0) - - /* Fail if the CSR has exceptions pending */ - srl t1, t0, 5 - and t1, t0 - andi t1, 0x1f << 7 - bnez t1, fault - nop - EX ldc1 $f0, SC32_FPREGS+0(a0) EX ldc1 $f2, SC32_FPREGS+16(a0) EX ldc1 $f4, SC32_FPREGS+32(a0) diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index b1f09d5..0811298 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -66,6 +66,38 @@ out: } static inline int +fpcsr_pending(unsigned int __user *fpcsr) +{ + int err, sig = 0; + unsigned int csr, enabled; + + err = __get_user(csr, fpcsr); + enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); + /* + * If the signal handler set some FPU exceptions, clear it and + * send SIGFPE. + */ + if (csr & enabled) { + csr &= ~enabled; + err |= __put_user(csr, fpcsr); + sig = SIGFPE; + } + return err ?: sig; +} + +static inline int +check_and_restore_fp_context(struct sigcontext __user *sc) +{ + int err, sig; + + err = sig = fpcsr_pending(&sc->sc_fpc_csr); + if (err > 0) + err = 0; + err |= restore_fp_context(sc); + return err ?: sig; +} + +static inline int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int used_math; @@ -112,7 +144,8 @@ restore_sigcontext(struct pt_regs *regs, if (used_math()) { /* restore fpu context if we have used it before */ own_fpu(); - err |= restore_fp_context(sc); + if (!err) + err = check_and_restore_fp_context(sc); } else { /* signal handler may have used FPU. Give it up. */ lose_fpu(); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index b9d358e..c19408e 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -190,6 +190,7 @@ _sys_sigreturn(nabi_no_regargs struct pt { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -203,8 +204,11 @@ _sys_sigreturn(nabi_no_regargs struct pt recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->sf_sc)) + sig = restore_sigcontext(®s, &frame->sf_sc); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); /* * Don't let your children do this ... @@ -228,6 +232,7 @@ _sys_rt_sigreturn(nabi_no_regargs struct struct rt_sigframe __user *frame; sigset_t set; stack_t st; + int sig; frame = (struct rt_sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -241,8 +246,11 @@ _sys_rt_sigreturn(nabi_no_regargs struct recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); + if (sig < 0) goto badframe; + else if (sig) + force_sig(sig, current); if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) goto badframe; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 7464df4..80ac070 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -321,6 +321,38 @@ asmlinkage int sys32_sigaltstack(nabi_no return ret; } +static inline int +fpcsr_pending(unsigned int __user *fpcsr) +{ + int err, sig = 0; + unsigned int csr, enabled; + + err = __get_user(csr, fpcsr); + enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); + /* + * If the signal handler set some FPU exceptions, clear it and + * send SIGFPE. + */ + if (csr & enabled) { + csr &= ~enabled; + err |= __put_user(csr, fpcsr); + sig = SIGFPE; + } + return err ?: sig; +} + +static inline 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) { u32 used_math; @@ -367,7 +399,8 @@ static int restore_sigcontext32(struct p 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(); @@ -464,6 +497,7 @@ _sys32_sigreturn(nabi_no_regargs struct { struct sigframe __user *frame; sigset_t blocked; + int sig; frame = (struct sigframe __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -477,8 +511,11 @@ _sys32_sigreturn(nabi_no_regargs struct 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 ... diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index d6160c9..617edd9 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -123,6 +123,7 @@ _sysn32_rt_sigreturn(nabi_no_regargs str sigset_t set; stack_t st; s32 sp; + int sig; frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -136,8 +137,11 @@ _sysn32_rt_sigreturn(nabi_no_regargs str recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + sig = restore_sigcontext(®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)) ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [MIPS] Check FCSR for pending interrupts before restoring from a context. 2007-02-08 16:30 ` Franck Bui-Huu 2007-02-08 16:54 ` Atsushi Nemoto @ 2007-02-08 17:03 ` Atsushi Nemoto 1 sibling, 0 replies; 14+ messages in thread From: Atsushi Nemoto @ 2007-02-08 17:03 UTC (permalink / raw) To: vagabon.xyz; +Cc: linux-mips, ralf, macro On Thu, 8 Feb 2007 17:30:29 +0100, "Franck Bui-Huu" <vagabon.xyz@gmail.com> wrote: > > unsigned int used_math; > > @@ -112,7 +144,8 @@ restore_sigcontext(struct pt_regs *regs, > > if (used_math()) { > > sorry for the stupid question but I don't know fpu code...Here > used_math() function is used as condition whereas used_math local is > already defined. Are we sure we want to use the function here ? Well, used_math() returns condition which are set by preceeding conditional_used_math(). In this case the condition is used_math :) Maybe we can use the used_math variable here to optimize a bit. --- Atsushi Nemoto ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2007-02-15 18:03 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- [not found] <S20038814AbXBEQMb/20070205161231Z+24864@ftp.linux-mips.org> 2007-02-07 4:38 ` [MIPS] Check FCSR for pending interrupts before restoring from a context Atsushi Nemoto 2007-02-07 11:09 ` Ralf Baechle 2007-02-07 16:22 ` Atsushi Nemoto 2007-02-07 17:29 ` Maciej W. Rozycki 2007-02-08 3:02 ` Atsushi Nemoto 2007-02-08 15:23 ` Atsushi Nemoto 2007-02-08 16:30 ` Franck Bui-Huu 2007-02-08 16:54 ` Atsushi Nemoto 2007-02-09 4:03 ` Atsushi Nemoto 2007-02-14 8:04 ` Atsushi Nemoto 2007-02-14 8:34 ` Franck Bui-Huu 2007-02-14 16:05 ` Atsushi Nemoto 2007-02-15 18:02 ` Atsushi Nemoto 2007-02-08 17:03 ` Atsushi Nemoto
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.