aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal.c
diff options
context:
space:
mode:
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 8c3c5a5789b0..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 own_fpu(1); 156 err |= protected_save_fp_context(sc);
117 enable_fp_in_kernel();
118 err |= save_fp_context(sc);
119 disable_fp_in_kernel();
120 } 157 }
121 return err; 158 return err;
122} 159}
@@ -148,7 +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 err |= restore_fp_context(sc); 188 err |= protected_restore_fp_context(sc);
152 return err ?: sig; 189 return err ?: sig;
153} 190}
154 191
@@ -187,11 +224,8 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
187 224
188 if (used_math) { 225 if (used_math) {
189 /* restore fpu context if we have used it before */ 226 /* restore fpu context if we have used it before */
190 own_fpu(0);
191 enable_fp_in_kernel();
192 if (!err) 227 if (!err)
193 err = check_and_restore_fp_context(sc); 228 err = check_and_restore_fp_context(sc);
194 disable_fp_in_kernel();
195 } else { 229 } else {
196 /* signal handler may have used FPU. Give it up. */ 230 /* signal handler may have used FPU. Give it up. */
197 lose_fpu(0); 231 lose_fpu(0);