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.c272
1 files changed, 205 insertions, 67 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index b9d358e05214..adbfb95e42d0 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -34,18 +34,192 @@
34 34
35#include "signal-common.h" 35#include "signal-common.h"
36 36
37#define DEBUG_SIG 0 37/*
38 * Horribly complicated - with the bloody RM9000 workarounds enabled
39 * the signal trampolines is moving to the end of the structure so we can
40 * increase the alignment without breaking software compatibility.
41 */
42#if ICACHE_REFILLS_WORKAROUND_WAR == 0
43
44struct sigframe {
45 u32 sf_ass[4]; /* argument save space for o32 */
46 u32 sf_code[2]; /* signal trampoline */
47 struct sigcontext sf_sc;
48 sigset_t sf_mask;
49};
50
51struct rt_sigframe {
52 u32 rs_ass[4]; /* argument save space for o32 */
53 u32 rs_code[2]; /* signal trampoline */
54 struct siginfo rs_info;
55 struct ucontext rs_uc;
56};
38 57
39#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 58#else
59
60struct sigframe {
61 u32 sf_ass[4]; /* argument save space for o32 */
62 u32 sf_pad[2];
63 struct sigcontext sf_sc; /* hw context */
64 sigset_t sf_mask;
65 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
66};
67
68struct rt_sigframe {
69 u32 rs_ass[4]; /* argument save space for o32 */
70 u32 rs_pad[2];
71 struct siginfo rs_info;
72 struct ucontext rs_uc;
73 u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */
74};
75
76#endif
77
78/*
79 * Helper routines
80 */
81int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
82{
83 int err = 0;
84 int i;
85
86 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
87
88 err |= __put_user(0, &sc->sc_regs[0]);
89 for (i = 1; i < 32; i++)
90 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
91
92 err |= __put_user(regs->hi, &sc->sc_mdhi);
93 err |= __put_user(regs->lo, &sc->sc_mdlo);
94 if (cpu_has_dsp) {
95 err |= __put_user(mfhi1(), &sc->sc_hi1);
96 err |= __put_user(mflo1(), &sc->sc_lo1);
97 err |= __put_user(mfhi2(), &sc->sc_hi2);
98 err |= __put_user(mflo2(), &sc->sc_lo2);
99 err |= __put_user(mfhi3(), &sc->sc_hi3);
100 err |= __put_user(mflo3(), &sc->sc_lo3);
101 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
102 }
103
104 err |= __put_user(!!used_math(), &sc->sc_used_math);
105
106 if (used_math()) {
107 /*
108 * Save FPU state to signal context. Signal handler
109 * will "inherit" current FPU state.
110 */
111 preempt_disable();
112
113 if (!is_fpu_owner()) {
114 own_fpu();
115 restore_fp(current);
116 }
117 err |= save_fp_context(sc);
118
119 preempt_enable();
120 }
121 return err;
122}
123
124int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
125{
126 unsigned int used_math;
127 unsigned long treg;
128 int err = 0;
129 int i;
130
131 /* Always make any pending restarted system calls return -EINTR */
132 current_thread_info()->restart_block.fn = do_no_restart_syscall;
133
134 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
135 err |= __get_user(regs->hi, &sc->sc_mdhi);
136 err |= __get_user(regs->lo, &sc->sc_mdlo);
137 if (cpu_has_dsp) {
138 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
139 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
140 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
141 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
142 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
143 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
144 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
145 }
146
147 for (i = 1; i < 32; i++)
148 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
149
150 err |= __get_user(used_math, &sc->sc_used_math);
151 conditional_used_math(used_math);
152
153 preempt_disable();
154
155 if (used_math()) {
156 /* restore fpu context if we have used it before */
157 own_fpu();
158 err |= restore_fp_context(sc);
159 } else {
160 /* signal handler may have used FPU. Give it up. */
161 lose_fpu();
162 }
163
164 preempt_enable();
165
166 return err;
167}
168
169void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
170 size_t frame_size)
171{
172 unsigned long sp;
173
174 /* Default to using normal stack */
175 sp = regs->regs[29];
176
177 /*
178 * FPU emulator may have it's own trampoline active just
179 * above the user stack, 16-bytes before the next lowest
180 * 16 byte boundary. Try to avoid trashing it.
181 */
182 sp -= 32;
183
184 /* This is the X/Open sanctioned signal stack switching. */
185 if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
186 sp = current->sas_ss_sp + current->sas_ss_size;
187
188 return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK));
189}
190
191int install_sigtramp(unsigned int __user *tramp, unsigned int syscall)
192{
193 int err;
194
195 /*
196 * Set up the return code ...
197 *
198 * li v0, __NR__foo_sigreturn
199 * syscall
200 */
201
202 err = __put_user(0x24020000 + syscall, tramp + 0);
203 err |= __put_user(0x0000000c , tramp + 1);
204 if (ICACHE_REFILLS_WORKAROUND_WAR) {
205 err |= __put_user(0, tramp + 2);
206 err |= __put_user(0, tramp + 3);
207 err |= __put_user(0, tramp + 4);
208 err |= __put_user(0, tramp + 5);
209 err |= __put_user(0, tramp + 6);
210 err |= __put_user(0, tramp + 7);
211 }
212 flush_cache_sigtramp((unsigned long) tramp);
213
214 return err;
215}
40 216
41/* 217/*
42 * Atomically swap in the new signal mask, and wait for a signal. 218 * Atomically swap in the new signal mask, and wait for a signal.
43 */ 219 */
44 220
45#ifdef CONFIG_TRAD_SIGNALS 221#ifdef CONFIG_TRAD_SIGNALS
46save_static_function(sys_sigsuspend); 222asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
47__attribute_used__ noinline static int
48_sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
49{ 223{
50 sigset_t newset; 224 sigset_t newset;
51 sigset_t __user *uset; 225 sigset_t __user *uset;
@@ -68,9 +242,7 @@ _sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
68} 242}
69#endif 243#endif
70 244
71save_static_function(sys_rt_sigsuspend); 245asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
72__attribute_used__ noinline static int
73_sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
74{ 246{
75 sigset_t newset; 247 sigset_t newset;
76 sigset_t __user *unewset; 248 sigset_t __user *unewset;
@@ -89,7 +261,7 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
89 spin_lock_irq(&current->sighand->siglock); 261 spin_lock_irq(&current->sighand->siglock);
90 current->saved_sigmask = current->blocked; 262 current->saved_sigmask = current->blocked;
91 current->blocked = newset; 263 current->blocked = newset;
92 recalc_sigpending(); 264 recalc_sigpending();
93 spin_unlock_irq(&current->sighand->siglock); 265 spin_unlock_irq(&current->sighand->siglock);
94 266
95 current->state = TASK_INTERRUPTIBLE; 267 current->state = TASK_INTERRUPTIBLE;
@@ -124,7 +296,7 @@ asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act,
124 296
125 if (!ret && oact) { 297 if (!ret && oact) {
126 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 298 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
127 return -EFAULT; 299 return -EFAULT;
128 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 300 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
129 err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); 301 err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler);
130 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 302 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
@@ -148,45 +320,8 @@ asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs)
148 return do_sigaltstack(uss, uoss, usp); 320 return do_sigaltstack(uss, uoss, usp);
149} 321}
150 322
151/*
152 * Horribly complicated - with the bloody RM9000 workarounds enabled
153 * the signal trampolines is moving to the end of the structure so we can
154 * increase the alignment without breaking software compatibility.
155 */
156#ifdef CONFIG_TRAD_SIGNALS
157struct sigframe {
158 u32 sf_ass[4]; /* argument save space for o32 */
159#if ICACHE_REFILLS_WORKAROUND_WAR
160 u32 sf_pad[2];
161#else
162 u32 sf_code[2]; /* signal trampoline */
163#endif
164 struct sigcontext sf_sc;
165 sigset_t sf_mask;
166#if ICACHE_REFILLS_WORKAROUND_WAR
167 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
168#endif
169};
170#endif
171
172struct rt_sigframe {
173 u32 rs_ass[4]; /* argument save space for o32 */
174#if ICACHE_REFILLS_WORKAROUND_WAR
175 u32 rs_pad[2];
176#else
177 u32 rs_code[2]; /* signal trampoline */
178#endif
179 struct siginfo rs_info;
180 struct ucontext rs_uc;
181#if ICACHE_REFILLS_WORKAROUND_WAR
182 u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */
183#endif
184};
185
186#ifdef CONFIG_TRAD_SIGNALS 323#ifdef CONFIG_TRAD_SIGNALS
187save_static_function(sys_sigreturn); 324asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs)
188__attribute_used__ noinline static void
189_sys_sigreturn(nabi_no_regargs struct pt_regs regs)
190{ 325{
191 struct sigframe __user *frame; 326 struct sigframe __user *frame;
192 sigset_t blocked; 327 sigset_t blocked;
@@ -221,9 +356,7 @@ badframe:
221} 356}
222#endif /* CONFIG_TRAD_SIGNALS */ 357#endif /* CONFIG_TRAD_SIGNALS */
223 358
224save_static_function(sys_rt_sigreturn); 359asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
225__attribute_used__ noinline static void
226_sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
227{ 360{
228 struct rt_sigframe __user *frame; 361 struct rt_sigframe __user *frame;
229 sigset_t set; 362 sigset_t set;
@@ -265,7 +398,7 @@ badframe:
265} 398}
266 399
267#ifdef CONFIG_TRAD_SIGNALS 400#ifdef CONFIG_TRAD_SIGNALS
268int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, 401static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
269 int signr, sigset_t *set) 402 int signr, sigset_t *set)
270{ 403{
271 struct sigframe __user *frame; 404 struct sigframe __user *frame;
@@ -275,7 +408,7 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
275 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 408 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
276 goto give_sigsegv; 409 goto give_sigsegv;
277 410
278 install_sigtramp(frame->sf_code, __NR_sigreturn); 411 err |= install_sigtramp(frame->sf_code, __NR_sigreturn);
279 412
280 err |= setup_sigcontext(regs, &frame->sf_sc); 413 err |= setup_sigcontext(regs, &frame->sf_sc);
281 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 414 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
@@ -299,12 +432,10 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
299 regs->regs[31] = (unsigned long) frame->sf_code; 432 regs->regs[31] = (unsigned long) frame->sf_code;
300 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 433 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
301 434
302#if DEBUG_SIG 435 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
303 printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
304 current->comm, current->pid, 436 current->comm, current->pid,
305 frame, regs->cp0_epc, frame->regs[31]); 437 frame, regs->cp0_epc, regs->regs[31]);
306#endif 438 return 0;
307 return 0;
308 439
309give_sigsegv: 440give_sigsegv:
310 force_sigsegv(signr, current); 441 force_sigsegv(signr, current);
@@ -312,7 +443,7 @@ give_sigsegv:
312} 443}
313#endif 444#endif
314 445
315int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, 446static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
316 int signr, sigset_t *set, siginfo_t *info) 447 int signr, sigset_t *set, siginfo_t *info)
317{ 448{
318 struct rt_sigframe __user *frame; 449 struct rt_sigframe __user *frame;
@@ -322,7 +453,7 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
322 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 453 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
323 goto give_sigsegv; 454 goto give_sigsegv;
324 455
325 install_sigtramp(frame->rs_code, __NR_rt_sigreturn); 456 err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn);
326 457
327 /* Create siginfo. */ 458 /* Create siginfo. */
328 err |= copy_siginfo_to_user(&frame->rs_info, info); 459 err |= copy_siginfo_to_user(&frame->rs_info, info);
@@ -359,11 +490,10 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
359 regs->regs[31] = (unsigned long) frame->rs_code; 490 regs->regs[31] = (unsigned long) frame->rs_code;
360 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 491 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
361 492
362#if DEBUG_SIG 493 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
363 printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
364 current->comm, current->pid, 494 current->comm, current->pid,
365 frame, regs->cp0_epc, regs->regs[31]); 495 frame, regs->cp0_epc, regs->regs[31]);
366#endif 496
367 return 0; 497 return 0;
368 498
369give_sigsegv: 499give_sigsegv:
@@ -371,7 +501,15 @@ give_sigsegv:
371 return -EFAULT; 501 return -EFAULT;
372} 502}
373 503
374static inline int handle_signal(unsigned long sig, siginfo_t *info, 504struct mips_abi mips_abi = {
505#ifdef CONFIG_TRAD_SIGNALS
506 .setup_frame = setup_frame,
507#endif
508 .setup_rt_frame = setup_rt_frame,
509 .restart = __NR_restart_syscall
510};
511
512static int handle_signal(unsigned long sig, siginfo_t *info,
375 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) 513 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
376{ 514{
377 int ret; 515 int ret;
@@ -409,7 +547,7 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
409 return ret; 547 return ret;
410} 548}
411 549
412void do_signal(struct pt_regs *regs) 550static void do_signal(struct pt_regs *regs)
413{ 551{
414 struct k_sigaction ka; 552 struct k_sigaction ka;
415 sigset_t *oldset; 553 sigset_t *oldset;
@@ -459,7 +597,7 @@ void do_signal(struct pt_regs *regs)
459 regs->cp0_epc -= 8; 597 regs->cp0_epc -= 8;
460 } 598 }
461 if (regs->regs[2] == ERESTART_RESTARTBLOCK) { 599 if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
462 regs->regs[2] = __NR_restart_syscall; 600 regs->regs[2] = current->thread.abi->restart;
463 regs->regs[7] = regs->regs[26]; 601 regs->regs[7] = regs->regs[26];
464 regs->cp0_epc -= 4; 602 regs->cp0_epc -= 4;
465 } 603 }
@@ -485,5 +623,5 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
485{ 623{
486 /* deal with pending signal delivery */ 624 /* deal with pending signal delivery */
487 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) 625 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
488 current->thread.abi->do_signal(regs); 626 do_signal(regs);
489} 627}