diff options
| -rw-r--r-- | arch/mips/kernel/r4k_fpu.S | 16 | ||||
| -rw-r--r-- | arch/mips/kernel/signal-common.h | 3 | ||||
| -rw-r--r-- | arch/mips/kernel/signal.c | 46 | ||||
| -rw-r--r-- | arch/mips/kernel/signal32.c | 27 | ||||
| -rw-r--r-- | arch/mips/kernel/signal_n32.c | 6 |
5 files changed, 75 insertions, 23 deletions
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 59c1577ecbb3..dbd42adc52ed 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S | |||
| @@ -114,14 +114,6 @@ LEAF(_save_fp_context32) | |||
| 114 | */ | 114 | */ |
| 115 | LEAF(_restore_fp_context) | 115 | LEAF(_restore_fp_context) |
| 116 | EX lw t0, SC_FPC_CSR(a0) | 116 | EX lw t0, SC_FPC_CSR(a0) |
| 117 | |||
| 118 | /* Fail if the CSR has exceptions pending */ | ||
| 119 | srl t1, t0, 5 | ||
| 120 | and t1, t0 | ||
| 121 | andi t1, 0x1f << 7 | ||
| 122 | bnez t1, fault | ||
| 123 | nop | ||
| 124 | |||
| 125 | #ifdef CONFIG_64BIT | 117 | #ifdef CONFIG_64BIT |
| 126 | EX ldc1 $f1, SC_FPREGS+8(a0) | 118 | EX ldc1 $f1, SC_FPREGS+8(a0) |
| 127 | EX ldc1 $f3, SC_FPREGS+24(a0) | 119 | EX ldc1 $f3, SC_FPREGS+24(a0) |
| @@ -165,14 +157,6 @@ LEAF(_restore_fp_context) | |||
| 165 | LEAF(_restore_fp_context32) | 157 | LEAF(_restore_fp_context32) |
| 166 | /* Restore an o32 sigcontext. */ | 158 | /* Restore an o32 sigcontext. */ |
| 167 | EX lw t0, SC32_FPC_CSR(a0) | 159 | EX lw t0, SC32_FPC_CSR(a0) |
| 168 | |||
| 169 | /* Fail if the CSR has exceptions pending */ | ||
| 170 | srl t1, t0, 5 | ||
| 171 | and t1, t0 | ||
| 172 | andi t1, 0x1f << 7 | ||
| 173 | bnez t1, fault | ||
| 174 | nop | ||
| 175 | |||
| 176 | EX ldc1 $f0, SC32_FPREGS+0(a0) | 160 | EX ldc1 $f0, SC32_FPREGS+0(a0) |
| 177 | EX ldc1 $f2, SC32_FPREGS+16(a0) | 161 | EX ldc1 $f2, SC32_FPREGS+16(a0) |
| 178 | EX ldc1 $f4, SC32_FPREGS+32(a0) | 162 | EX ldc1 $f4, SC32_FPREGS+32(a0) |
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index fdbdbdc65b54..297dfcb97524 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h | |||
| @@ -31,4 +31,7 @@ extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
| 31 | */ | 31 | */ |
| 32 | extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); | 32 | extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); |
| 33 | 33 | ||
| 34 | /* Check and clear pending FPU exceptions in saved CSR */ | ||
| 35 | extern int fpcsr_pending(unsigned int __user *fpcsr); | ||
| 36 | |||
| 34 | #endif /* __SIGNAL_COMMON_H */ | 37 | #endif /* __SIGNAL_COMMON_H */ |
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index f091786187a6..bf094fc4c7eb 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
| @@ -124,6 +124,37 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
| 124 | return err; | 124 | return err; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | int fpcsr_pending(unsigned int __user *fpcsr) | ||
| 128 | { | ||
| 129 | int err, sig = 0; | ||
| 130 | unsigned int csr, enabled; | ||
| 131 | |||
| 132 | err = __get_user(csr, fpcsr); | ||
| 133 | enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5); | ||
| 134 | /* | ||
| 135 | * If the signal handler set some FPU exceptions, clear it and | ||
| 136 | * send SIGFPE. | ||
| 137 | */ | ||
| 138 | if (csr & enabled) { | ||
| 139 | csr &= ~enabled; | ||
| 140 | err |= __put_user(csr, fpcsr); | ||
| 141 | sig = SIGFPE; | ||
| 142 | } | ||
| 143 | return err ?: sig; | ||
| 144 | } | ||
| 145 | |||
| 146 | static int | ||
| 147 | check_and_restore_fp_context(struct sigcontext __user *sc) | ||
| 148 | { | ||
| 149 | int err, sig; | ||
| 150 | |||
| 151 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | ||
| 152 | if (err > 0) | ||
| 153 | err = 0; | ||
| 154 | err |= restore_fp_context(sc); | ||
| 155 | return err ?: sig; | ||
| 156 | } | ||
| 157 | |||
| 127 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | 158 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
| 128 | { | 159 | { |
| 129 | unsigned int used_math; | 160 | unsigned int used_math; |
| @@ -162,7 +193,8 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
| 162 | if (used_math()) { | 193 | if (used_math()) { |
| 163 | /* restore fpu context if we have used it before */ | 194 | /* restore fpu context if we have used it before */ |
| 164 | own_fpu(); | 195 | own_fpu(); |
| 165 | err |= restore_fp_context(sc); | 196 | if (!err) |
| 197 | err = check_and_restore_fp_context(sc); | ||
| 166 | } else { | 198 | } else { |
| 167 | /* signal handler may have used FPU. Give it up. */ | 199 | /* signal handler may have used FPU. Give it up. */ |
| 168 | lose_fpu(); | 200 | lose_fpu(); |
| @@ -332,6 +364,7 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 332 | { | 364 | { |
| 333 | struct sigframe __user *frame; | 365 | struct sigframe __user *frame; |
| 334 | sigset_t blocked; | 366 | sigset_t blocked; |
| 367 | int sig; | ||
| 335 | 368 | ||
| 336 | frame = (struct sigframe __user *) regs.regs[29]; | 369 | frame = (struct sigframe __user *) regs.regs[29]; |
| 337 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 370 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| @@ -345,8 +378,11 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 345 | recalc_sigpending(); | 378 | recalc_sigpending(); |
| 346 | spin_unlock_irq(¤t->sighand->siglock); | 379 | spin_unlock_irq(¤t->sighand->siglock); |
| 347 | 380 | ||
| 348 | if (restore_sigcontext(®s, &frame->sf_sc)) | 381 | sig = restore_sigcontext(®s, &frame->sf_sc); |
| 382 | if (sig < 0) | ||
| 349 | goto badframe; | 383 | goto badframe; |
| 384 | else if (sig) | ||
| 385 | force_sig(sig, current); | ||
| 350 | 386 | ||
| 351 | /* | 387 | /* |
| 352 | * Don't let your children do this ... | 388 | * Don't let your children do this ... |
| @@ -368,6 +404,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 368 | struct rt_sigframe __user *frame; | 404 | struct rt_sigframe __user *frame; |
| 369 | sigset_t set; | 405 | sigset_t set; |
| 370 | stack_t st; | 406 | stack_t st; |
| 407 | int sig; | ||
| 371 | 408 | ||
| 372 | frame = (struct rt_sigframe __user *) regs.regs[29]; | 409 | frame = (struct rt_sigframe __user *) regs.regs[29]; |
| 373 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 410 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| @@ -381,8 +418,11 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 381 | recalc_sigpending(); | 418 | recalc_sigpending(); |
| 382 | spin_unlock_irq(¤t->sighand->siglock); | 419 | spin_unlock_irq(¤t->sighand->siglock); |
| 383 | 420 | ||
| 384 | if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) | 421 | sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); |
| 422 | if (sig < 0) | ||
| 385 | goto badframe; | 423 | goto badframe; |
| 424 | else if (sig) | ||
| 425 | force_sig(sig, current); | ||
| 386 | 426 | ||
| 387 | if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) | 427 | if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) |
| 388 | goto badframe; | 428 | goto badframe; |
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 19bbef001959..20013b6fe725 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c | |||
| @@ -220,6 +220,18 @@ static int setup_sigcontext32(struct pt_regs *regs, | |||
| 220 | return err; | 220 | return err; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | static int | ||
| 224 | check_and_restore_fp_context32(struct sigcontext32 __user *sc) | ||
| 225 | { | ||
| 226 | int err, sig; | ||
| 227 | |||
| 228 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | ||
| 229 | if (err > 0) | ||
| 230 | err = 0; | ||
| 231 | err |= restore_fp_context32(sc); | ||
| 232 | return err ?: sig; | ||
| 233 | } | ||
| 234 | |||
| 223 | static int restore_sigcontext32(struct pt_regs *regs, | 235 | static int restore_sigcontext32(struct pt_regs *regs, |
| 224 | struct sigcontext32 __user *sc) | 236 | struct sigcontext32 __user *sc) |
| 225 | { | 237 | { |
| @@ -255,7 +267,8 @@ static int restore_sigcontext32(struct pt_regs *regs, | |||
| 255 | if (used_math()) { | 267 | if (used_math()) { |
| 256 | /* restore fpu context if we have used it before */ | 268 | /* restore fpu context if we have used it before */ |
| 257 | own_fpu(); | 269 | own_fpu(); |
| 258 | err |= restore_fp_context32(sc); | 270 | if (!err) |
| 271 | err = check_and_restore_fp_context32(sc); | ||
| 259 | } else { | 272 | } else { |
| 260 | /* signal handler may have used FPU. Give it up. */ | 273 | /* signal handler may have used FPU. Give it up. */ |
| 261 | lose_fpu(); | 274 | lose_fpu(); |
| @@ -508,6 +521,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 508 | { | 521 | { |
| 509 | struct sigframe32 __user *frame; | 522 | struct sigframe32 __user *frame; |
| 510 | sigset_t blocked; | 523 | sigset_t blocked; |
| 524 | int sig; | ||
| 511 | 525 | ||
| 512 | frame = (struct sigframe32 __user *) regs.regs[29]; | 526 | frame = (struct sigframe32 __user *) regs.regs[29]; |
| 513 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 527 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| @@ -521,8 +535,11 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 521 | recalc_sigpending(); | 535 | recalc_sigpending(); |
| 522 | spin_unlock_irq(¤t->sighand->siglock); | 536 | spin_unlock_irq(¤t->sighand->siglock); |
| 523 | 537 | ||
| 524 | if (restore_sigcontext32(®s, &frame->sf_sc)) | 538 | sig = restore_sigcontext32(®s, &frame->sf_sc); |
| 539 | if (sig < 0) | ||
| 525 | goto badframe; | 540 | goto badframe; |
| 541 | else if (sig) | ||
| 542 | force_sig(sig, current); | ||
| 526 | 543 | ||
| 527 | /* | 544 | /* |
| 528 | * Don't let your children do this ... | 545 | * Don't let your children do this ... |
| @@ -545,6 +562,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 545 | sigset_t set; | 562 | sigset_t set; |
| 546 | stack_t st; | 563 | stack_t st; |
| 547 | s32 sp; | 564 | s32 sp; |
| 565 | int sig; | ||
| 548 | 566 | ||
| 549 | frame = (struct rt_sigframe32 __user *) regs.regs[29]; | 567 | frame = (struct rt_sigframe32 __user *) regs.regs[29]; |
| 550 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 568 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| @@ -558,8 +576,11 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 558 | recalc_sigpending(); | 576 | recalc_sigpending(); |
| 559 | spin_unlock_irq(¤t->sighand->siglock); | 577 | spin_unlock_irq(¤t->sighand->siglock); |
| 560 | 578 | ||
| 561 | if (restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext)) | 579 | sig = restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext); |
| 580 | if (sig < 0) | ||
| 562 | goto badframe; | 581 | goto badframe; |
| 582 | else if (sig) | ||
| 583 | force_sig(sig, current); | ||
| 563 | 584 | ||
| 564 | /* The ucontext contains a stack32_t, so we must convert! */ | 585 | /* The ucontext contains a stack32_t, so we must convert! */ |
| 565 | if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) | 586 | if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) |
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index ecf1f7ecaad9..a9202fa95987 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c | |||
| @@ -127,6 +127,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 127 | sigset_t set; | 127 | sigset_t set; |
| 128 | stack_t st; | 128 | stack_t st; |
| 129 | s32 sp; | 129 | s32 sp; |
| 130 | int sig; | ||
| 130 | 131 | ||
| 131 | frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; | 132 | frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; |
| 132 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 133 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| @@ -140,8 +141,11 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 140 | recalc_sigpending(); | 141 | recalc_sigpending(); |
| 141 | spin_unlock_irq(¤t->sighand->siglock); | 142 | spin_unlock_irq(¤t->sighand->siglock); |
| 142 | 143 | ||
| 143 | if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) | 144 | sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); |
| 145 | if (sig < 0) | ||
| 144 | goto badframe; | 146 | goto badframe; |
| 147 | else if (sig) | ||
| 148 | force_sig(sig, current); | ||
| 145 | 149 | ||
| 146 | /* The ucontext contains a stack32_t, so we must convert! */ | 150 | /* The ucontext contains a stack32_t, so we must convert! */ |
| 147 | if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) | 151 | if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) |
