microblaze: clean up signal handling
authorArnd Bergmann <arnd@arndb.de>
Thu, 18 Jun 2009 17:55:29 +0000 (19:55 +0200)
committerMichal Simek <monstr@monstr.eu>
Mon, 6 Jul 2009 08:26:57 +0000 (10:26 +0200)
When legacy signal handling is disabled, the
arch/microblaze/kernel/signal.c implementation can
be much simpler, as most of it is handled generically
from kernel/signal.c.

This is also a prerequisite for using the generic
asm/unistd.h, which does not provide __NR_sigreturn,
because this macro is referenced by the current signal.c
implementation.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Michal Simek <monstr@monstr.eu>
arch/microblaze/include/asm/signal.h
arch/microblaze/include/asm/syscalls.h
arch/microblaze/include/asm/unistd.h
arch/microblaze/kernel/entry-nommu.S
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/signal.c
arch/microblaze/kernel/syscall_table.S

index 46bc2267d9497a751de01b75324120b384f4ce5f..7b1573ce19de50ed695751b2af1bd8dfc54b86e8 100644 (file)
@@ -1,165 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *     Yasushi SHOJI <yashi@atmark-techno.com>
- *     Tetsuya OHKAWA <tetsuya@atmark-techno.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SIGNAL_H
-#define _ASM_MICROBLAZE_SIGNAL_H
-
-#define SIGHUP         1
-#define SIGINT         2
-#define SIGQUIT                3
-#define SIGILL         4
-#define SIGTRAP                5
-#define SIGABRT                6
-#define SIGIOT         6
-#define SIGBUS         7
-#define SIGFPE         8
-#define SIGKILL                9
-#define SIGUSR1                10
-#define SIGSEGV                11
-#define SIGUSR2                12
-#define SIGPIPE                13
-#define SIGALRM                14
-#define SIGTERM                15
-#define SIGSTKFLT      16
-#define SIGCHLD                17
-#define SIGCONT                18
-#define SIGSTOP                19
-#define SIGTSTP                20
-#define SIGTTIN                21
-#define SIGTTOU                22
-#define SIGURG         23
-#define SIGXCPU                24
-#define SIGXFSZ                25
-#define SIGVTALRM      26
-#define SIGPROF                27
-#define SIGWINCH       28
-#define SIGIO          29
-#define SIGPOLL                SIGIO
-/*
-#define SIGLOST                29
-*/
-#define SIGPWR         30
-#define SIGSYS         31
-#define        SIGUNUSED       31
-
-/* These should not be considered constants from userland. */
-#define SIGRTMIN       32
-#define SIGRTMAX       _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP   0x00000001
-#define SA_NOCLDWAIT   0x00000002
-#define SA_SIGINFO     0x00000004
-#define SA_ONSTACK     0x08000000
-#define SA_RESTART     0x10000000
-#define SA_NODEFER     0x40000000
-#define SA_RESETHAND   0x80000000
-
-#define SA_NOMASK      SA_NODEFER
-#define SA_ONESHOT     SA_RESETHAND
-
-#define SA_RESTORER    0x04000000
-
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
-#define MINSIGSTKSZ    2048
-#define SIGSTKSZ       8192
-
-# ifndef __ASSEMBLY__
-# include <linux/types.h>
-# include <asm-generic/signal-defs.h>
-
-/* Avoid too many header ordering problems. */
-struct siginfo;
-
-#  ifdef __KERNEL__
-/*
- * Most things should be clean enough to redefine this at will, if care
- * is taken to make libc match.
- */
-#  define _NSIG                64
-#  define _NSIG_BPW    32
-#  define _NSIG_WORDS  (_NSIG / _NSIG_BPW)
-
-typedef unsigned long old_sigset_t; /* at least 32 bits */
-
-typedef struct {
-       unsigned long sig[_NSIG_WORDS];
-} sigset_t;
-
-struct old_sigaction {
-       __sighandler_t sa_handler;
-       old_sigset_t sa_mask;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-};
-
-struct sigaction {
-       __sighandler_t sa_handler;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-       sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
-       struct sigaction sa;
-};
-
-#  include <asm/sigcontext.h>
-#  undef __HAVE_ARCH_SIG_BITOPS
-
-#  define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
-#  else /* !__KERNEL__ */
-
-/* Here we must cater to libcs that poke about in kernel headers. */
-
-#  define NSIG         32
-typedef unsigned long sigset_t;
-
-struct sigaction {
-       union {
-       __sighandler_t _sa_handler;
-       void (*_sa_sigaction)(int, struct siginfo *, void *);
-       } _u;
-       sigset_t sa_mask;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-};
-
-#  define sa_handler   _u._sa_handler
-#  define sa_sigaction _u._sa_sigaction
-
-#  endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
-       void *ss_sp;
-       int ss_flags;
-       size_t ss_size;
-} stack_t;
-
-# endif /* __ASSEMBLY__ */
-#endif /* _ASM_MICROBLAZE_SIGNAL_H */
+#include <asm-generic/signal.h>
index ddea9eb31f8da76aa4a3a820a7ee8a9c0744dae7..ea23843e2c26beddbfa663f4fffd327aa4f69697 100644 (file)
@@ -26,23 +26,16 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
                        unsigned long fd, off_t offset);
 
 /* from signal.c */
