]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/s390/kernel/compat_signal.c
Merge remote-tracking branch 'net-next/master'
[karo-tx-linux.git] / arch / s390 / kernel / compat_signal.c
index adaa9e9478d83fb77a2e91a41de0934f84acfb66..5a3ab5c191fdaf7f370a14cc69d52eb9d3052647 100644 (file)
@@ -153,57 +153,66 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 
 static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
 {
-       _s390_regs_common32 regs32;
-       int err, i;
+       _sigregs32 user_sregs;
+       int i;
 
-       regs32.psw.mask = psw32_user_bits |
-               ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER);
-       regs32.psw.addr = (__u32) regs->psw.addr |
+       user_sregs.regs.psw.mask = (__u32)(regs->psw.mask >> 32);
+       user_sregs.regs.psw.mask &= PSW32_MASK_USER | PSW32_MASK_RI;
+       user_sregs.regs.psw.mask |= PSW32_USER_BITS;
+       user_sregs.regs.psw.addr = (__u32) regs->psw.addr |
                (__u32)(regs->psw.mask & PSW_MASK_BA);
        for (i = 0; i < NUM_GPRS; i++)
-               regs32.gprs[i] = (__u32) regs->gprs[i];
+               user_sregs.regs.gprs[i] = (__u32) regs->gprs[i];
        save_access_regs(current->thread.acrs);
-       memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));
-       err = __copy_to_user(&sregs->regs, &regs32, sizeof(regs32));
-       if (err)
-               return err;
-       save_fp_regs(&current->thread.fp_regs);
-       /* s390_fp_regs and _s390_fp_regs32 are the same ! */
-       return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
-                             sizeof(_s390_fp_regs32));
+       memcpy(&user_sregs.regs.acrs, current->thread.acrs,
+              sizeof(user_sregs.regs.acrs));
+       save_fp_ctl(&current->thread.fp_regs.fpc);
+       save_fp_regs(current->thread.fp_regs.fprs);
+       memcpy(&user_sregs.fpregs, &current->thread.fp_regs,
+              sizeof(user_sregs.fpregs));
+       if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs32)))
+               return -EFAULT;
+       return 0;
 }
 
 static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
 {
-       _s390_regs_common32 regs32;
-       int err, i;
+       _sigregs32 user_sregs;
+       int i;
 
        /* Alwys make any pending restarted system call return -EINTR */
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-       err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
-       if (err)
-               return err;
+       if (__copy_from_user(&user_sregs, &sregs->regs, sizeof(user_sregs)))
+               return -EFAULT;
+
+       if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW32_MASK_RI))
+               return -EINVAL;
+
+       /* Loading the floating-point-control word can fail. Do that first. */
+       if (restore_fp_ctl(&user_sregs.fpregs.fpc))
+               return -EINVAL;
+
+       /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
        regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
-               (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
-               (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
+               (__u64)(user_sregs.regs.psw.mask & PSW32_MASK_USER) << 32 |
+               (__u64)(user_sregs.regs.psw.mask & PSW32_MASK_RI) << 32 |
+               (__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_AMODE);
        /* Check for invalid user address space control. */
-       if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC))
-               regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) |
+       if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME)
+               regs->psw.mask = PSW_ASC_PRIMARY |
                        (regs->psw.mask & ~PSW_MASK_ASC);
-       regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
+       regs->psw.addr = (__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_INSN);
        for (i = 0; i < NUM_GPRS; i++)
-               regs->gprs[i] = (__u64) regs32.gprs[i];
-       memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));
+               regs->gprs[i] = (__u64) user_sregs.regs.gprs[i];
+       memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
+              sizeof(current->thread.acrs));
        restore_access_regs(current->thread.acrs);
 
-       err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
-                              sizeof(_s390_fp_regs32));
-       current->thread.fp_regs.fpc &= FPC_VALID_MASK;
-       if (err)
-               return err;
+       memcpy(&current->thread.fp_regs, &user_sregs.fpregs,
+              sizeof(current->thread.fp_regs));
 
-       restore_fp_regs(&current->thread.fp_regs);
+       restore_fp_regs(current->thread.fp_regs.fprs);
        clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */
        return 0;
 }
@@ -215,18 +224,18 @@ static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
 
        for (i = 0; i < NUM_GPRS; i++)
                gprs_high[i] = regs->gprs[i] >> 32;
-
-       return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high));
+       if (__copy_to_user(uregs, &gprs_high, sizeof(gprs_high)))
+               return -EFAULT;
+       return 0;
 }
 
 static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
 {
        __u32 gprs_high[NUM_GPRS];
-       int err, i;
+       int i;
 
-       err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high));
-       if (err)
-               return err;
+       if (__copy_from_user(&gprs_high, uregs, sizeof(gprs_high)))
+               return -EFAULT;
        for (i = 0; i < NUM_GPRS; i++)
                *(__u32 *)&regs->gprs[i] = gprs_high[i];
        return 0;
@@ -348,7 +357,7 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
        regs->gprs[15] = (__force __u64) frame;
        /* Force 31 bit amode and default user address space control. */
        regs->psw.mask = PSW_MASK_BA |
-               (psw_user_bits & PSW_MASK_ASC) |
+               (PSW_USER_BITS & PSW_MASK_ASC) |
                (regs->psw.mask & ~PSW_MASK_ASC);
        regs->psw.addr = (__force __u64) ka->sa.sa_handler;
 
@@ -415,7 +424,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->gprs[15] = (__force __u64) frame;
        /* Force 31 bit amode and default user address space control. */
        regs->psw.mask = PSW_MASK_BA |
-               (psw_user_bits & PSW_MASK_ASC) |
+               (PSW_USER_BITS & PSW_MASK_ASC) |
                (regs->psw.mask & ~PSW_MASK_ASC);
        regs->psw.addr = (__u64 __force) ka->sa.sa_handler;