]> git.hungrycats.org Git - linux/commitdiff
MIPS: init upper 64b of vector registers when MSA is first used
authorPaul Burton <paul.burton@imgtec.com>
Wed, 30 Jul 2014 07:53:20 +0000 (08:53 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Tue, 4 Apr 2017 21:21:53 +0000 (22:21 +0100)
commit c9017757c532d48bf43d6e7d3b7282443ad4207b upstream.

When a task first makes use of MSA we need to ensure that the upper
64b of the vector registers are set to some value such that no
information can be leaked to it from the previous task to use MSA
context on the CPU. The architecture formerly specified that these
bits would be cleared to 0 when a scalar FP instructions wrote to the
aliased FP registers, which would have implicitly handled this as the
kernel restored scalar FP context. However more recent versions of the
specification now state that the value of the bits in such cases is
unpredictable. Initialise them explictly to be sure, and set all the
bits to 1 rather than 0 for consistency with the least significant
64b.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/7497/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Cc: Arnd Bergmann <arnd@arndb.de>
arch/mips/include/asm/asmmacro.h
arch/mips/include/asm/msa.h
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/traps.c

index eca94c2b114b5a01aa206d1877fd12c5e10975dd..8a83c06e1d17836defb20625d07a4c19ebfdd1ba 100644 (file)
        ld_d    31, THREAD_FPR31, \thread
        .endm
 
+       .macro  msa_init_upper wd
+#ifdef CONFIG_64BIT
+       insert_d \wd, 1
+#else
+       insert_w \wd, 2
+       insert_w \wd, 3
+#endif
+       .if     31-\wd
+       msa_init_upper  (\wd+1)
+       .endif
+       .endm
+
+       .macro  msa_init_all_upper
+       .set    push
+       .set    noat
+       not     $1, zero
+       msa_init_upper  0
+       .set    pop
+       .endm
+
 #endif /* _ASM_ASMMACRO_H */
index ab3fea101a7f945fdbdb42cfcddadf8f58c763b7..af5638b12c756794b72df9adaeee27a828e1ddc7 100644 (file)
@@ -16,6 +16,7 @@
 
 extern void _save_msa(struct task_struct *);
 extern void _restore_msa(struct task_struct *);
+extern void _init_msa_upper(void);
 
 static inline void enable_msa(void)
 {
index 1a1aef04312d370e9c9601365b3428a78ac53c17..4c4ec1812420b873663d682d706860f394d7db00 100644 (file)
@@ -144,6 +144,11 @@ LEAF(_restore_msa)
        jr      ra
        END(_restore_msa)
 
+LEAF(_init_msa_upper)
+       msa_init_all_upper
+       jr      ra
+       END(_init_msa_upper)
+
 #endif
 
 /*
index e0d9757a845935f3558c4614b87a3de951e42e84..e998f69a095c5258713031bc6d8586da048c349d 100644 (file)
@@ -1094,13 +1094,15 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
 
 static int enable_restore_fp_context(int msa)
 {
-       int err, was_fpu_owner;
+       int err, was_fpu_owner, prior_msa;
 
        if (!used_math()) {
                /* First time FP context user. */
                err = init_fpu();
-               if (msa && !err)
+               if (msa && !err) {
                        enable_msa();
+                       _init_msa_upper();
+               }
                if (!err)
                        set_used_math();
                return err;
@@ -1152,18 +1154,37 @@ static int enable_restore_fp_context(int msa)
        /*
         * If this is the first time that the task is using MSA and it has
         * previously used scalar FP in this time slice then we already nave
-        * FP context which we shouldn't clobber.
+        * FP context which we shouldn't clobber. We do however need to clear
+        * the upper 64b of each vector register so that this task has no
+        * opportunity to see data left behind by another.
         */
-       if (!test_and_set_thread_flag(TIF_MSA_CTX_LIVE) && was_fpu_owner)
+       prior_msa = test_and_set_thread_flag(TIF_MSA_CTX_LIVE);
+       if (!prior_msa && was_fpu_owner) {
+               _init_msa_upper();
                return 0;
+       }
 
-       /* We need to restore the vector context. */
-       restore_msa(current);
+       if (!prior_msa) {
+               /*
+                * Restore the least significant 64b of each vector register
+                * from the existing scalar FP context.
+                */
+               _restore_fp(current);
 
-       /* Restore the scalar FP control & status register */
-       if (!was_fpu_owner)
-               asm volatile("ctc1 %0, $31" : : "r"(current->thread.fpu.fcr31));
+               /*
+                * The task has not formerly used MSA, so clear the upper 64b
+                * of each vector register such that it cannot see data left
+                * behind by another task.
+                */
+               _init_msa_upper();
+       } else {
+               /* We need to restore the vector context. */
+               restore_msa(current);
 
+               /* Restore the scalar FP control & status register */
+               if (!was_fpu_owner)
+                       asm volatile("ctc1 %0, $31" : : "r"(current->thread.fpu.fcr31));
+       }
        return 0;
 }