aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-10-30 21:37:12 -0500
committerPaul Mackerras <paulus@samba.org>2005-10-30 21:37:12 -0500
commit23fd07750a789a66fe88cf173d52a18f1a387da4 (patch)
tree06fdd6df35fdb835abdaa9b754d62f6b84b97250 /arch/mips/kernel/signal.c
parentbd787d438a59266af3c9f6351644c85ef1dd21fe (diff)
parented28f96ac1960f30f818374d65be71d2fdf811b0 (diff)
Merge ../linux-2.6 by hand
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r--arch/mips/kernel/signal.c143
1 files changed, 56 insertions, 87 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 0209c1dd1429..9202a17db8f7 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -8,6 +8,7 @@
8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 8 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9 */ 9 */
10#include <linux/config.h> 10#include <linux/config.h>
11#include <linux/cache.h>
11#include <linux/sched.h> 12#include <linux/sched.h>
12#include <linux/mm.h> 13#include <linux/mm.h>
13#include <linux/personality.h> 14#include <linux/personality.h>
@@ -21,6 +22,7 @@
21#include <linux/unistd.h> 22#include <linux/unistd.h>
22#include <linux/compiler.h> 23#include <linux/compiler.h>
23 24
25#include <asm/abi.h>
24#include <asm/asm.h> 26#include <asm/asm.h>
25#include <linux/bitops.h> 27#include <linux/bitops.h>
26#include <asm/cacheflush.h> 28#include <asm/cacheflush.h>
@@ -29,6 +31,7 @@
29#include <asm/uaccess.h> 31#include <asm/uaccess.h>
30#include <asm/ucontext.h> 32#include <asm/ucontext.h>
31#include <asm/cpu-features.h> 33#include <asm/cpu-features.h>
34#include <asm/war.h>
32 35
33#include "signal-common.h" 36#include "signal-common.h"
34 37
@@ -36,7 +39,7 @@
36 39
37#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 40#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
38 41
39static int do_signal(sigset_t *oldset, struct pt_regs *regs); 42int do_signal(sigset_t *oldset, struct pt_regs *regs);
40 43
41/* 44/*
42 * Atomically swap in the new signal mask, and wait for a signal. 45 * Atomically swap in the new signal mask, and wait for a signal.
@@ -47,9 +50,10 @@ save_static_function(sys_sigsuspend);
47__attribute_used__ noinline static int 50__attribute_used__ noinline static int
48_sys_sigsuspend(nabi_no_regargs struct pt_regs regs) 51_sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
49{ 52{
50 sigset_t *uset, saveset, newset; 53 sigset_t saveset, newset;
54 sigset_t __user *uset;
51 55
52 uset = (sigset_t *) regs.regs[4]; 56 uset = (sigset_t __user *) regs.regs[4];
53 if (copy_from_user(&newset, uset, sizeof(sigset_t))) 57 if (copy_from_user(&newset, uset, sizeof(sigset_t)))
54 return -EFAULT; 58 return -EFAULT;
55 sigdelsetmask(&newset, ~_BLOCKABLE); 59 sigdelsetmask(&newset, ~_BLOCKABLE);
@@ -75,7 +79,8 @@ save_static_function(sys_rt_sigsuspend);
75__attribute_used__ noinline static int 79__attribute_used__ noinline static int
76_sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) 80_sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
77{ 81{
78 sigset_t *unewset, saveset, newset; 82 sigset_t saveset, newset;
83 sigset_t __user *unewset;
79 size_t sigsetsize; 84 size_t sigsetsize;
80 85
81 /* XXX Don't preclude handling different sized sigset_t's. */ 86 /* XXX Don't preclude handling different sized sigset_t's. */
@@ -83,7 +88,7 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
83 if (sigsetsize != sizeof(sigset_t)) 88 if (sigsetsize != sizeof(sigset_t))
84 return -EINVAL; 89 return -EINVAL;
85 90
86 unewset = (sigset_t *) regs.regs[4]; 91 unewset = (sigset_t __user *) regs.regs[4];
87 if (copy_from_user(&newset, unewset, sizeof(newset))) 92 if (copy_from_user(&newset, unewset, sizeof(newset)))
88 return -EFAULT; 93 return -EFAULT;
89 sigdelsetmask(&newset, ~_BLOCKABLE); 94 sigdelsetmask(&newset, ~_BLOCKABLE);
@@ -147,33 +152,46 @@ asmlinkage int sys_sigaction(int sig, const struct sigaction *act,
147 152
148asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs) 153asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs)
149{ 154{
150 const stack_t *uss = (const stack_t *) regs.regs[4]; 155 const stack_t __user *uss = (const stack_t __user *) regs.regs[4];
151 stack_t *uoss = (stack_t *) regs.regs[5]; 156 stack_t __user *uoss = (stack_t __user *) regs.regs[5];
152 unsigned long usp = regs.regs[29]; 157 unsigned long usp = regs.regs[29];
153 158
154 return do_sigaltstack(uss, uoss, usp); 159 return do_sigaltstack(uss, uoss, usp);
155} 160}
156 161
157#if PLAT_TRAMPOLINE_STUFF_LINE 162/*
158#define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE))) 163 * Horribly complicated - with the bloody RM9000 workarounds enabled
159#else 164 * the signal trampolines is moving to the end of the structure so we can
160#define __tramp 165 * increase the alignment without breaking software compatibility.
161#endif 166 */
162
163#ifdef CONFIG_TRAD_SIGNALS 167#ifdef CONFIG_TRAD_SIGNALS
164struct sigframe { 168struct sigframe {
165 u32 sf_ass[4]; /* argument save space for o32 */ 169 u32 sf_ass[4]; /* argument save space for o32 */
166 u32 sf_code[2] __tramp; /* signal trampoline */ 170#if ICACHE_REFILLS_WORKAROUND_WAR
167 struct sigcontext sf_sc __tramp; 171 u32 sf_pad[2];
172#else
173 u32 sf_code[2]; /* signal trampoline */
174#endif
175 struct sigcontext sf_sc;
168 sigset_t sf_mask; 176 sigset_t sf_mask;
177#if ICACHE_REFILLS_WORKAROUND_WAR
178 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
179#endif
169}; 180};
170#endif 181#endif
171 182
172struct rt_sigframe { 183struct rt_sigframe {
173 u32 rs_ass[4]; /* argument save space for o32 */ 184 u32 rs_ass[4]; /* argument save space for o32 */
174 u32 rs_code[2] __tramp; /* signal trampoline */ 185#if ICACHE_REFILLS_WORKAROUND_WAR
175 struct siginfo rs_info __tramp; 186 u32 rs_pad[2];
187#else
188 u32 rs_code[2]; /* signal trampoline */
189#endif
190 struct siginfo rs_info;
176 struct ucontext rs_uc; 191 struct ucontext rs_uc;
192#if ICACHE_REFILLS_WORKAROUND_WAR
193 u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */
194#endif
177}; 195};
178 196
179#ifdef CONFIG_TRAD_SIGNALS 197#ifdef CONFIG_TRAD_SIGNALS
@@ -214,7 +232,7 @@ _sys_sigreturn(nabi_no_regargs struct pt_regs regs)
214badframe: 232badframe:
215 force_sig(SIGSEGV, current); 233 force_sig(SIGSEGV, current);
216} 234}
217#endif 235#endif /* CONFIG_TRAD_SIGNALS */
218 236
219save_static_function(sys_rt_sigreturn); 237save_static_function(sys_rt_sigreturn);
220__attribute_used__ noinline static void 238__attribute_used__ noinline static void
@@ -260,7 +278,7 @@ badframe:
260} 278}
261 279
262#ifdef CONFIG_TRAD_SIGNALS 280#ifdef CONFIG_TRAD_SIGNALS
263static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs, 281int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
264 int signr, sigset_t *set) 282 int signr, sigset_t *set)
265{ 283{
266 struct sigframe *frame; 284 struct sigframe *frame;
@@ -270,17 +288,7 @@ static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
270 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 288 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
271 goto give_sigsegv; 289 goto give_sigsegv;
272 290
273 /* 291 install_sigtramp(frame->sf_code, __NR_sigreturn);
274 * Set up the return code ...
275 *
276 * li v0, __NR_sigreturn
277 * syscall
278 */
279 if (PLAT_TRAMPOLINE_STUFF_LINE)
280 __clear_user(frame->sf_code, PLAT_TRAMPOLINE_STUFF_LINE);
281 err |= __put_user(0x24020000 + __NR_sigreturn, frame->sf_code + 0);
282 err |= __put_user(0x0000000c , frame->sf_code + 1);
283 flush_cache_sigtramp((unsigned long) frame->sf_code);
284 292
285 err |= setup_sigcontext(regs, &frame->sf_sc); 293 err |= setup_sigcontext(regs, &frame->sf_sc);
286 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 294 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
@@ -309,14 +317,15 @@ static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
309 current->comm, current->pid, 317 current->comm, current->pid,
310 frame, regs->cp0_epc, frame->regs[31]); 318 frame, regs->cp0_epc, frame->regs[31]);
311#endif 319#endif
312 return; 320 return 1;
313 321
314give_sigsegv: 322give_sigsegv:
315 force_sigsegv(signr, current); 323 force_sigsegv(signr, current);
324 return 0;
316} 325}
317#endif 326#endif
318 327
319static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, 328int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
320 int signr, sigset_t *set, siginfo_t *info) 329 int signr, sigset_t *set, siginfo_t *info)
321{ 330{
322 struct rt_sigframe *frame; 331 struct rt_sigframe *frame;
@@ -326,17 +335,7 @@ static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
326 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 335 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
327 goto give_sigsegv; 336 goto give_sigsegv;
328 337
329 /* 338 install_sigtramp(frame->rs_code, __NR_rt_sigreturn);
330 * Set up the return code ...
331 *
332 * li v0, __NR_rt_sigreturn
333 * syscall
334 */
335 if (PLAT_TRAMPOLINE_STUFF_LINE)
336 __clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE);
337 err |= __put_user(0x24020000 + __NR_rt_sigreturn, frame->rs_code + 0);
338 err |= __put_user(0x0000000c , frame->rs_code + 1);
339 flush_cache_sigtramp((unsigned long) frame->rs_code);
340 339
341 /* Create siginfo. */ 340 /* Create siginfo. */
342 err |= copy_siginfo_to_user(&frame->rs_info, info); 341 err |= copy_siginfo_to_user(&frame->rs_info, info);
@@ -378,18 +377,21 @@ static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
378 current->comm, current->pid, 377 current->comm, current->pid,
379 frame, regs->cp0_epc, regs->regs[31]); 378 frame, regs->cp0_epc, regs->regs[31]);
380#endif 379#endif
381 return; 380 return 1;
382 381
383give_sigsegv: 382give_sigsegv:
384 force_sigsegv(signr, current); 383 force_sigsegv(signr, current);
384 return 0;
385} 385}
386 386
387extern void setup_rt_frame_n32(struct k_sigaction * ka, 387extern void setup_rt_frame_n32(struct k_sigaction * ka,
388 struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info); 388 struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info);
389 389
390static inline void handle_signal(unsigned long sig, siginfo_t *info, 390static inline int handle_signal(unsigned long sig, siginfo_t *info,
391 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) 391 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
392{ 392{
393 int ret;
394
393 switch(regs->regs[0]) { 395 switch(regs->regs[0]) {
394 case ERESTART_RESTARTBLOCK: 396 case ERESTART_RESTARTBLOCK:
395 case ERESTARTNOHAND: 397 case ERESTARTNOHAND:
@@ -408,22 +410,10 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
408 410
409 regs->regs[0] = 0; /* Don't deal with this again. */ 411 regs->regs[0] = 0; /* Don't deal with this again. */
410 412
411#ifdef CONFIG_TRAD_SIGNALS 413 if (sig_uses_siginfo(ka))
412 if (ka->sa.sa_flags & SA_SIGINFO) { 414 ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info);
413#else
414 if (1) {
415#endif
416#ifdef CONFIG_MIPS32_N32
417 if ((current->thread.mflags & MF_ABI_MASK) == MF_N32)
418 setup_rt_frame_n32 (ka, regs, sig, oldset, info);
419 else
420#endif
421 setup_rt_frame(ka, regs, sig, oldset, info);
422 }
423#ifdef CONFIG_TRAD_SIGNALS
424 else 415 else
425 setup_frame(ka, regs, sig, oldset); 416 ret = current->thread.abi->setup_frame(ka, regs, sig, oldset);
426#endif
427 417
428 spin_lock_irq(&current->sighand->siglock); 418 spin_lock_irq(&current->sighand->siglock);
429 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); 419 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -431,23 +421,16 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
431 sigaddset(&current->blocked,sig); 421 sigaddset(&current->blocked,sig);
432 recalc_sigpending(); 422 recalc_sigpending();
433 spin_unlock_irq(&current->sighand->siglock); 423 spin_unlock_irq(&current->sighand->siglock);
434}
435 424
436extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); 425 return ret;
437extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs); 426}
438 427
439static int do_signal(sigset_t *oldset, struct pt_regs *regs) 428int do_signal(sigset_t *oldset, struct pt_regs *regs)
440{ 429{
441 struct k_sigaction ka; 430 struct k_sigaction ka;
442 siginfo_t info; 431 siginfo_t info;
443 int signr; 432 int signr;
444 433
445#ifdef CONFIG_BINFMT_ELF32
446 if ((current->thread.mflags & MF_ABI_MASK) == MF_O32) {
447 return do_signal32(oldset, regs);
448 }
449#endif
450
451 /* 434 /*
452 * We want the common case to go fast, which is why we may in certain 435 * We want the common case to go fast, which is why we may in certain
453 * cases get here from kernel mode. Just return without doing anything 436 * cases get here from kernel mode. Just return without doing anything
@@ -463,10 +446,8 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs)
463 oldset = &current->blocked; 446 oldset = &current->blocked;
464 447
465 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 448 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
466 if (signr > 0) { 449 if (signr > 0)
467 handle_signal(signr, &info, &ka, oldset, regs); 450 return handle_signal(signr, &info, &ka, oldset, regs);
468 return 1;
469 }
470 451
471no_signal: 452no_signal:
472 /* 453 /*
@@ -499,18 +480,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
499{ 480{
500 /* deal with pending signal delivery */ 481 /* deal with pending signal delivery */
501 if (thread_info_flags & _TIF_SIGPENDING) { 482 if (thread_info_flags & _TIF_SIGPENDING) {
502#ifdef CONFIG_BINFMT_ELF32 483 current->thread.abi->do_signal(oldset, regs);
503 if (likely((current->thread.mflags & MF_ABI_MASK) == MF_O32)) {
504 do_signal32(oldset, regs);
505 return;
506 }
507#endif
508#ifdef CONFIG_BINFMT_IRIX
509 if (unlikely(current->personality != PER_LINUX)) {
510 do_irix_signal(oldset, regs);
511 return;
512 }
513#endif
514 do_signal(oldset, regs);
515 } 484 }
516} 485}