arm64: errata: Fix exec handling in erratum 1418040
workaround
The erratum1418040
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:d49f7d7376
("arm64: Move handling of erratum1418040
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>
This commit is contained in:
Родитель
31e833b203
Коммит
38e0257e0e
|
@ -439,34 +439,26 @@ static void entry_task_switch(struct task_struct *next)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ARM erratum 1418040 handling, affecting the 32bit view of CNTVCT.
|
* ARM erratum 1418040 handling, affecting the 32bit view of CNTVCT.
|
||||||
* Assuming the virtual counter is enabled at the beginning of times:
|
* Ensure access is disabled when switching to a 32bit task, ensure
|
||||||
*
|
* access is enabled when switching to a 64bit task.
|
||||||
* - disable access when switching from a 64bit task to a 32bit task
|
|
||||||
* - enable access when switching from a 32bit task to a 64bit task
|
|
||||||
*/
|
*/
|
||||||
static void erratum_1418040_thread_switch(struct task_struct *prev,
|
static void erratum_1418040_thread_switch(struct task_struct *next)
|
||||||
struct task_struct *next)
|
|
||||||
{
|
{
|
||||||
bool prev32, next32;
|
if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040) ||
|
||||||
u64 val;
|
!this_cpu_has_cap(ARM64_WORKAROUND_1418040))
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
prev32 = is_compat_thread(task_thread_info(prev));
|
if (is_compat_thread(task_thread_info(next)))
|
||||||
next32 = is_compat_thread(task_thread_info(next));
|
sysreg_clear_set(cntkctl_el1, ARCH_TIMER_USR_VCT_ACCESS_EN, 0);
|
||||||
|
|
||||||
if (prev32 == next32 || !this_cpu_has_cap(ARM64_WORKAROUND_1418040))
|
|
||||||
return;
|
|
||||||
|
|
||||||
val = read_sysreg(cntkctl_el1);
|
|
||||||
|
|
||||||
if (!next32)
|
|
||||||
val |= ARCH_TIMER_USR_VCT_ACCESS_EN;
|
|
||||||
else
|
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);
|
contextidr_thread_switch(next);
|
||||||
entry_task_switch(next);
|
entry_task_switch(next);
|
||||||
ssbs_thread_switch(next);
|
ssbs_thread_switch(next);
|
||||||
erratum_1418040_thread_switch(prev, next);
|
erratum_1418040_thread_switch(next);
|
||||||
ptrauth_thread_switch_user(next);
|
ptrauth_thread_switch_user(next);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -611,6 +603,7 @@ void arch_setup_new_exec(void)
|
||||||
current->mm->context.flags = mmflags;
|
current->mm->context.flags = mmflags;
|
||||||
ptrauth_thread_init_user();
|
ptrauth_thread_init_user();
|
||||||
mte_thread_init_user();
|
mte_thread_init_user();
|
||||||
|
erratum_1418040_new_exec();
|
||||||
|
|
||||||
if (task_spec_ssb_noexec(current)) {
|
if (task_spec_ssb_noexec(current)) {
|
||||||
arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,
|
arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче