aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal.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/signal.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/signal.c')
-rw-r--r--arch/mips/kernel/signal.c52
1 files changed, 43 insertions, 9 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index fa581192de21..07d67309451a 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -20,6 +20,7 @@
20#include <linux/ptrace.h> 20#include <linux/ptrace.h>
21#include <linux/unistd.h> 21#include <linux/unistd.h>
22#include <linux/compiler.h> 22#include <linux/compiler.h>
23#include <linux/uaccess.h>
23 24
24#include <asm/abi.h> 25#include <asm/abi.h>
25#include <asm/asm.h> 26#include <asm/asm.h>
@@ -27,7 +28,6 @@
27#include <asm/cacheflush.h> 28#include <asm/cacheflush.h>
28#include <asm/fpu.h> 29#include <asm/fpu.h>
29#include <asm/sim.h> 30#include <asm/sim.h>
30#include <asm/uaccess.h>
31#include <asm/ucontext.h> 31#include <asm/ucontext.h>
32#include <asm/cpu-features.h> 32#include <asm/cpu-features.h>
33#include <asm/war.h> 33#include <asm/war.h>
@@ -78,6 +78,46 @@ struct rt_sigframe {
78/* 78/*
79 * Helper routines 79 * Helper routines
80 */ 80 */
81static int protected_save_fp_context(struct sigcontext __user *sc)
82{
83 int err;
84 while (1) {
85 lock_fpu_owner();
86 own_fpu_inatomic(1);
87 err = save_fp_context(sc); /* this might fail */
88 unlock_fpu_owner();
89 if (likely(!err))
90 break;
91 /* touch the sigcontext and try again */
92 err = __put_user(0, &sc->sc_fpregs[0]) |
93 __put_user(0, &sc->sc_fpregs[31]) |
94 __put_user(0, &sc->sc_fpc_csr);
95 if (err)
96 break; /* really bad sigcontext */
97 }
98 return err;
99}
100
101static int protected_restore_fp_context(struct sigcontext __user *sc)
102{
103 int err, tmp;
104 while (1) {
105 lock_fpu_owner();
106 own_fpu_inatomic(0);
107 err = restore_fp_context(sc); /* this might fail */
108 unlock_fpu_owner();
109 if (likely(!err))
110 break;
111 /* touch the sigcontext and try again */
112 err = __get_user(tmp, &sc->sc_fpregs[0]) |
113 __get_user(tmp, &sc->sc_fpregs[31]) |
114 __get_user(tmp, &sc->sc_fpc_csr);
115 if (err)
116 break; /* really bad sigcontext */
117 }
118 return err;
119}
120
81int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 121int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
82{ 122{
83 int err = 0; 123 int err = 0;
@@ -113,10 +153,7 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
113 * Save FPU state to signal context. Signal handler 153 * Save FPU state to signal context. Signal handler
114 * will "inherit" current FPU state. 154 * will "inherit" current FPU state.
115 */ 155 */
116 preempt_disable(); 156 err |= protected_save_fp_context(sc);
117 own_fpu(1);
118 err |= save_fp_context(sc);
119 preempt_enable();
120 } 157 }
121 return err; 158 return err;
122} 159}
@@ -148,10 +185,7 @@ check_and_restore_fp_context(struct sigcontext __user *sc)
148 err = sig = fpcsr_pending(&sc->sc_fpc_csr); 185 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
149 if (err > 0) 186 if (err > 0)
150 err = 0; 187 err = 0;
151 preempt_disable(); 188 err |= protected_restore_fp_context(sc);
152 own_fpu(0);
153 err |= restore_fp_context(sc);
154 preempt_enable();
155 return err ?: sig; 189 return err ?: sig;
156} 190}
157 191