Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/pmladek...
[linux-2.6-block.git] / arch / arm64 / kernel / process.c
index 37c9470cbdaa5b6e2aa1571d98881da41b3e630d..ad8aeb098b31ed5887aa98a438622bb2304abe97 100644 (file)
@@ -313,6 +313,15 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
        clear_tsk_thread_flag(p, TIF_SVE);
        p->thread.sve_state = NULL;
 
+       /*
+        * In case p was allocated the same task_struct pointer as some
+        * other recently-exited task, make sure p is disassociated from
+        * any cpu that may have run that now-exited task recently.
+        * Otherwise we could erroneously skip reloading the FPSIMD
+        * registers for p.
+        */
+       fpsimd_flush_task_state(p);
+
        if (likely(!(p->flags & PF_KTHREAD))) {
                *childregs = *current_pt_regs();
                childregs->regs[0] = 0;
@@ -360,16 +369,14 @@ void tls_preserve_current_state(void)
 
 static void tls_thread_switch(struct task_struct *next)
 {
-       unsigned long tpidr, tpidrro;
-
        tls_preserve_current_state();
 
-       tpidr = *task_user_tls(next);
-       tpidrro = is_compat_thread(task_thread_info(next)) ?
-                 next->thread.tp_value : 0;
+       if (is_compat_thread(task_thread_info(next)))
+               write_sysreg(next->thread.tp_value, tpidrro_el0);
+       else if (!arm64_kernel_unmapped_at_el0())
+               write_sysreg(0, tpidrro_el0);
 
-       write_sysreg(tpidr, tpidr_el0);
-       write_sysreg(tpidrro, tpidrro_el0);
+       write_sysreg(*task_user_tls(next), tpidr_el0);
 }
 
 /* Restore the UAO state depending on next's addr_limit */