diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-04-26 04:31:28 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2007-04-26 04:31:28 -0400 |
commit | ef2e58ea6b9931c3a4816c66593da49bb20e3b24 (patch) | |
tree | ce7432add3becbe78de4ea06425cd2d9e91f4ada /arch/mips/kernel/signal32.c | |
parent | 06d63cc51d47f572009138a7f3ac34d95773405d (diff) | |
parent | de46c33745f5e2ad594c72f2cf5f490861b16ce1 (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.c | 94 |
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 | */ |
179 | static 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 | |||
199 | static 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 | |||
179 | static int setup_sigcontext32(struct pt_regs *regs, | 219 | static 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 | ||
257 | static int | ||
258 | check_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 | |||
223 | static int restore_sigcontext32(struct pt_regs *regs, | 269 | static 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(¤t->sighand->siglock); | 565 | spin_unlock_irq(¤t->sighand->siglock); |
523 | 566 | ||
524 | if (restore_sigcontext32(®s, &frame->sf_sc)) | 567 | sig = restore_sigcontext32(®s, &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(¤t->sighand->siglock); | 606 | spin_unlock_irq(¤t->sighand->siglock); |
560 | 607 | ||
561 | if (restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext)) | 608 | sig = restore_sigcontext32(®s, &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)) |