-asmlinkage int sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs);
-
-asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
+asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
                struct pt_regs *regs);
 
-asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act,
-               struct old_sigaction *oact);
-
 asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act,
                struct sigaction __user *oact, size_t sigsetsize);
 
 asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
                struct pt_regs *regs);
 
-asmlinkage int sys_sigreturn(struct pt_regs *regs);
-
-asmlinkage int sys_rt_sigreturn(struct pt_regs *regs);
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs);
 
 #endif /* __KERNEL__ */
 #endif /* __ASM_MICROBLAZE_SYSCALLS_H */
index b5e2f5fa5c53559adaf1cd1dd593b4c57aa34404..6c660c1446537060ca42f2bf278196bdca6abd3c 100644 (file)
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
-/* #define __ARCH_WANT_SYS_RT_SIGSUSPEND */
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 /*
  * "Conditional" syscalls
index 1fce6b803f54905b69ffadca0162a4db0593ed66..2eaf3946cb42e885dc87ea1bbe9a6f039bf7b735 100644 (file)
@@ -563,18 +563,10 @@ sys_execve_wrapper:
        brid    sys_execve
        addk    r8, r1, r0
 
-sys_sigreturn_wrapper:
-       brid    sys_sigreturn
-       addk    r5, r1, r0
-
 sys_rt_sigreturn_wrapper:
        brid    sys_rt_sigreturn
        addk    r5, r1, r0
 
-sys_sigsuspend_wrapper:
-       brid    sys_rt_sigsuspend
-       addk    r6, r1, r0
-
 sys_rt_sigsuspend_wrapper:
        brid    sys_rt_sigsuspend
        addk    r7, r1, r0
index 91a0e7b185dd998c0b51981adc43e81ced768361..ea7107652d8d11ae9101cb414d17c06e8b2f74c7 100644 (file)
@@ -449,17 +449,6 @@ C_ENTRY(sys_execve_wrapper):
        brid    sys_execve;     /* Do real work (tail-call).*/
        nop;
 
-C_ENTRY(sys_sigsuspend_wrapper):
-       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       swi     r4, r1, PTO+PT_R4;
-       la      r6, r1, PTO;            /* add user context as 2nd arg */
-       bralid  r15, sys_sigsuspend; /* Do real work.*/
-       nop;
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
-       bri ret_from_trap /* fall through will not work here due to align */
-       nop;
-
 C_ENTRY(sys_rt_sigsuspend_wrapper):
        swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
        swi     r4, r1, PTO+PT_R4;
@@ -471,18 +460,6 @@ C_ENTRY(sys_rt_sigsuspend_wrapper):
        bri ret_from_trap /* fall through will not work here due to align */
        nop;
 
-
-C_ENTRY(sys_sigreturn_wrapper):
-       swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       swi     r4, r1, PTO+PT_R4;
-       la      r5, r1, PTO;            /* add user context as 1st arg */
-       brlid   r15, sys_sigreturn;     /* Do real work.*/
-       nop;
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
-       bri ret_from_trap /* fall through will not work here due to align */
-       nop;
-
 C_ENTRY(sys_rt_sigreturn_wrapper):
        swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
        swi     r4, r1, PTO+PT_R4;
index 4c0e6521b1140e6d92183fb165b03076253a889d..2e5862c3002a769efbef96b125258d8eecf6a3de 100644 (file)
 
 asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
 
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs)
-{
-       sigset_t saveset;
-
-       mask &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
-       siginitset(&current->blocked, mask);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       regs->r3 = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(regs, &saveset, 1))
-                       return -EINTR;
-       }
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
-               struct pt_regs *regs)
-{
-       sigset_t saveset, newset;
-
-       /* XXX: Don't preclude handling different sized sigset_t's. */
-       if (sigsetsize != sizeof(sigset_t))
-               return -EINVAL;
-
-       if (copy_from_user(&newset, unewset, sizeof(newset)))
-               return -EFAULT;
-       sigdelsetmask(&newset, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       regs->r3 = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(regs, &saveset, 1))
-                       return -EINTR;
-       }
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction *act,
-               struct old_sigaction *oact)
-{
-       struct k_sigaction new_ka, old_ka;
-       int ret;
-
-       if (act) {
-               old_sigset_t mask;
-               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
-                       __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-                       __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
-                       return -EFAULT;
-               __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-               __get_user(mask, &act->sa_mask);
-               siginitset(&new_ka.sa.sa_mask, mask);
-       }
-
-       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-       if (!ret && oact) {
-               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
-                       __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-                       __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
-                       return -EFAULT;
-               __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-               __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-       }
-
-       return ret;
-}
 
 asmlinkage int
 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
