When a task first makes use of MSA we need to ensure that the upper 64b of the vector registers are cleared, so that no information can be leaked to it from the previous task to use MSA context on the CPU. The architecture specification formerly specified that these bits would be cleared to 0 when a scalar FP instructions wrote to the aliased FP registers but more recent versions of the specification now state that the bits are unpredictable. Clear then explicitly to be sure. Signed-off-by: Paul Burton <paul.burton@xxxxxxxxxx> --- arch/mips/include/asm/asmmacro.h | 20 ++++++++++++++++++++ arch/mips/include/asm/msa.h | 1 + arch/mips/kernel/r4k_switch.S | 5 +++++ arch/mips/kernel/traps.c | 12 +++++++++--- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 4986bf5..2d601e7 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -426,4 +426,24 @@ ld_d 31, THREAD_FPR31, \thread .endm + .macro msa_clear_upper wd +#ifdef CONFIG_64BIT + insert_d \wd, 1 +#else + insert_w \wd, 2 + insert_w \wd, 3 +#endif + .if 31-\wd + msa_clear_upper (\wd+1) + .endif + .endm + + .macro msa_clear_all_upper + .set push + .set noat + move $1, zero + msa_clear_upper 0 + .set pop + .endm + #endif /* _ASM_ASMMACRO_H */ diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h index e80e85c..f32aa06 100644 --- a/arch/mips/include/asm/msa.h +++ b/arch/mips/include/asm/msa.h @@ -16,6 +16,7 @@ extern void _save_msa(struct task_struct *); extern void _restore_msa(struct task_struct *); +extern void _clear_msa_upper(void); static inline void enable_msa(void) { diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 1a1aef0..e459c04 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -144,6 +144,11 @@ LEAF(_restore_msa) jr ra END(_restore_msa) +LEAF(_clear_msa_upper) + msa_clear_all_upper + jr ra + END(_clear_msa_upper) + #endif /* diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 4792fd7..9359907 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1093,8 +1093,10 @@ static int enable_restore_fp_context(int msa) if (!used_math()) { /* First time FP context user. */ err = init_fpu(); - if (msa && !err) + if (msa && !err) { enable_msa(); + _clear_msa_upper(); + } if (!err) set_used_math(); return err; @@ -1146,10 +1148,14 @@ 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) + if (!test_and_set_thread_flag(TIF_MSA_CTX_LIVE) && was_fpu_owner) { + _clear_msa_upper(); return 0; + } /* We need to restore the vector context. */ restore_msa(current); -- 2.0.1