x86: use sizeof(long) to unify signal_32|64.c
[sfrench/cifs-2.6.git] / arch / x86 / kernel / signal_64.c
index 7347bb14e306bb3ff66385beee9cc1e5c6a15113..1045a07eeaec44e62b86499a3304af8a2d198f4d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/stddef.h>
 #include <linux/personality.h>
 #include <linux/compiler.h>
+#include <asm/processor.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
+#define __FIX_EFLAGS   (X86_EFLAGS_AC | X86_EFLAGS_OF | \
+                        X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
+                        X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
+                        X86_EFLAGS_CF)
+
+#ifdef CONFIG_X86_32
+# define FIX_EFLAGS    (__FIX_EFLAGS | X86_EFLAGS_RF)
+#else
+# define FIX_EFLAGS    __FIX_EFLAGS
+#endif
+
 int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                sigset_t *set, struct pt_regs * regs); 
 int ia32_setup_frame(int sig, struct k_sigaction *ka,
@@ -87,7 +99,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned
        {
                unsigned int tmpflags;
                err |= __get_user(tmpflags, &sc->flags);
-               regs->flags = (regs->flags & ~0x40DD5) | (tmpflags & 0x40DD5);
+               regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
                regs->orig_ax = -1;             /* disable syscall checks */
        }
 
@@ -121,13 +133,11 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
        sigset_t set;
        unsigned long ax;
 
-       frame = (struct rt_sigframe __user *)(regs->sp - 8);
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) {
+       frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
-       } 
-       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) { 
+       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
                goto badframe;
-       } 
 
        sigdelsetmask(&set, ~_BLOCKABLE);
        spin_lock_irq(&current->sighand->siglock);
@@ -295,7 +305,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
           see include/asm-x86_64/uaccess.h for details. */
        set_fs(USER_DS);
 
-       regs->flags &= ~X86_EFLAGS_TF;
+       regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF);
        if (test_thread_flag(TIF_SINGLESTEP))
                ptrace_notify(SIGTRAP);
 #ifdef DEBUG_SIG
@@ -310,13 +320,42 @@ give_sigsegv:
        return -EFAULT;
 }
 
+/*
+ * Return -1L or the syscall number that @regs is executing.
+ */
+static long current_syscall(struct pt_regs *regs)
+{
+       /*
+        * We always sign-extend a -1 value being set here,
+        * so this is always either -1L or a syscall number.
+        */
+       return regs->orig_ax;
+}
+
+/*
+ * Return a value that is -EFOO if the system call in @regs->orig_ax
+ * returned an error.  This only works for @regs from @current.
+ */
+static long current_syscall_ret(struct pt_regs *regs)
+{
+#ifdef CONFIG_IA32_EMULATION
+       if (test_thread_flag(TIF_IA32))
+               /*
+                * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
+                * and will match correctly in comparisons.
+                */
+               return (int) regs->ax;
+#endif
+       return regs->ax;
+}
+
 /*
  * OK, we're invoking a handler
  */    
 
 static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
-               sigset_t *oldset, struct pt_regs *regs)
+             sigset_t *oldset, struct pt_regs *regs)
 {
        int ret;
 
@@ -327,24 +366,24 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 #endif
 
        /* Are we from a system call? */
-       if ((long)regs->orig_ax >= 0) {
+       if (current_syscall(regs) >= 0) {
                /* If so, check system call restarting.. */
-               switch (regs->ax) {
-                       case -ERESTART_RESTARTBLOCK:
-                       case -ERESTARTNOHAND:
-                               regs->ax = -EINTR;
-                               break;
+               switch (current_syscall_ret(regs)) {
+               case -ERESTART_RESTARTBLOCK:
+               case -ERESTARTNOHAND:
+                       regs->ax = -EINTR;
+                       break;
 
-                       case -ERESTARTSYS:
-                               if (!(ka->sa.sa_flags & SA_RESTART)) {
-                                       regs->ax = -EINTR;
-                                       break;
-                               }
-                               /* fallthrough */
-                       case -ERESTARTNOINTR:
-                               regs->ax = regs->orig_ax;
-                               regs->ip -= 2;
+               case -ERESTARTSYS:
+                       if (!(ka->sa.sa_flags & SA_RESTART)) {
+                               regs->ax = -EINTR;
                                break;
+                       }
+               /* fallthrough */
+               case -ERESTARTNOINTR:
+                       regs->ax = regs->orig_ax;
+                       regs->ip -= 2;
+                       break;
                }
        }
 
@@ -391,10 +430,11 @@ static void 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
+        * 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.
+        * X86_32: vm86 regs switched out by assembly code before reaching
+        * here, so testing against kernel CS suffices.
         */
        if (!user_mode(regs))
                return;
@@ -426,10 +466,9 @@ static void do_signal(struct pt_regs *regs)
        }
 
        /* Did we come from a system call? */
-       if ((long)regs->orig_ax >= 0) {
+       if (current_syscall(regs) >= 0) {
                /* Restart the system call - no handlers present */
-               long res = regs->ax;
-               switch (res) {
+               switch (current_syscall_ret(regs)) {
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
@@ -445,16 +484,18 @@ static void do_signal(struct pt_regs *regs)
                }
        }
 
-       /* if there's no signal to deliver, we just put the saved sigmask
-          back. */
+       /*
+        * If there's no signal to deliver, we just put the saved sigmask
+        * back.
+        */
        if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
                clear_thread_flag(TIF_RESTORE_SIGMASK);
                sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
        }
 }
 
-void
-do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
+void do_notify_resume(struct pt_regs *regs, void *unused,
+                     __u32 thread_info_flags)
 {
 #ifdef DEBUG_SIG
        printk("do_notify_resume flags:%x ip:%lx sp:%lx caller:%p pending:%x\n",
@@ -474,7 +515,7 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 #endif /* CONFIG_X86_MCE */
 
        /* deal with pending signal delivery */
-       if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
+       if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
                do_signal(regs);
 
        if (thread_info_flags & _TIF_HRTICK_RESCHED)