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.c130
1 files changed, 64 insertions, 66 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 6254041b942f..2099d5a4c4b7 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -32,50 +32,33 @@
32#include <asm/ucontext.h> 32#include <asm/ucontext.h>
33#include <asm/cpu-features.h> 33#include <asm/cpu-features.h>
34#include <asm/war.h> 34#include <asm/war.h>
35#include <asm/vdso.h>
35 36
36#include "signal-common.h" 37#include "signal-common.h"
37 38
38/* 39static int (*save_fp_context)(struct sigcontext __user *sc);
39 * Horribly complicated - with the bloody RM9000 workarounds enabled 40static int (*restore_fp_context)(struct sigcontext __user *sc);
40 * the signal trampolines is moving to the end of the structure so we can 41
41 * increase the alignment without breaking software compatibility. 42extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
42 */ 43extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
43#if ICACHE_REFILLS_WORKAROUND_WAR == 0 44
45extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
46extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
44 47
45struct sigframe { 48struct sigframe {
46 u32 sf_ass[4]; /* argument save space for o32 */ 49 u32 sf_ass[4]; /* argument save space for o32 */
47 u32 sf_code[2]; /* signal trampoline */ 50 u32 sf_pad[2]; /* Was: signal trampoline */
48 struct sigcontext sf_sc; 51 struct sigcontext sf_sc;
49 sigset_t sf_mask; 52 sigset_t sf_mask;
50}; 53};
51 54
52struct rt_sigframe { 55struct rt_sigframe {
53 u32 rs_ass[4]; /* argument save space for o32 */ 56 u32 rs_ass[4]; /* argument save space for o32 */
54 u32 rs_code[2]; /* signal trampoline */ 57 u32 rs_pad[2]; /* Was: signal trampoline */
55 struct siginfo rs_info;
56 struct ucontext rs_uc;
57};
58
59#else
60
61struct sigframe {
62 u32 sf_ass[4]; /* argument save space for o32 */
63 u32 sf_pad[2];
64 struct sigcontext sf_sc; /* hw context */
65 sigset_t sf_mask;
66 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
67};
68
69struct rt_sigframe {
70 u32 rs_ass[4]; /* argument save space for o32 */
71 u32 rs_pad[2];
72 struct siginfo rs_info; 58 struct siginfo rs_info;
73 struct ucontext rs_uc; 59 struct ucontext rs_uc;
74 u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */
75}; 60};
76 61
77#endif
78
79/* 62/*
80 * Helper routines 63 * Helper routines
81 */ 64 */
@@ -257,32 +240,6 @@ void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
257 return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); 240 return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK));
258} 241}
259 242
260int install_sigtramp(unsigned int __user *tramp, unsigned int syscall)
261{
262 int err;
263
264 /*
265 * Set up the return code ...
266 *
267 * li v0, __NR__foo_sigreturn
268 * syscall
269 */
270
271 err = __put_user(0x24020000 + syscall, tramp + 0);
272 err |= __put_user(0x0000000c , tramp + 1);
273 if (ICACHE_REFILLS_WORKAROUND_WAR) {
274 err |= __put_user(0, tramp + 2);
275 err |= __put_user(0, tramp + 3);
276 err |= __put_user(0, tramp + 4);
277 err |= __put_user(0, tramp + 5);
278 err |= __put_user(0, tramp + 6);
279 err |= __put_user(0, tramp + 7);
280 }
281 flush_cache_sigtramp((unsigned long) tramp);
282
283 return err;
284}
285
286/* 243/*
287 * Atomically swap in the new signal mask, and wait for a signal. 244 * Atomically swap in the new signal mask, and wait for a signal.
288 */ 245 */
@@ -475,8 +432,8 @@ badframe:
475} 432}
476 433
477#ifdef CONFIG_TRAD_SIGNALS 434#ifdef CONFIG_TRAD_SIGNALS
478static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, 435static int setup_frame(void *sig_return, struct k_sigaction *ka,
479 int signr, sigset_t *set) 436 struct pt_regs *regs, int signr, sigset_t *set)
480{ 437{
481 struct sigframe __user *frame; 438 struct sigframe __user *frame;
482 int err = 0; 439 int err = 0;
@@ -485,8 +442,6 @@ static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
485 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 442 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
486 goto give_sigsegv; 443 goto give_sigsegv;
487 444
488 err |= install_sigtramp(frame->sf_code, __NR_sigreturn);
489
490 err |= setup_sigcontext(regs, &frame->sf_sc); 445 err |= setup_sigcontext(regs, &frame->sf_sc);
491 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 446 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
492 if (err) 447 if (err)
@@ -506,7 +461,7 @@ static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
506 regs->regs[ 5] = 0; 461 regs->regs[ 5] = 0;
507 regs->regs[ 6] = (unsigned long) &frame->sf_sc; 462 regs->regs[ 6] = (unsigned long) &frame->sf_sc;
508 regs->regs[29] = (unsigned long) frame; 463 regs->regs[29] = (unsigned long) frame;
509 regs->regs[31] = (unsigned long) frame->sf_code; 464 regs->regs[31] = (unsigned long) sig_return;
510 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 465 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
511 466
512 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 467 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
@@ -520,8 +475,9 @@ give_sigsegv:
520} 475}
521#endif 476#endif
522 477
523static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, 478static int setup_rt_frame(void *sig_return, struct k_sigaction *ka,
524 int signr, sigset_t *set, siginfo_t *info) 479 struct pt_regs *regs, int signr, sigset_t *set,
480 siginfo_t *info)
525{ 481{
526 struct rt_sigframe __user *frame; 482 struct rt_sigframe __user *frame;
527 int err = 0; 483 int err = 0;
@@ -530,8 +486,6 @@ static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
530 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 486 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
531 goto give_sigsegv; 487 goto give_sigsegv;
532 488
533 err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn);
534
535 /* Create siginfo. */ 489 /* Create siginfo. */
536 err |= copy_siginfo_to_user(&frame->rs_info, info); 490 err |= copy_siginfo_to_user(&frame->rs_info, info);
537 491
@@ -564,7 +518,7 @@ static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
564 regs->regs[ 5] = (unsigned long) &frame->rs_info; 518 regs->regs[ 5] = (unsigned long) &frame->rs_info;
565 regs->regs[ 6] = (unsigned long) &frame->rs_uc; 519 regs->regs[ 6] = (unsigned long) &frame->rs_uc;
566 regs->regs[29] = (unsigned long) frame; 520 regs->regs[29] = (unsigned long) frame;
567 regs->regs[31] = (unsigned long) frame->rs_code; 521 regs->regs[31] = (unsigned long) sig_return;
568 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 522 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
569 523
570 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 524 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
@@ -581,8 +535,11 @@ give_sigsegv:
581struct mips_abi mips_abi = { 535struct mips_abi mips_abi = {
582#ifdef CONFIG_TRAD_SIGNALS 536#ifdef CONFIG_TRAD_SIGNALS
583 .setup_frame = setup_frame, 537 .setup_frame = setup_frame,
538 .signal_return_offset = offsetof(struct mips_vdso, signal_trampoline),
584#endif 539#endif
585 .setup_rt_frame = setup_rt_frame, 540 .setup_rt_frame = setup_rt_frame,
541 .rt_signal_return_offset =
542 offsetof(struct mips_vdso, rt_signal_trampoline),
586 .restart = __NR_restart_syscall 543 .restart = __NR_restart_syscall
587}; 544};
588 545
@@ -590,6 +547,8 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
590 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) 547 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
591{ 548{
592 int ret; 549 int ret;
550 struct mips_abi *abi = current->thread.abi;
551 void *vdso = current->mm->context.vdso;
593 552
594 switch(regs->regs[0]) { 553 switch(regs->regs[0]) {
595 case ERESTART_RESTARTBLOCK: 554 case ERESTART_RESTARTBLOCK:
@@ -610,9 +569,11 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
610 regs->regs[0] = 0; /* Don't deal with this again. */ 569 regs->regs[0] = 0; /* Don't deal with this again. */
611 570
612 if (sig_uses_siginfo(ka)) 571 if (sig_uses_siginfo(ka))
613 ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); 572 ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset,
573 ka, regs, sig, oldset, info);
614 else 574 else
615 ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); 575 ret = abi->setup_frame(vdso + abi->signal_return_offset,
576 ka, regs, sig, oldset);
616 577
617 spin_lock_irq(&current->sighand->siglock); 578 spin_lock_irq(&current->sighand->siglock);
618 sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask); 579 sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
@@ -709,3 +670,40 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
709 key_replace_session_keyring(); 670 key_replace_session_keyring();
710 } 671 }
711} 672}
673
674#ifdef CONFIG_SMP
675static int smp_save_fp_context(struct sigcontext __user *sc)
676{
677 return raw_cpu_has_fpu
678 ? _save_fp_context(sc)
679 : fpu_emulator_save_context(sc);
680}
681
682static int smp_restore_fp_context(struct sigcontext __user *sc)
683{
684 return raw_cpu_has_fpu
685 ? _restore_fp_context(sc)
686 : fpu_emulator_restore_context(sc);
687}
688#endif
689
690static int signal_setup(void)
691{
692#ifdef CONFIG_SMP
693 /* For now just do the cpu_has_fpu check when the functions are invoked */
694 save_fp_context = smp_save_fp_context;
695 restore_fp_context = smp_restore_fp_context;
696#else
697 if (cpu_has_fpu) {
698 save_fp_context = _save_fp_context;
699 restore_fp_context = _restore_fp_context;
700 } else {
701 save_fp_context = fpu_emulator_save_context;
702 restore_fp_context = fpu_emulator_restore_context;
703 }
704#endif
705
706 return 0;
707}
708
709arch_initcall(signal_setup);