diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2007-03-09 11:03:48 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-03-16 21:03:25 -0400 |
commit | c6a2f4679331206ef5d353fc9a6cda2fa4aef8c6 (patch) | |
tree | 9634ba2d5b6c6c97f4301b28088c68254201bf74 /arch/mips | |
parent | f1dbf8e718ef0ddb196a28bcc71925ac7da881af (diff) |
[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')
-rw-r--r-- | arch/mips/kernel/r4k_fpu.S | 16 | ||||
-rw-r--r-- | arch/mips/kernel/signal-common.h | 3 | ||||
-rw-r--r-- | arch/mips/kernel/signal.c | 46 | ||||
-rw-r--r-- | arch/mips/kernel/signal32.c | 27 | ||||
-rw-r--r-- | 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 59c1577ecbb3..dbd42adc52ed 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S | |||
@@ -114,14 +114,6 @@ LEAF(_save_fp_context32) | |||
114 | */ | 114 | */ |
115 | LEAF(_restore_fp_context) | 115 | LEAF(_restore_fp_context) |
116 | EX lw t0, SC_FPC_CSR(a0) | 116 | EX lw t0, SC_FPC_CSR(a0) |
117 | |||
118 | /* Fail if the CSR has exceptions pending */ | ||
119 | srl t1, t0, 5 | ||
120 | and t1, t0 | ||
121 | andi t1, 0x1f << 7 | ||
122 | bnez t1, fault | ||
123 | nop | ||
124 | |||
125 | #ifdef CONFIG_64BIT | 117 | #ifdef CONFIG_64BIT |
126 | EX ldc1 $f1, SC_FPREGS+8(a0) | 118 | EX ldc1 $f1, SC_FPREGS+8(a0) |
127 | EX ldc1 $f3, SC_FPREGS+24(a0) | 119 | EX ldc1 $f3, SC_FPREGS+24(a0) |
@@ -165,14 +157,6 @@ LEAF(_restore_fp_context) | |||
165 | LEAF(_restore_fp_context32) | 157 | LEAF(_restore_fp_context32) |
166 | /* Restore an o32 sigcontext. */ | 158 | /* Restore an o32 sigcontext. */ |
167 | EX lw t0, SC32_FPC_CSR(a0) | 159 | EX lw t0, SC32_FPC_CSR(a0) |
168 | |||
169 | /* Fail if the CSR has exceptions pending */ | ||
170 | srl t1, t0, 5 | ||
171 | and t1, t0 | ||
172 | andi t1, 0x1f << 7 | ||
173 | bnez t1, fault | ||
174 | nop | ||
175 | |||
176 | EX ldc1 $f0, SC32_FPREGS+0(a0) | 160 | EX ldc1 $f0, SC32_FPREGS+0(a0) |
177 | EX ldc1 $f2, SC32_FPREGS+16(a0) | 161 | EX ldc1 $f2, SC32_FPREGS+16(a0) |
178 | EX ldc1 $f4, SC32_FPREGS+32(a0) | 162 | EX ldc1 $f4, SC32_FPREGS+32(a0) |
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index fdbdbdc65b54..297dfcb97524 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, | |||
31 | */ | 31 | */ |
32 | extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); | 32 | extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); |
33 | 33 | ||
34 | /* Check and clear pending FPU exceptions in saved CSR */ | ||
35 | extern int fpcsr_pending(unsigned int __user *fpcsr); | ||
36 | |||
34 | #endif /* __SIGNAL_COMMON_H */ | 37 | #endif /* __SIGNAL_COMMON_H */ |
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index f091786187a6..bf094fc4c7eb 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
@@ -124,6 +124,37 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
124 | return err; | 124 | return err; |
125 | } | 125 | } |
126 | 126 | ||
127 | int fpcsr_pending(unsigned int __user *fpcsr) | ||
128 | { | ||
129 | int err, sig = 0; | ||
130 | unsigned int csr, enabled; | ||
131 | |||
132 | err = __get_user(csr, fpcsr); | ||
133 | enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); | ||
134 | /* | ||
135 | * If the signal handler set some FPU exceptions, clear it and | ||
136 | * send SIGFPE. | ||
137 | */ | ||
138 | if (csr & enabled) { | ||
139 | csr &= ~enabled; | ||
140 | err |= __put_user(csr, fpcsr); | ||
141 | sig = SIGFPE; | ||
142 | } | ||
143 | return err ?: sig; | ||
144 | } | ||
145 | |||
146 | static int | ||
147 | check_and_restore_fp_context(struct sigcontext __user *sc) | ||
148 | { | ||
149 | int err, sig; | ||
150 | |||
151 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | ||
152 | if (err > 0) | ||
153 | err = 0; | ||
154 | err |= restore_fp_context(sc); | ||
155 | return err ?: sig; | ||
156 | } | ||
157 | |||
127 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | 158 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
128 | { | 159 | { |
129 | unsigned int used_math; | 160 | unsigned int used_math; |
@@ -162,7 +193,8 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
162 | if (used_math()) { | 193 | if (used_math()) { |
163 | /* restore fpu context if we have used it before */ | 194 | /* restore fpu context if we have used it before */ |
164 | own_fpu(); | 195 | own_fpu(); |
165 | err |= restore_fp_context(sc); | 196 | if (!err) |
197 | err = check_and_restore_fp_context(sc); | ||
166 | } else { | 198 | } else { |
167 | /* signal handler may have used FPU. Give it up. */ | 199 | /* signal handler may have used FPU. Give it up. */ |
168 | lose_fpu(); | 200 | lose_fpu(); |
@@ -332,6 +364,7 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
332 | { | 364 | { |
333 | struct sigframe __user *frame; | 365 | struct sigframe __user *frame; |
334 | sigset_t blocked; | 366 | sigset_t blocked; |
367 | int sig; | ||
335 | 368 | ||
336 | frame = (struct sigframe __user *) regs.regs[29]; | 369 | frame = (struct sigframe __user *) regs.regs[29]; |
337 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 370 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -345,8 +378,11 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
345 | recalc_sigpending(); | 378 | recalc_sigpending(); |
346 | spin_unlock_irq(¤t->sighand->siglock); | 379 | spin_unlock_irq(¤t->sighand->siglock); |
347 | 380 | ||
348 | if (restore_sigcontext(®s, &frame->sf_sc)) | 381 | sig = restore_sigcontext(®s, &frame->sf_sc); |
382 | if (sig < 0) | ||
349 | goto badframe; | 383 | goto badframe; |
384 | else if (sig) | ||
385 | force_sig(sig, current); | ||
350 | 386 | ||
351 | /* | 387 | /* |
352 | * Don't let your children do this ... | 388 | * Don't let your children do this ... |
@@ -368,6 +404,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
368 | struct rt_sigframe __user *frame; | 404 | struct rt_sigframe __user *frame; |
369 | sigset_t set; | 405 | sigset_t set; |
370 | stack_t st; | 406 | stack_t st; |
407 | int sig; | ||
371 | 408 | ||
372 | frame = (struct rt_sigframe __user *) regs.regs[29]; | 409 | frame = (struct rt_sigframe __user *) regs.regs[29]; |
373 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 410 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -381,8 +418,11 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
381 | recalc_sigpending(); | 418 | recalc_sigpending(); |
382 | spin_unlock_irq(¤t->sighand->siglock); | 419 | spin_unlock_irq(¤t->sighand->siglock); |
383 | 420 | ||
384 | if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) | 421 | sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); |
422 | if (sig < 0) | ||
385 | goto badframe; | 423 | goto badframe; |
424 | else if (sig) | ||
425 | force_sig(sig, current); | ||
386 | 426 | ||
387 | if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) | 427 | if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) |
388 | goto badframe; | 428 | goto badframe; |
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, | |||
220 | return err; | 220 | return err; |
221 | } | 221 | } |
222 | 222 | ||
223 | static int | ||
224 | check_and_restore_fp_context32(struct sigcontext32 __user *sc) | ||
225 | { | ||
226 | int err, sig; | ||
227 | |||
228 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | ||
229 | if (err > 0) | ||
230 | err = 0; | ||
231 | err |= restore_fp_context32(sc); | ||
232 | return err ?: sig; | ||
233 | } | ||
234 | |||
223 | static int restore_sigcontext32(struct pt_regs *regs, | 235 | static int restore_sigcontext32(struct pt_regs *regs, |
224 | struct sigcontext32 __user *sc) | 236 | struct sigcontext32 __user *sc) |
225 | { | 237 | { |
@@ -255,7 +267,8 @@ static int restore_sigcontext32(struct pt_regs *regs, | |||
255 | if (used_math()) { | 267 | if (used_math()) { |
256 | /* restore fpu context if we have used it before */ | 268 | /* restore fpu context if we have used it before */ |
257 | own_fpu(); | 269 | own_fpu(); |
258 | err |= restore_fp_context32(sc); | 270 | if (!err) |
271 | err = check_and_restore_fp_context32(sc); | ||
259 | } else { | 272 | } else { |
260 | /* signal handler may have used FPU. Give it up. */ | 273 | /* signal handler may have used FPU. Give it up. */ |
261 | lose_fpu(); | 274 | lose_fpu(); |
@@ -508,6 +521,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
508 | { | 521 | { |
509 | struct sigframe32 __user *frame; | 522 | struct sigframe32 __user *frame; |
510 | sigset_t blocked; | 523 | sigset_t blocked; |
524 | int sig; | ||
511 | 525 | ||
512 | frame = (struct sigframe32 __user *) regs.regs[29]; | 526 | frame = (struct sigframe32 __user *) regs.regs[29]; |
513 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 527 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -521,8 +535,11 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
521 | recalc_sigpending(); | 535 | recalc_sigpending(); |
522 | spin_unlock_irq(¤t->sighand->siglock); | 536 | spin_unlock_irq(¤t->sighand->siglock); |
523 | 537 | ||
524 | if (restore_sigcontext32(®s, &frame->sf_sc)) | 538 | sig = restore_sigcontext32(®s, &frame->sf_sc); |
539 | if (sig < 0) | ||
525 | goto badframe; | 540 | goto badframe; |
541 | else if (sig) | ||
542 | force_sig(sig, current); | ||
526 | 543 | ||
527 | /* | 544 | /* |
528 | * Don't let your children do this ... | 545 | * Don't let your children do this ... |
@@ -545,6 +562,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
545 | sigset_t set; | 562 | sigset_t set; |
546 | stack_t st; | 563 | stack_t st; |
547 | s32 sp; | 564 | s32 sp; |
565 | int sig; | ||
548 | 566 | ||
549 | frame = (struct rt_sigframe32 __user *) regs.regs[29]; | 567 | frame = (struct rt_sigframe32 __user *) regs.regs[29]; |
550 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 568 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -558,8 +576,11 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
558 | recalc_sigpending(); | 576 | recalc_sigpending(); |
559 | spin_unlock_irq(¤t->sighand->siglock); | 577 | spin_unlock_irq(¤t->sighand->siglock); |
560 | 578 | ||
561 | if (restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext)) | 579 | sig = restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext); |
580 | if (sig < 0) | ||
562 | goto badframe; | 581 | goto badframe; |
582 | else if (sig) | ||
583 | force_sig(sig, current); | ||
563 | 584 | ||
564 | /* The ucontext contains a stack32_t, so we must convert! */ | 585 | /* The ucontext contains a stack32_t, so we must convert! */ |
565 | if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) | 586 | 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 ecf1f7ecaad9..a9202fa95987 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c | |||
@@ -127,6 +127,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
127 | sigset_t set; | 127 | sigset_t set; |
128 | stack_t st; | 128 | stack_t st; |
129 | s32 sp; | 129 | s32 sp; |
130 | int sig; | ||
130 | 131 | ||
131 | frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; | 132 | frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; |
132 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 133 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -140,8 +141,11 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
140 | recalc_sigpending(); | 141 | recalc_sigpending(); |
141 | spin_unlock_irq(¤t->sighand->siglock); | 142 | spin_unlock_irq(¤t->sighand->siglock); |
142 | 143 | ||
143 | if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) | 144 | sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); |
145 | if (sig < 0) | ||
144 | goto badframe; | 146 | goto badframe; |
147 | else if (sig) | ||
148 | force_sig(sig, current); | ||
145 | 149 | ||
146 | /* The ucontext contains a stack32_t, so we must convert! */ | 150 | /* The ucontext contains a stack32_t, so we must convert! */ |
147 | if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) | 151 | if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) |