]> git.baikalelectronics.ru Git - kernel.git/commitdiff
arm64: errata: Fix exec handling in erratum 1418040 workaround
authorD Scott Phillips <scott@os.amperecomputing.com>
Mon, 20 Dec 2021 23:41:14 +0000 (15:41 -0800)
committerCatalin Marinas <catalin.marinas@arm.com>
Wed, 22 Dec 2021 15:18:19 +0000 (15:18 +0000)
The erratum 1418040 workaround enables CNTVCT_EL1 access trapping in EL0
when executing compat threads. The workaround is applied when switching
between tasks, but the need for the workaround could also change at an
exec(), when a non-compat task execs a compat binary or vice versa. Apply
the workaround in arch_setup_new_exec().

This leaves a small window of time between SET_PERSONALITY and
arch_setup_new_exec where preemption could occur and confuse the old
workaround logic that compares TIF_32BIT between prev and next. Instead, we
can just read cntkctl to make sure it's in the state that the next task
needs. I measured cntkctl read time to be about the same as a mov from a
general-purpose register on N1. Update the workaround logic to examine the
current value of cntkctl instead of the previous task's compat state.

Fixes: 01abb0f93d15 ("arm64: Move handling of erratum 1418040 into C code")
Cc: <stable@vger.kernel.org> # 5.9.x
Signed-off-by: D Scott Phillips <scott@os.amperecomputing.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20211220234114.3926-1-scott@os.amperecomputing.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/kernel/process.c

index aacf2f5559a8bda4ed609a6170def696f7a20306..271d4bbf468e33d7ed73910665951bcc38b05775 100644 (file)
@@ -439,34 +439,26 @@ static void entry_task_switch(struct task_struct *next)
 
 /*
  * ARM erratum 1418040 handling, affecting the 32bit view of CNTVCT.
- * Assuming the virtual counter is enabled at the beginning of times:
- *
- * - disable access when switching from a 64bit task to a 32bit task
- * - enable access when switching from a 32bit task to a 64bit task
+ * Ensure access is disabled when switching to a 32bit task, ensure
+ * access is enabled when switching to a 64bit task.
  */
-static void erratum_1418040_thread_switch(struct task_struct *prev,
-                                         struct task_struct *next)
+static void erratum_1418040_thread_switch(struct task_struct *next)
 {
-       bool prev32, next32;
-       u64 val;
-
-       if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040))
-               return;
-
-       prev32 = is_compat_thread(task_thread_info(prev));
-       next32 = is_compat_thread(task_thread_info(next));
-
-       if (prev32 == next32 || !this_cpu_has_cap(ARM64_WORKAROUND_1418040))
+       if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040) ||
+           !this_cpu_has_cap(ARM64_WORKAROUND_1418040))
                return;
 
-       val = read_sysreg(cntkctl_el1);
-
-       if (!next32)
-               val |= ARCH_TIMER_USR_VCT_ACCESS_EN;
+       if (is_compat_thread(task_thread_info(next)))
+               sysreg_clear_set(cntkctl_el1, ARCH_TIMER_USR_VCT_ACCESS_EN, 0);
        else
-               val &= ~ARCH_TIMER_USR_VCT_ACCESS_EN;
+               sysreg_clear_set(cntkctl_el1, 0, ARCH_TIMER_USR_VCT_ACCESS_EN);
+}
 
-       write_sysreg(val, cntkctl_el1);
+static void erratum_1418040_new_exec(void)
+{
+       preempt_disable();
+       erratum_1418040_thread_switch(current);
+       preempt_enable();
 }
 
 /*
@@ -501,7 +493,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
        contextidr_thread_switch(next);
        entry_task_switch(next);
        ssbs_thread_switch(next);
-       erratum_1418040_thread_switch(prev, next);
+       erratum_1418040_thread_switch(next);
        ptrauth_thread_switch_user(next);
 
        /*
@@ -611,6 +603,7 @@ void arch_setup_new_exec(void)
        current->mm->context.flags = mmflags;
        ptrauth_thread_init_user();
        mte_thread_init_user();
+       erratum_1418040_new_exec();
 
        if (task_spec_ssb_noexec(current)) {
                arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,