diff options
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r-- | arch/mips/kernel/signal.c | 46 |
1 files changed, 43 insertions, 3 deletions
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; |