fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / m68knommu / kernel / signal.c
index 0d58915..437f8c6 100644 (file)
@@ -116,7 +116,7 @@ sys_sigaction(int sig, const struct old_sigaction *act,
 
        if (act) {
                old_sigset_t mask;
-               if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+               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;
@@ -128,7 +128,7 @@ sys_sigaction(int sig, const struct old_sigaction *act,
        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
        if (!ret && oact) {
-               if (verify_area(VERIFY_WRITE, oact, sizeof(*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;
@@ -285,6 +285,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
        regs->d1 = context.sc_d1;
        regs->a0 = context.sc_a0;
        regs->a1 = context.sc_a1;
+       ((struct switch_stack *)regs - 1)->a5 = context.sc_a5;
        regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
        regs->pc = context.sc_pc;
        regs->orig_d0 = -1;             /* disable syscall checks */
@@ -360,7 +361,7 @@ asmlinkage int do_sigreturn(unsigned long __unused)
        sigset_t set;
        int d0;
 
-       if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
        if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
            (_NSIG_WORDS > 1 &&
@@ -392,7 +393,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
        sigset_t set;
        int d0;
 
-       if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
                goto badframe;
@@ -498,6 +499,7 @@ static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
        sc->sc_d1 = regs->d1;
        sc->sc_a0 = regs->a0;
        sc->sc_a1 = regs->a1;
+       sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5;
        sc->sc_sr = regs->sr;
        sc->sc_pc = regs->pc;
        sc->sc_formatvec = regs->format << 12 | regs->vector;
@@ -551,7 +553,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 
        /* This is the X/Open sanctioned signal stack switching.  */
        if (ka->sa.sa_flags & SA_ONSTACK) {
-               if (!on_sig_stack(usp))
+               if (!sas_ss_flags(usp))
                        usp = current->sas_ss_sp + current->sas_ss_size;
        }
        return (void *)((usp - frame_size) & -8UL);
@@ -597,13 +599,16 @@ static void setup_frame (int sig, struct k_sigaction *ka,
        /* Set up registers for signal handler */
        wrusp ((unsigned long) frame);
        regs->pc = (unsigned long) ka->sa.sa_handler;
+       ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
+       regs->format = 0x4; /*set format byte to make stack appear modulo 4 
+                                               which it will be when doing the rte */
 
 adjust_stack:
        /* Prepare to skip over the extra stuff in the exception frame.  */
        if (regs->stkadj) {
                struct pt_regs *tregs =
                        (struct pt_regs *)((ulong)regs + regs->stkadj);
-#if DEBUG
+#if defined(DEBUG)
                printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
 #endif
                /* This must be copied with decreasing addresses to
@@ -664,13 +669,16 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
        /* Set up registers for signal handler */
        wrusp ((unsigned long) frame);
        regs->pc = (unsigned long) ka->sa.sa_handler;
+       ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
+       regs->format = 0x4; /*set format byte to make stack appear modulo 4 
+                                               which it will be when doing the rte */
 
 adjust_stack:
        /* Prepare to skip over the extra stuff in the exception frame.  */
        if (regs->stkadj) {
                struct pt_regs *tregs =
                        (struct pt_regs *)((ulong)regs + regs->stkadj);
-#if DEBUG
+#if defined(DEBUG)
                printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
 #endif
                /* This must be copied with decreasing addresses to
@@ -732,160 +740,56 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
- *
- * Note that we go through the signals twice: once to check the signals
- * that the kernel can handle, and then we build all the user-level signal
- * handling stack-frames in one go after that.
  */
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
+       struct k_sigaction ka;
        siginfo_t info;
-       struct k_sigaction *ka;
-
-       current->thread.esp0 = (unsigned long) regs;
+       int signr;
+
+       /*
+        * We want the common case to go fast, which
+        * is why we may in certain cases get here from
+        * kernel mode. Just return without doing anything
+        * if so.
+        */
+       if (!user_mode(regs))
+               return 1;
 
        if (!oldset)
                oldset = &current->blocked;
 
-       for (;;) {
-               int signr;
-
-               signr = get_signal_to_deliver(&info, regs, NULL);
-
-               if (!signr)
-                       break;
-
-               if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-                       current->exit_code = signr;
-                       current->state = TASK_STOPPED;
-                       regs->sr &= ~PS_T;
-
-                       /* Did we come from a system call? */
-                       if (regs->orig_d0 >= 0) {
-                               /* Restart the system call the same way as
-                                  if the process were not traced.  */
-                               struct k_sigaction *ka =
-                                       &current->sighand->action[signr-1];
-                               int has_handler =
-                                       (ka->sa.sa_handler != SIG_IGN &&
-                                        ka->sa.sa_handler != SIG_DFL);
-                               handle_restart(regs, ka, has_handler);
-                       }
-                       notify_parent(current, SIGCHLD);
-                       schedule();
-
-                       /* We're back.  Did the debugger cancel the sig?  */
-                       if (!(signr = current->exit_code)) {
-                       discard_frame:
-                           continue;
-                       }
-                       current->exit_code = 0;
-
-                       /* The debugger continued.  Ignore SIGSTOP.  */
-                       if (signr == SIGSTOP)
-                               goto discard_frame;
-
-                       /* Update the siginfo structure.  Is this good?  */
-                       if (signr != info.si_signo) {
-                               info.si_signo = signr;
-                               info.si_errno = 0;
-                               info.si_code = SI_USER;
-                               info.si_pid = current->parent->pid;
-                               info.si_uid = current->parent->uid;
-                       }
-
-                       /* If the (new) signal is now blocked, requeue it.  */
-                       if (sigismember(&current->blocked, signr)) {
-                               send_sig_info(signr, &info, current);
-                               continue;
-                       }
-               }
-
-               ka = &current->sighand->action[signr-1];
-               if (ka->sa.sa_handler == SIG_IGN) {
-                       if (signr != SIGCHLD)
-                               continue;
-                       /* Check for SIGCHLD: it's special.  */
-                       while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-                               /* nothing */;
-                       continue;
-               }
-
-               if (ka->sa.sa_handler == SIG_DFL) {
-                       int exit_code = signr;
-
-                       if (current->pid == 1)
-                               continue;
-
-                       switch (signr) {
-                       case SIGCONT: case SIGCHLD:
-                       case SIGWINCH: case SIGURG:
-                               continue;
-
-                       case SIGTSTP: case SIGTTIN: case SIGTTOU:
-                               if (is_orphaned_pgrp(process_group(current)))
-                                       continue;
-                               /* FALLTHRU */
-
-                       case SIGSTOP:
-                               current->state = TASK_STOPPED;
-                               current->exit_code = signr;
-                               if (!(current->parent->sighand->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
-                                       notify_parent(current, SIGCHLD);
-                               schedule();
-                               continue;
-
-                       case SIGQUIT: case SIGILL: case SIGTRAP:
-                       case SIGIOT: case SIGFPE: case SIGSEGV:
-                       case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-                               if (do_coredump(signr, exit_code, regs))
-                                       exit_code |= 0x80;
-                               /* FALLTHRU */
-
-                       default:
-                               sigaddset(&current->pending.signal, signr);
-                               recalc_sigpending();
-                               current->flags |= PF_SIGNALED;
-                               do_exit(exit_code);
-                               /* NOTREACHED */
-                       }
-               }
-
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+       if (signr > 0) {
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, ka, &info, oldset, regs);
+               handle_signal(signr, &ka, &info, oldset, regs);
                return 1;
        }
 
        /* Did we come from a system call? */
-       if (regs->orig_d0 >= 0)
+       if (regs->orig_d0 >= 0) {
                /* Restart the system call - no handlers present */
-               handle_restart(regs, NULL, 0);
-
-       /* If we are about to discard some frame stuff we must copy
-          over the remaining frame. */
-       if (regs->stkadj) {
-               struct pt_regs *tregs =
-                 (struct pt_regs *) ((ulong) regs + regs->stkadj);
-
-               /* This must be copied with decreasing addresses to
-                  handle overlaps.  */
-               tregs->vector = 0;
-               tregs->format = 0;
-               tregs->pc = regs->pc;
-               tregs->sr = regs->sr;
+               if (regs->d0 == -ERESTARTNOHAND
+                   || regs->d0 == -ERESTARTSYS
+                   || regs->d0 == -ERESTARTNOINTR) {
+                       regs->d0 = regs->orig_d0;
+                       regs->pc -= 2;
+               } else if (regs->d0 == -ERESTART_RESTARTBLOCK) {
+                       regs->d0 = __NR_restart_syscall;
+                       regs->pc -= 2;
+               }
        }
        return 0;
 }