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.c136
1 files changed, 110 insertions, 26 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index b2e9ab1bb101..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
@@ -89,6 +130,9 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
89 for (i = 1; i < 32; i++) 130 for (i = 1; i < 32; i++)
90 err |= __put_user(regs->regs[i], &sc->sc_regs[i]); 131 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
91 132
133#ifdef CONFIG_CPU_HAS_SMARTMIPS
134 err |= __put_user(regs->acx, &sc->sc_acx);
135#endif
92 err |= __put_user(regs->hi, &sc->sc_mdhi); 136 err |= __put_user(regs->hi, &sc->sc_mdhi);
93 err |= __put_user(regs->lo, &sc->sc_mdlo); 137 err |= __put_user(regs->lo, &sc->sc_mdlo);
94 if (cpu_has_dsp) { 138 if (cpu_has_dsp) {
@@ -101,24 +145,48 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
101 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); 145 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
102 } 146 }
103 147
104 err |= __put_user(!!used_math(), &sc->sc_used_math); 148 used_math = !!used_math();
149 err |= __put_user(used_math, &sc->sc_used_math);
105 150
106 if (used_math()) { 151 if (used_math) {
107 /* 152 /*
108 * Save FPU state to signal context. Signal handler 153 * Save FPU state to signal context. Signal handler
109 * will "inherit" current FPU state. 154 * will "inherit" current FPU state.
110 */ 155 */
111 preempt_disable(); 156 err |= protected_save_fp_context(sc);
157 }
158 return err;
159}
112 160
113 if (!is_fpu_owner()) { 161int fpcsr_pending(unsigned int __user *fpcsr)
114 own_fpu(); 162{
115 restore_fp(current); 163 int err, sig = 0;
116 } 164 unsigned int csr, enabled;
117 err |= save_fp_context(sc);
118 165
119 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;
120 } 176 }
121 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;
122} 190}
123 191
124int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 192int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
@@ -132,6 +200,10 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
132 current_thread_info()->restart_block.fn = do_no_restart_syscall; 200 current_thread_info()->restart_block.fn = do_no_restart_syscall;
133 201
134 err |= __get_user(regs->cp0_epc, &sc->sc_pc); 202 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
203
204#ifdef CONFIG_CPU_HAS_SMARTMIPS
205 err |= __get_user(regs->acx, &sc->sc_acx);
206#endif
135 err |= __get_user(regs->hi, &sc->sc_mdhi); 207 err |= __get_user(regs->hi, &sc->sc_mdhi);
136 err |= __get_user(regs->lo, &sc->sc_mdlo); 208 err |= __get_user(regs->lo, &sc->sc_mdlo);
137 if (cpu_has_dsp) { 209 if (cpu_has_dsp) {
@@ -150,19 +222,15 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
150 err |= __get_user(used_math, &sc->sc_used_math); 222 err |= __get_user(used_math, &sc->sc_used_math);
151 conditional_used_math(used_math); 223 conditional_used_math(used_math);
152 224
153 preempt_disable(); 225 if (used_math) {
154
155 if (used_math()) {
156 /* restore fpu context if we have used it before */ 226 /* restore fpu context if we have used it before */
157 own_fpu(); 227 if (!err)
158 err |= restore_fp_context(sc); 228 err = check_and_restore_fp_context(sc);
159 } else { 229 } else {
160 /* signal handler may have used FPU. Give it up. */ 230 /* signal handler may have used FPU. Give it up. */
161 lose_fpu(); 231 lose_fpu(0);
162 } 232 }
163 233
164 preempt_enable();
165
166 return err; 234 return err;
167} 235}
168 236
@@ -325,6 +393,7 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs)
325{ 393{
326 struct sigframe __user *frame; 394 struct sigframe __user *frame;
327 sigset_t blocked; 395 sigset_t blocked;
396 int sig;
328 397
329 frame = (struct sigframe __user *) regs.regs[29]; 398 frame = (struct sigframe __user *) regs.regs[29];
330 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 399 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -338,8 +407,11 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs)
338 recalc_sigpending(); 407 recalc_sigpending();
339 spin_unlock_irq(&current->sighand->siglock); 408 spin_unlock_irq(&current->sighand->siglock);
340 409
341 if (restore_sigcontext(&regs, &frame->sf_sc)) 410 sig = restore_sigcontext(&regs, &frame->sf_sc);
411 if (sig < 0)
342 goto badframe; 412 goto badframe;
413 else if (sig)
414 force_sig(sig, current);
343 415
344 /* 416 /*
345 * Don't let your children do this ... 417 * Don't let your children do this ...
@@ -361,6 +433,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
361 struct rt_sigframe __user *frame; 433 struct rt_sigframe __user *frame;
362 sigset_t set; 434 sigset_t set;
363 stack_t st; 435 stack_t st;
436 int sig;
364 437
365 frame = (struct rt_sigframe __user *) regs.regs[29]; 438 frame = (struct rt_sigframe __user *) regs.regs[29];
366 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 439 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -374,8 +447,11 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
374 recalc_sigpending(); 447 recalc_sigpending();
375 spin_unlock_irq(&current->sighand->siglock); 448 spin_unlock_irq(&current->sighand->siglock);
376 449
377 if (restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext)) 450 sig = restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext);
451 if (sig < 0)
378 goto badframe; 452 goto badframe;
453 else if (sig)
454 force_sig(sig, current);
379 455
380 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)))
381 goto badframe; 457 goto badframe;
@@ -398,7 +474,7 @@ badframe:
398} 474}
399 475
400#ifdef CONFIG_TRAD_SIGNALS 476#ifdef CONFIG_TRAD_SIGNALS
401int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, 477static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
402 int signr, sigset_t *set) 478 int signr, sigset_t *set)
403{ 479{
404 struct sigframe __user *frame; 480 struct sigframe __user *frame;
@@ -443,7 +519,7 @@ give_sigsegv:
443} 519}
444#endif 520#endif
445 521
446int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, 522static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
447 int signr, sigset_t *set, siginfo_t *info) 523 int signr, sigset_t *set, siginfo_t *info)
448{ 524{
449 struct rt_sigframe __user *frame; 525 struct rt_sigframe __user *frame;
@@ -501,6 +577,14 @@ give_sigsegv:
501 return -EFAULT; 577 return -EFAULT;
502} 578}
503 579
580struct mips_abi mips_abi = {
581#ifdef CONFIG_TRAD_SIGNALS
582 .setup_frame = setup_frame,
583#endif
584 .setup_rt_frame = setup_rt_frame,
585 .restart = __NR_restart_syscall
586};
587
504static int handle_signal(unsigned long sig, siginfo_t *info, 588static int handle_signal(unsigned long sig, siginfo_t *info,
505 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) 589 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
506{ 590{
@@ -539,7 +623,7 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
539 return ret; 623 return ret;
540} 624}
541 625
542void do_signal(struct pt_regs *regs) 626static void do_signal(struct pt_regs *regs)
543{ 627{
544 struct k_sigaction ka; 628 struct k_sigaction ka;
545 sigset_t *oldset; 629 sigset_t *oldset;
@@ -589,7 +673,7 @@ void do_signal(struct pt_regs *regs)
589 regs->cp0_epc -= 8; 673 regs->cp0_epc -= 8;
590 } 674 }
591 if (regs->regs[2] == ERESTART_RESTARTBLOCK) { 675 if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
592 regs->regs[2] = __NR_restart_syscall; 676 regs->regs[2] = current->thread.abi->restart;
593 regs->regs[7] = regs->regs[26]; 677 regs->regs[7] = regs->regs[26];
594 regs->cp0_epc -= 4; 678 regs->cp0_epc -= 4;
595 } 679 }
@@ -615,5 +699,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
615{ 699{
616 /* deal with pending signal delivery */ 700 /* deal with pending signal delivery */
617 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) 701 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
618 current->thread.abi->do_signal(regs); 702 do_signal(regs);
619} 703}