1
0
Fork 0

arm64: Introduce a way to disable the 32bit vdso

commit 97884ca8c2 upstream.

[this is a redesign rather than a backport]

We have a class of errata (grouped under the ARM64_WORKAROUND_1418040
banner) that force the trapping of counter access from 32bit EL0.

We would normally disable the whole vdso for such defect, except that
it would disable it for 64bit userspace as well, which is a shame.

Instead, add a new vdso_clock_mode, which signals that the vdso
isn't usable for compat tasks.  This gets checked in the new
vdso_clocksource_ok() helper, now provided for the 32bit vdso.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20200706163802.1836732-2-maz@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
5.4-rM2-2.2.x-imx-squashed
Marc Zyngier 2020-07-06 17:37:59 +01:00 committed by Greg Kroah-Hartman
parent 36d60eba86
commit 71d65a3fc6
8 changed files with 41 additions and 14 deletions

View File

@ -1,8 +1,17 @@
#ifndef _ASM_CLOCKSOURCE_H
#define _ASM_CLOCKSOURCE_H
enum vdso_arch_clockmode {
/* vdso clocksource not usable */
VDSO_CLOCKMODE_NONE,
/* vdso clocksource usable */
VDSO_CLOCKMODE_ARCHTIMER,
VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT = VDSO_CLOCKMODE_ARCHTIMER,
};
struct arch_clocksource_data {
bool vdso_direct; /* Usable for direct VDSO access? */
/* Usable for direct VDSO access? */
enum vdso_arch_clockmode clock_mode;
};
#endif

View File

@ -281,7 +281,7 @@ static bool tk_is_cntvct(const struct timekeeper *tk)
if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
return false;
if (!tk->tkr_mono.clock->archdata.vdso_direct)
if (tk->tkr_mono.clock->archdata.clock_mode != VDSO_CLOCKMODE_ARCHTIMER)
return false;
return true;

View File

@ -2,8 +2,11 @@
#ifndef _ASM_CLOCKSOURCE_H
#define _ASM_CLOCKSOURCE_H
#include <asm/vdso/clocksource.h>
struct arch_clocksource_data {
bool vdso_direct; /* Usable for direct VDSO access? */
/* Usable for direct VDSO access? */
enum vdso_arch_clockmode clock_mode;
};
#endif

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_VDSOCLOCKSOURCE_H
#define __ASM_VDSOCLOCKSOURCE_H
enum vdso_arch_clockmode {
/* vdso clocksource not usable */
VDSO_CLOCKMODE_NONE,
/* vdso clocksource for both 32 and 64bit tasks */
VDSO_CLOCKMODE_ARCHTIMER,
/* vdso clocksource for 64bit tasks only */
VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT,
};
#endif

View File

@ -10,6 +10,7 @@
#include <asm/unistd.h>
#include <uapi/linux/time.h>
#include <asm/vdso/clocksource.h>
#include <asm/vdso/compat_barrier.h>
#define __VDSO_USE_SYSCALL ULLONG_MAX
@ -117,10 +118,10 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
u64 res;
/*
* clock_mode == 0 implies that vDSO are enabled otherwise
* clock_mode == ARCHTIMER implies that vDSO are enabled otherwise
* fallback on syscall.
*/
if (clock_mode)
if (clock_mode != VDSO_CLOCKMODE_ARCHTIMER)
return __VDSO_USE_SYSCALL;
/*

View File

@ -10,6 +10,8 @@
#include <asm/unistd.h>
#include <uapi/linux/time.h>
#include <asm/vdso/clocksource.h>
#define __VDSO_USE_SYSCALL ULLONG_MAX
#define VDSO_HAS_CLOCK_GETRES 1
@ -71,10 +73,10 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
u64 res;
/*
* clock_mode == 0 implies that vDSO are enabled otherwise
* clock_mode != NONE implies that vDSO are enabled otherwise
* fallback on syscall.
*/
if (clock_mode)
if (clock_mode == VDSO_CLOCKMODE_NONE)
return __VDSO_USE_SYSCALL;
/*

View File

@ -24,9 +24,7 @@ struct vdso_data *__arm64_get_k_vdso_data(void)
static __always_inline
int __arm64_get_clock_mode(struct timekeeper *tk)
{
u32 use_syscall = !tk->tkr_mono.clock->archdata.vdso_direct;
return use_syscall;
return tk->tkr_mono.clock->archdata.clock_mode;
}
#define __arch_get_clock_mode __arm64_get_clock_mode

View File

@ -69,7 +69,7 @@ static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI;
static bool arch_timer_c3stop;
static bool arch_timer_mem_use_virtual;
static bool arch_counter_suspend_stop;
static bool vdso_default = true;
static enum vdso_arch_clockmode vdso_default = VDSO_CLOCKMODE_ARCHTIMER;
static cpumask_t evtstrm_available = CPU_MASK_NONE;
static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM);
@ -560,8 +560,8 @@ void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa
* change both the default value and the vdso itself.
*/
if (wa->read_cntvct_el0) {
clocksource_counter.archdata.vdso_direct = false;
vdso_default = false;
clocksource_counter.archdata.clock_mode = VDSO_CLOCKMODE_NONE;
vdso_default = VDSO_CLOCKMODE_NONE;
}
}
@ -979,7 +979,7 @@ static void __init arch_counter_register(unsigned type)
}
arch_timer_read_counter = rd;
clocksource_counter.archdata.vdso_direct = vdso_default;
clocksource_counter.archdata.clock_mode = vdso_default;
} else {
arch_timer_read_counter = arch_counter_get_cntvct_mem;
}