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.c111
1 files changed, 90 insertions, 21 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index f091786187a6..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,10 +78,51 @@ 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;
84 int i; 124 int i;
125 unsigned int used_math;
85 126
86 err |= __put_user(regs->cp0_epc, &sc->sc_pc); 127 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
87 128
@@ -104,24 +145,48 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
104 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 145 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
105 } 146 }
106 147
107 err |= __put_user(!!used_math(), &sc->sc_used_math); 148 used_math = !!used_math();
149 err |= __put_user(used_math, &sc->sc_used_math);
108 150
109 if (used_math()) { 151 if (used_math) {
110 /* 152 /*
111 * Save FPU state to signal context. Signal handler 153 * Save FPU state to signal context. Signal handler
112 * will "inherit" current FPU state. 154 * will "inherit" current FPU state.
113 */ 155 */
114 preempt_disable(); 156 err |= protected_save_fp_context(sc);
157 }
158 return err;
159}
115 160
116 if (!is_fpu_owner()) { 161int fpcsr_pending(unsigned int __user *fpcsr)
117 own_fpu(); 162{
118 restore_fp(current); 163 int err, sig = 0;
119 } 164 unsigned int csr, enabled;
120 err |= save_fp_context(sc);
121 165
122 preempt_enable(); 166 err = __get_user(csr, fpcsr);
167 enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5);
168 /*
169 * If the signal handler set some FPU exceptions, clear it and
170 * send SIGFPE.
171 */
172 if (csr & enabled) {
173 csr &= ~enabled;
174 err |= __put_user(csr, fpcsr);
175 sig = SIGFPE;
123 } 176 }
124 return err; 177 return err ?: sig;
178}
179
180static int
181check_and_restore_fp_context(struct sigcontext __user *sc)
182{
183 int err, sig;
184
185 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
186 if (err > 0)
187 err = 0;
188 err |= protected_restore_fp_context(sc);
189 return err ?: sig;
125} 190}
126 191
127int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 192int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
@@ -157,19 +222,15 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
157 err |= __get_user(used_math, &sc->sc_used_math); 222 err |= __get_user(used_math, &sc->sc_used_math);
158 conditional_used_math(used_math); 223 conditional_used_math(used_math);
159 224
160 preempt_disable(); 225 if (used_math) {
161
162 if (used_math()) {
163 /* restore fpu context if we have used it before */ 226 /* restore fpu context if we have used it before */
164 own_fpu(); 227 if (!err)
165 err |= restore_fp_context(sc); 228 err = check_and_restore_fp_context(sc);
166 } else { 229 } else {
167 /* signal handler may have used FPU. Give it up. */ 230 /* signal handler may have used FPU. Give it up. */
168 lose_fpu(); 231 lose_fpu(0);
169 } 232 }
170 233
171 preempt_enable();
172
173 return err; 234 return err;
174} 235}
175 236
@@ -332,6 +393,7 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs)
332{ 393{
333 struct sigframe __user *frame; 394 struct sigframe __user *frame;
334 sigset_t blocked; 395 sigset_t blocked;
396 int sig;
335 397
336 frame = (struct sigframe __user *) regs.regs[29]; 398 frame = (struct sigframe __user *) regs.regs[29];
337 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 399 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -345,8 +407,11 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs)
345 recalc_sigpending(); 407 recalc_sigpending();
346 spin_unlock_irq(&current->sighand->siglock); 408 spin_unlock_irq(&current->sighand->siglock);
347 409
348 if (restore_sigcontext(&regs, &frame->sf_sc)) 410 sig = restore_sigcontext(&regs, &frame->sf_sc);
411 if (sig < 0)
349 goto badframe; 412 goto badframe;
413 else if (sig)
414 force_sig(sig, current);
350 415
351 /* 416 /*
352 * Don't let your children do this ... 417 * Don't let your children do this ...
@@ -368,6 +433,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
368 struct rt_sigframe __user *frame; 433 struct rt_sigframe __user *frame;
369 sigset_t set; 434 sigset_t set;
370 stack_t st; 435 stack_t st;
436 int sig;
371 437
372 frame = (struct rt_sigframe __user *) regs.regs[29]; 438 frame = (struct rt_sigframe __user *) regs.regs[29];
373 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 439 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -381,8 +447,11 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
381 recalc_sigpending(); 447 recalc_sigpending();
382 spin_unlock_irq(&current->sighand->siglock); 448 spin_unlock_irq(&current->sighand->siglock);
383 449
384 if (restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext)) 450 sig = restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext);
451 if (sig < 0)
385 goto badframe; 452 goto badframe;
453 else if (sig)
454 force_sig(sig, current);
386 455
387 if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) 456 if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st)))
388 goto badframe; 457 goto badframe;