@@ -139,7 +56,6 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
 /*
  * Do a signal return; undo the signal stack.
  */
-
 struct sigframe {
        struct sigcontext sc;
        unsigned long extramask[_NSIG_WORDS-1];
@@ -176,40 +92,7 @@ static int restore_sigcontext(struct pt_regs *regs,
        return err;
 }
 
-asmlinkage int sys_sigreturn(struct pt_regs *regs)
-{
-       struct sigframe *frame =
-                       (struct sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE);
-
-       sigset_t set;
-       int rval;
-
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-
-       if (__get_user(set.sig[0], &frame->sc.oldmask)
-               || (_NSIG_WORDS > 1
-               && __copy_from_user(&set.sig[1], &frame->extramask,
-                                       sizeof(frame->extramask))))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       if (restore_sigcontext(regs, &frame->sc, &rval))
-               goto badframe;
-       return rval;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}
-
-asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame =
                (struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE);
@@ -324,21 +207,17 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        /* Set up to return from userspace. If provided, use a stub
         already in userspace. */
        /* minus 8 is offset to cater for "rtsd r15,8" */
-       if (ka->sa.sa_flags & SA_RESTORER) {
-               regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8;
-       } else {
-               /* addi r12, r0, __NR_sigreturn */
-               err |= __put_user(0x31800000 | __NR_rt_sigreturn ,
-                               frame->tramp + 0);
-               /* brki r14, 0x8 */
-               err |= __put_user(0xb9cc0008, frame->tramp + 1);
-
-               /* Return from sighandler will jump to the tramp.
-                Negative 8 offset because return is rtsd r15, 8 */
-               regs->r15 = ((unsigned long)frame->tramp)-8;
-
-               __invalidate_cache_sigtramp((unsigned long)frame->tramp);
-       }
+       /* addi r12, r0, __NR_sigreturn */
+       err |= __put_user(0x31800000 | __NR_rt_sigreturn ,
+                       frame->tramp + 0);
+       /* brki r14, 0x8 */
+       err |= __put_user(0xb9cc0008, frame->tramp + 1);
+
+       /* Return from sighandler will jump to the tramp.
+        Negative 8 offset because return is rtsd r15, 8 */
+       regs->r15 = ((unsigned long)frame->tramp)-8;
+
+       __invalidate_cache_sigtramp((unsigned long)frame->tramp);
 
        if (err)
                goto give_sigsegv;
@@ -405,7 +284,7 @@ do_restart:
  * OK, we're invoking a handler
  */
 
-static void
+static int
 handle_signal(unsigned long sig, struct k_sigaction *ka,
                siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
@@ -426,6 +305,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
+       return 1;
 }
 
 /*
@@ -456,7 +336,9 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
        if (kernel_mode(regs))
                return 1;
 
-       if (!oldset)
+       if (current_thread_info()->status & TS_RESTORE_SIGMASK)
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->blocked;
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -464,13 +346,31 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
                /* Whee! Actually deliver the signal. */
                if (in_syscall)
                        handle_restart(regs, &ka, 1);
-               handle_signal(signr, &ka, &info, oldset, regs);
+               if (handle_signal(signr, &ka, &info, oldset, regs)) {
+                       /*
+                        * A signal was successfully delivered; the saved
+                        * sigmask will have been stored in the signal frame,
+                        * and will be restored by sigreturn, so we can simply
+                        * clear the TS_RESTORE_SIGMASK flag.
+                        */
+                       current_thread_info()->status &=
+                           ~TS_RESTORE_SIGMASK;
+               }
                return 1;
        }
 
        if (in_syscall)
                handle_restart(regs, NULL, 0);
 
+       /*
+        * If there's no signal to deliver, we just put the saved sigmask
+        * back.
+        */
+       if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+               current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
+
        /* Did we come from a system call? */
        return 0;
 }
index 376d1789f7c065e436fdf39d7b3e2f8f2318494f..ef0e8932af33aebdb16423dba76891ac360a8f6b 100644 (file)
@@ -71,12 +71,12 @@ ENTRY(sys_call_table)
        .long sys_getppid
        .long sys_getpgrp               /* 65 */
        .long sys_setsid
-       .long sys_sigaction
+       .long sys_ni_syscall            /* sys_sigaction */
        .long sys_sgetmask
        .long sys_ssetmask
        .long sys_setreuid              /* 70 */
        .long sys_setregid
-       .long sys_sigsuspend_wrapper
+       .long sys_ni_syscall            /* sys_sigsuspend_wrapper */
        .long sys_sigpending
        .long sys_sethostname
        .long sys_setrlimit             /* 75 */
@@ -123,7 +123,7 @@ ENTRY(sys_call_table)
        .long sys_sysinfo
        .long sys_ipc
        .long sys_fsync
-       .long sys_sigreturn_wrapper
+       .long sys_ni_syscall            /* sys_sigreturn_wrapper */
        .long sys_clone_wrapper         /* 120 */
        .long sys_setdomainname
        .long sys_newuname