powerpc: Set used_(vsr|vr|spe) in sigreturn path when MSR bits are active
authorSimon Guo <wei.guo.simon@gmail.com>
Tue, 26 Jul 2016 08:06:01 +0000 (16:06 +0800)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 13 Sep 2016 07:37:12 +0000 (17:37 +1000)
Normally, when MSR[VSX/VR/SPE] bits == 1, the used_vsr/used_vr/used_spe
bit have already been set. However when loading a signal frame from user
space we need to explicitly set used_vsr/used_vr/used_spe to make them
consistent with the MSR bits from the signal frame.

For example, CRIU application, who utilizes sigreturn to restore
checkpointed process, will lead to the case where MSR[VSX] bit is active
in signal frame, but used_vsr bit is not set in the kernel. (the same
applies to VR/SPE).

This patch fixes this by always setting used_* bit when MSR related bits
are active in signal frame and we are doing sigreturn.

Based on a proposal by Benh.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Simon Guo <wei.guo.simon@gmail.com>
[mpe: Massage change log]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c

index 6856276a91cc615712854db03e4217abca36f49a..d2745375f27e1dbe01403bdd3259f8e16f8bea42 100644 (file)
@@ -699,6 +699,7 @@ static long restore_user_regs(struct pt_regs *regs,
                if (__copy_from_user(&current->thread.vr_state, &sr->mc_vregs,
                                     sizeof(sr->mc_vregs)))
                        return 1;
+               current->thread.used_vr = true;
        } else if (current->thread.used_vr)
                memset(&current->thread.vr_state, 0,
                       ELF_NVRREG * sizeof(vector128));
@@ -725,6 +726,7 @@ static long restore_user_regs(struct pt_regs *regs,
                 */
                if (copy_vsx_from_user(current, &sr->mc_vsregs))
                        return 1;
+               current->thread.used_vsr = true;
        } else if (current->thread.used_vsr)
                for (i = 0; i < 32 ; i++)
                        current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
@@ -744,6 +746,7 @@ static long restore_user_regs(struct pt_regs *regs,
                if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
                                     ELF_NEVRREG * sizeof(u32)))
                        return 1;
+               current->thread.used_spe = true;
        } else if (current->thread.used_spe)
                memset(current->thread.evr, 0, ELF_NEVRREG * sizeof(u32));
 
@@ -800,6 +803,7 @@ static long restore_tm_user_regs(struct pt_regs *regs,
                                     &tm_sr->mc_vregs,
                                     sizeof(sr->mc_vregs)))
                        return 1;
+               current->thread.used_vr = true;
        } else if (current->thread.used_vr) {
                memset(&current->thread.vr_state, 0,
                       ELF_NVRREG * sizeof(vector128));
@@ -833,6 +837,7 @@ static long restore_tm_user_regs(struct pt_regs *regs,
                if (copy_vsx_from_user(current, &sr->mc_vsregs) ||
                    copy_transact_vsx_from_user(current, &tm_sr->mc_vsregs))
                        return 1;
+               current->thread.used_vsr = true;
        } else if (current->thread.used_vsr)
                for (i = 0; i < 32 ; i++) {
                        current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
@@ -849,6 +854,7 @@ static long restore_tm_user_regs(struct pt_regs *regs,
                if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
                                     ELF_NEVRREG * sizeof(u32)))
                        return 1;
+               current->thread.used_spe = true;
        } else if (current->thread.used_spe)
                memset(current->thread.evr, 0, ELF_NEVRREG * sizeof(u32));
 
index f08c9196f209ecda8c2fbf8184b223d36aba9a94..6faa8240b7c9fd35a4b256f9c0cec2339f8b4f3f 100644 (file)
@@ -369,9 +369,11 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
        if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128)))
                return -EFAULT;
        /* Copy 33 vec registers (vr0..31 and vscr) from the stack */
-       if (v_regs != NULL && (msr & MSR_VEC) != 0)
+       if (v_regs != NULL && (msr & MSR_VEC) != 0) {
                err |= __copy_from_user(&current->thread.vr_state, v_regs,
                                        33 * sizeof(vector128));
+               current->thread.used_vr = true;
+       }
        else if (current->thread.used_vr)
                memset(&current->thread.vr_state, 0, 33 * sizeof(vector128));
        /* Always get VRSAVE back */
@@ -391,9 +393,10 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
         * buffer for formatting, then into the taskstruct.
         */
        v_regs += ELF_NVRREG;
-       if ((msr & MSR_VSX) != 0)
+       if ((msr & MSR_VSX) != 0) {
                err |= copy_vsx_from_user(current, v_regs);
-       else
+               current->thread.used_vsr = true;
+       } else
                for (i = 0; i < 32 ; i++)
                        current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;
 #endif
@@ -488,6 +491,7 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
                                        33 * sizeof(vector128));
                err |= __copy_from_user(&current->thread.transact_vr, tm_v_regs,
                                        33 * sizeof(vector128));
+               current->thread.used_vr = true;
        }
        else if (current->thread.used_vr) {
                memset(&current->thread.vr_state, 0, 33 * sizeof(vector128));
@@ -521,6 +525,7 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
                tm_v_regs += ELF_NVRREG;
                err |= copy_vsx_from_user(current, v_regs);
                err |= copy_transact_vsx_from_user(current, tm_v_regs);
+               current->thread.used_vsr = true;
        } else {
                for (i = 0; i < 32 ; i++) {
                        current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0;