diff options
author | Wilson Callan <wcallan@savantav.com> | 2008-04-30 22:16:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-01 11:08:35 -0400 |
commit | 2d7f16d6d12682c41fb287ea8261df8e4679f638 (patch) | |
tree | c9e8bce26b85ec9f4790e0f18baaa24c8f6d8f38 /arch/m68knommu/kernel | |
parent | 10ed2195bb8aef4358223f07bb00e8cf9b278bf2 (diff) |
m68knommu: fix signal handling return path
The return from software signal handling pushes code on the stack
that system calls to the kernels cleanup code. This is borrowed
directly from the m68k linux signal handler.
The rt signal case is not quite right for the restricted instruction
set of the ColdFire parts. And neither the normal signal case or rt
signal case properly flushes/pushes the appropriate cache lines.
Rework the return path to just call back through some code fragments
in the kernel proper (with no MMU in the way we can do this). No
cache problems, and less code overall.
Original patch submitted by Wilson Callan <wcallan@savantav.com>
Greg fixed the rt signal return path to use the proper system call
Signed-off-by: Greg Ungerer <gerg@uclinux.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/m68knommu/kernel')
-rw-r--r-- | arch/m68knommu/kernel/entry.S | 9 | ||||
-rw-r--r-- | arch/m68knommu/kernel/signal.c | 21 |
2 files changed, 13 insertions, 17 deletions
diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S index 1e7ea6a3e1a1..f4782d2dce8f 100644 --- a/arch/m68knommu/kernel/entry.S +++ b/arch/m68knommu/kernel/entry.S | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/segment.h> | 32 | #include <asm/segment.h> |
33 | #include <asm/asm-offsets.h> | 33 | #include <asm/asm-offsets.h> |
34 | #include <asm/entry.h> | 34 | #include <asm/entry.h> |
35 | #include <asm/unistd.h> | ||
35 | 36 | ||
36 | .text | 37 | .text |
37 | 38 | ||
@@ -140,3 +141,11 @@ ENTRY(sys_rt_sigreturn) | |||
140 | RESTORE_SWITCH_STACK | 141 | RESTORE_SWITCH_STACK |
141 | rts | 142 | rts |
142 | 143 | ||
144 | ENTRY(ret_from_user_signal) | ||
145 | moveq #__NR_sigreturn,%d0 | ||
146 | trap #0 | ||
147 | |||
148 | ENTRY(ret_from_user_rt_signal) | ||
149 | move #__NR_rt_sigreturn,%d0 | ||
150 | trap #0 | ||
151 | |||
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c index 70371378db86..bbfcae9e52b4 100644 --- a/arch/m68knommu/kernel/signal.c +++ b/arch/m68knommu/kernel/signal.c | |||
@@ -51,6 +51,8 @@ | |||
51 | 51 | ||
52 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 52 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
53 | 53 | ||
54 | void ret_from_user_signal(void); | ||
55 | void ret_from_user_rt_signal(void); | ||
54 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); | 56 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); |
55 | 57 | ||
56 | /* | 58 | /* |
@@ -539,10 +541,6 @@ static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) | |||
539 | return err; | 541 | return err; |
540 | } | 542 | } |
541 | 543 | ||
542 | static inline void push_cache (unsigned long vaddr) | ||
543 | { | ||
544 | } | ||
545 | |||
546 | static inline void * | 544 | static inline void * |
547 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 545 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) |
548 | { | 546 | { |
@@ -586,16 +584,11 @@ static void setup_frame (int sig, struct k_sigaction *ka, | |||
586 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); | 584 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); |
587 | 585 | ||
588 | /* Set up to return from userspace. */ | 586 | /* Set up to return from userspace. */ |
589 | err |= __put_user(frame->retcode, &frame->pretcode); | 587 | err |= __put_user((void *) ret_from_user_signal, &frame->pretcode); |
590 | /* moveq #,d0; trap #0 */ | ||
591 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), | ||
592 | (long *)(frame->retcode)); | ||
593 | 588 | ||
594 | if (err) | 589 | if (err) |
595 | goto give_sigsegv; | 590 | goto give_sigsegv; |
596 | 591 | ||
597 | push_cache ((unsigned long) &frame->retcode); | ||
598 | |||
599 | /* Set up registers for signal handler */ | 592 | /* Set up registers for signal handler */ |
600 | wrusp ((unsigned long) frame); | 593 | wrusp ((unsigned long) frame); |
601 | regs->pc = (unsigned long) ka->sa.sa_handler; | 594 | regs->pc = (unsigned long) ka->sa.sa_handler; |
@@ -655,17 +648,11 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | |||
655 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); | 648 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); |
656 | 649 | ||
657 | /* Set up to return from userspace. */ | 650 | /* Set up to return from userspace. */ |
658 | err |= __put_user(frame->retcode, &frame->pretcode); | 651 | err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode); |
659 | /* moveq #,d0; notb d0; trap #0 */ | ||
660 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), | ||
661 | (long *)(frame->retcode + 0)); | ||
662 | err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); | ||
663 | 652 | ||
664 | if (err) | 653 | if (err) |
665 | goto give_sigsegv; | 654 | goto give_sigsegv; |
666 | 655 | ||
667 | push_cache ((unsigned long) &frame->retcode); | ||
668 | |||
669 | /* Set up registers for signal handler */ | 656 | /* Set up registers for signal handler */ |
670 | wrusp ((unsigned long) frame); | 657 | wrusp ((unsigned long) frame); |
671 | regs->pc = (unsigned long) ka->sa.sa_handler; | 658 | regs->pc = (unsigned long) ka->sa.sa_handler; |