Merge branch 'master'
[pandora-kernel.git] / arch / i386 / kernel / signal.c
index ea46d02..adcd069 100644 (file)
@@ -278,9 +278,9 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
        int tmp, err = 0;
 
        tmp = 0;
-       __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
+       savesegment(gs, tmp);
        err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
-       __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
+       savesegment(fs, tmp);
        err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
 
        err |= __put_user(regs->xes, (unsigned int __user *)&sc->es);
@@ -338,7 +338,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
                esp = (unsigned long) ka->sa.sa_restorer;
        }
 
-       return (void __user *)((esp - frame_size) & -8ul);
+       esp -= frame_size;
+       /* Align the stack pointer according to the i386 ABI,
+        * i.e. so that on function entry ((sp + 4) & 15) == 0. */
+       esp = ((esp + 4) & -16ul) - 4;
+       return (void __user *) esp;
 }
 
 /* These symbols are defined with the addresses in the vsyscall page.
@@ -346,8 +350,8 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 extern void __user __kernel_sigreturn;
 extern void __user __kernel_rt_sigreturn;
 
-static void setup_frame(int sig, struct k_sigaction *ka,
-                       sigset_t *set, struct pt_regs * regs)
+static int setup_frame(int sig, struct k_sigaction *ka,
+                      sigset_t *set, struct pt_regs * regs)
 {
        void __user *restorer;
        struct sigframe __user *frame;
@@ -429,13 +433,14 @@ static void setup_frame(int sig, struct k_sigaction *ka,
                current->comm, current->pid, frame, regs->eip, frame->pretcode);
 #endif
 
-       return;
+       return 1;
 
 give_sigsegv:
        force_sigsegv(sig, current);
+       return 0;
 }
 
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                           sigset_t *set, struct pt_regs * regs)
 {
        void __user *restorer;
@@ -522,20 +527,23 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                current->comm, current->pid, frame, regs->eip, frame->pretcode);
 #endif
 
-       return;
+       return 1;
 
 give_sigsegv:
        force_sigsegv(sig, current);
+       return 0;
 }
 
 /*
  * OK, we're invoking a handler
  */    
 
-static void
+static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
              sigset_t *oldset, struct pt_regs * regs)
 {
+       int ret;
+
        /* Are we from a system call? */
        if (regs->orig_eax >= 0) {
                /* If so, check system call restarting.. */
@@ -569,17 +577,20 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 
        /* Set up the stack frame */
        if (ka->sa.sa_flags & SA_SIGINFO)
-               setup_rt_frame(sig, ka, info, oldset, regs);
+               ret = setup_rt_frame(sig, ka, info, oldset, regs);
        else
-               setup_frame(sig, ka, oldset, regs);
+               ret = setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-               sigaddset(&current->blocked,sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked,sig);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
+
+       return ret;
 }
 
 /*
@@ -597,15 +608,15 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
         * 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 so.  vm86 regs switched out by assembly code
+        * before reaching here, so testing against kernel
+        * CS suffices.
         */
-       if ((regs->xcs & 3) != 3)
+       if (!user_mode(regs))
                return 1;
 
-       if (current->flags & PF_FREEZE) {
-               refrigerator(0);
+       if (try_to_freeze())
                goto no_signal;
-       }
 
        if (!oldset)
                oldset = &current->blocked;
@@ -618,12 +629,11 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
                 * inside the kernel.
                 */
                if (unlikely(current->thread.debugreg[7])) {
-                       loaddebug(&current->thread, 7);
+                       set_debugreg(current->thread.debugreg[7], 7);
                }
 
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &info, &ka, oldset, regs);
-               return 1;
+               return handle_signal(signr, &info, &ka, oldset, regs);
        }
 
  no_signal: