aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal32.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-04-26 04:31:28 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-04-26 04:31:28 -0400
commitef2e58ea6b9931c3a4816c66593da49bb20e3b24 (patch)
treece7432add3becbe78de4ea06425cd2d9e91f4ada /arch/mips/kernel/signal32.c
parent06d63cc51d47f572009138a7f3ac34d95773405d (diff)
parentde46c33745f5e2ad594c72f2cf5f490861b16ce1 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r--arch/mips/kernel/signal32.c94
1 files changed, 72 insertions, 22 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 19bbef001959..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,11 +176,52 @@ 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{
182 int err = 0; 222 int err = 0;
183 int i; 223 int i;
224 u32 used_math;
184 225
185 err |= __put_user(regs->cp0_epc, &sc->sc_pc); 226 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
186 227
@@ -200,26 +241,31 @@ static int setup_sigcontext32(struct pt_regs *regs,
200 err |= __put_user(mflo3(), &sc->sc_lo3); 241 err |= __put_user(mflo3(), &sc->sc_lo3);
201 } 242 }
202 243
203 err |= __put_user(!!used_math(), &sc->sc_used_math); 244 used_math = !!used_math();
245 err |= __put_user(used_math, &sc->sc_used_math);
204 246
205 if (used_math()) { 247 if (used_math) {
206 /* 248 /*
207 * Save FPU state to signal context. Signal handler 249 * Save FPU state to signal context. Signal handler
208 * will "inherit" current FPU state. 250 * will "inherit" current FPU state.
209 */ 251 */
210 preempt_disable(); 252 err |= protected_save_fp_context32(sc);
211
212 if (!is_fpu_owner()) {
213 own_fpu();
214 restore_fp(current);
215 }
216 err |= save_fp_context32(sc);
217
218 preempt_enable();
219 } 253 }
220 return err; 254 return err;
221} 255}
222 256
257static int
258check_and_restore_fp_context32(struct sigcontext32 __user *sc)
259{
260 int err, sig;
261
262 err = sig = fpcsr_pending(&sc->sc_fpc_csr);
263 if (err > 0)
264 err = 0;
265 err |= protected_restore_fp_context32(sc);
266 return err ?: sig;
267}
268
223static int restore_sigcontext32(struct pt_regs *regs, 269static int restore_sigcontext32(struct pt_regs *regs,
224 struct sigcontext32 __user *sc) 270 struct sigcontext32 __user *sc)
225{ 271{
@@ -250,19 +296,15 @@ static int restore_sigcontext32(struct pt_regs *regs,
250 err |= __get_user(used_math, &sc->sc_used_math); 296 err |= __get_user(used_math, &sc->sc_used_math);
251 conditional_used_math(used_math); 297 conditional_used_math(used_math);
252 298
253 preempt_disable(); 299 if (used_math) {
254
255 if (used_math()) {
256 /* restore fpu context if we have used it before */ 300 /* restore fpu context if we have used it before */
257 own_fpu(); 301 if (!err)
258 err |= restore_fp_context32(sc); 302 err = check_and_restore_fp_context32(sc);
259 } else { 303 } else {
260 /* signal handler may have used FPU. Give it up. */ 304 /* signal handler may have used FPU. Give it up. */
261 lose_fpu(); 305 lose_fpu(0);
262 } 306 }
263 307
264 preempt_enable();
265
266 return err; 308 return err;
267} 309}
268 310
@@ -508,6 +550,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
508{ 550{
509 struct sigframe32 __user *frame; 551 struct sigframe32 __user *frame;
510 sigset_t blocked; 552 sigset_t blocked;
553 int sig;
511 554
512 frame = (struct sigframe32 __user *) regs.regs[29]; 555 frame = (struct sigframe32 __user *) regs.regs[29];
513 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 556 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -521,8 +564,11 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
521 recalc_sigpending(); 564 recalc_sigpending();
522 spin_unlock_irq(&current->sighand->siglock); 565 spin_unlock_irq(&current->sighand->siglock);
523 566
524 if (restore_sigcontext32(&regs, &frame->sf_sc)) 567 sig = restore_sigcontext32(&regs, &frame->sf_sc);
568 if (sig < 0)
525 goto badframe; 569 goto badframe;
570 else if (sig)
571 force_sig(sig, current);
526 572
527 /* 573 /*
528 * Don't let your children do this ... 574 * Don't let your children do this ...
@@ -545,6 +591,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
545 sigset_t set; 591 sigset_t set;
546 stack_t st; 592 stack_t st;
547 s32 sp; 593 s32 sp;
594 int sig;
548 595
549 frame = (struct rt_sigframe32 __user *) regs.regs[29]; 596 frame = (struct rt_sigframe32 __user *) regs.regs[29];
550 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 597 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -558,8 +605,11 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
558 recalc_sigpending(); 605 recalc_sigpending();
559 spin_unlock_irq(&current->sighand->siglock); 606 spin_unlock_irq(&current->sighand->siglock);
560 607
561 if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext)) 608 sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
609 if (sig < 0)
562 goto badframe; 610 goto badframe;
611 else if (sig)
612 force_sig(sig, current);
563 613
564 /* The ucontext contains a stack32_t, so we must convert! */ 614 /* The ucontext contains a stack32_t, so we must convert! */
565 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) 615 if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))