aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal32.c
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2007-04-16 10:19:44 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-04-20 09:58:37 -0400
commitfaea62346444ce5b1dba8fb5291d95b676522c42 (patch)
treed00e53763ca9b145348e5754aaf0cd4dcbb12123 /arch/mips/kernel/signal32.c
parent5323180db75d562a287cb2020b07c9422df13df6 (diff)
[MIPS] Retry {save,restore}_fp_context if failed in atomic context.
The save_fp_context()/restore_fp_context() might sleep on accessing user stack and therefore might lose FPU ownership in middle of them. If these function failed due to "in_atomic" test in do_page_fault, touch the sigcontext area in non-atomic context and retry these save/restore operation. This is a replacement of a (broken) fix which was titled "Allow CpU exception in kernel partially". 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.c52
1 files changed, 43 insertions, 9 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 53a337cfeb66..b9a014411f83 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -22,6 +22,7 @@
22#include <linux/compat.h> 22#include <linux/compat.h>
23#include <linux/suspend.h> 23#include <linux/suspend.h>
24#include <linux/compiler.h> 24#include <linux/compiler.h>
25#include <linux/uaccess.h>
25 26
26#include <asm/abi.h> 27#include <asm/abi.h>
27#include <asm/asm.h> 28#include <asm/asm.h>
@@ -29,7 +30,6 @@
29#include <linux/bitops.h> 30#include <linux/bitops.h>
30#include <asm/cacheflush.h> 31#include <asm/cacheflush.h>
31#include <asm/sim.h> 32#include <asm/sim.h>
32#include <asm/uaccess.h>
33#include <asm/ucontext.h> 33#include <asm/ucontext.h>
34#include <asm/system.h> 34#include <asm/system.h>
35#include <asm/fpu.h> 35#include <asm/fpu.h>
@@ -176,6 +176,46 @@ struct rt_sigframe32 {
176/* 176/*
177 * sigcontext handlers 177 * sigcontext handlers
178 */ 178 */
179static int protected_save_fp_context32(struct sigcontext32 __user *sc)
180{
181 int err;
182 while (1) {
183 lock_fpu_owner();
184 own_fpu_inatomic(1);
185 err = save_fp_context32(sc); /* this might fail */
186 unlock_fpu_owner();
187 if (likely(!err))
188 break;
189 /* touch the sigcontext and try again */
190 err = __put_user(0, &sc->sc_fpregs[0]) |
191 __put_user(0, &sc->sc_fpregs[31]) |
192 __put_user(0, &sc->sc_fpc_csr);
193 if (err)
194 break; /* really bad sigcontext */
195 }
196 return err;
197}
198
199static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
200{
201 int err, tmp;
202 while (1) {
203 lock_fpu_owner();
204 own_fpu_inatomic(0);
205 err = restore_fp_context32(sc); /* this might fail */
206 unlock_fpu_owner();
207 if (likely(!err))
208 break;
209 /* touch the sigcontext and try again */
210 err = __get_user(tmp, &sc->sc_fpregs[0]) |
211 __get_user(tmp, &sc->sc_fpregs[31]) |
212 __get_user(tmp, &sc->sc_fpc_csr);
213 if (err)
214 break; /* really bad sigcontext */
215 }
216 return err;
217}
218
179static int setup_sigcontext32(struct pt_regs *regs, 219static int setup_sigcontext32(struct pt_regs *regs,
180 struct sigcontext32 __user *sc) 220 struct sigcontext32 __user *sc)
181{ 221{
@@ -209,10 +249,7 @@ static int setup_sigcontext32(struct pt_regs *regs,
209 * Save FPU state to signal context. Signal handler 249 * Save FPU state to signal context. Signal handler
210 * will "inherit" current FPU state. 250 * will "inherit" current FPU state.
211 */ 251 */
212 preempt_disable(); 252 err |= protected_save_fp_context32(sc);
213 own_fpu(1);
214 err |= save_fp_context32(sc);
215 preempt_enable();
216 } 253 }
217 return err; 254 return err;
218} 255}
@@ -225,10 +262,7 @@ check_and_restore_fp_context32(struct sigcontext32 __user *sc)
225 err = sig = fpcsr_pending(&sc->sc_fpc_csr); 262 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
226 if (err > 0) 263 if (err > 0)
227 err = 0; 264 err = 0;
228 preempt_disable(); 265 err |= protected_restore_fp_context32(sc);
229 own_fpu(0);
230 err |= restore_fp_context32(sc);
231 preempt_enable();
232 return err ?: sig; 266 return err ?: sig;
233} 267}
234 268