Commit 381c02a7 authored by Yang Yingliang's avatar Yang Yingliang
Browse files

arm64: arch_timer: Disable CNTVCT_EL0 trap if workaround is enabled

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8LFBU


CVE: NA

--------------------------------------------------

It costs very much time to read CNTVCT_EL0, if a cntvct workaround
and CNTVCT_EL0 trap is enabled. To decrease the read time, we disable
CNTVCT_EL0 trap, introduce vdso_fix and vdso_shift for doing cntvct
workaround in VDSO.

Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
parent cb2566ed
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -732,4 +732,9 @@ config GOLDFISH_TIMER
	help
	  Support for the timer/counter of goldfish-rtc

config ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
	bool "Enable arch timer workaround in vdso"
	default y
	depends on ARM_ARCH_TIMER_OOL_WORKAROUND

endmenu
+27 −0
Original line number Diff line number Diff line
@@ -92,6 +92,10 @@ static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER;
#else
static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_NONE;
#endif /* CONFIG_GENERIC_GETTIMEOFDAY */
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
static bool vdso_fix;
static u16 vdso_shift;
#endif

static cpumask_t evtstrm_available = CPU_MASK_NONE;
static bool evtstrm_enable __ro_after_init = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM);
@@ -599,8 +603,23 @@ 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) {
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
		if (!strncmp(wa->desc, "HiSilicon erratum 161010101",
			     strlen("HiSilicon erratum 161010101"))) {
			vdso_fix = true;
			vdso_shift = 5;
		} else if (!strncmp(wa->desc, "Freescale erratum a005858",
				    strlen("Freescale erratum a005858"))) {
			vdso_fix = true;
			vdso_shift = 0;
		} else {
			clocksource_counter.vdso_clock_mode = VDSO_CLOCKMODE_NONE;
			vdso_default = VDSO_CLOCKMODE_NONE;
		}
#else
		clocksource_counter.vdso_clock_mode = VDSO_CLOCKMODE_NONE;
		vdso_default = VDSO_CLOCKMODE_NONE;
#endif
	} else if (wa->disable_compat_vdso && vdso_default != VDSO_CLOCKMODE_NONE) {
		vdso_default = VDSO_CLOCKMODE_ARCHTIMER_NOCOMPAT;
		clocksource_counter.vdso_clock_mode = vdso_default;
@@ -973,7 +992,11 @@ static void arch_counter_set_user_access(void)
	 * need to be workaround. The vdso may have been already
	 * disabled though.
	 */
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
	if (arch_timer_this_cpu_has_cntvct_wa() && !vdso_fix)
#else
	if (arch_timer_this_cpu_has_cntvct_wa())
#endif
		pr_info("CPU%d: Trapping CNTVCT access\n", smp_processor_id());
	else
		cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
@@ -1129,6 +1152,10 @@ static void __init arch_counter_register(unsigned type)

		arch_timer_read_counter = rd;
		clocksource_counter.vdso_clock_mode = vdso_default;
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
		clocksource_counter.vdso_fix = vdso_fix;
		clocksource_counter.vdso_shift = vdso_shift;
#endif
	} else {
		arch_timer_read_counter = arch_counter_get_cntvct_mem;
		scr = arch_counter_get_cntvct_mem;
+4 −0
Original line number Diff line number Diff line
@@ -110,6 +110,10 @@ struct clocksource {
	int			rating;
	enum clocksource_ids	id;
	enum vdso_clock_mode	vdso_clock_mode;
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
	u16			vdso_fix;
	u16			vdso_shift;
#endif
	unsigned long		flags;

	int			(*enable)(struct clocksource *cs);
+7 −1
Original line number Diff line number Diff line
@@ -69,7 +69,8 @@ struct vdso_timestamp {
 * @tz_minuteswest:	minutes west of Greenwich
 * @tz_dsttime:		type of DST correction
 * @hrtimer_res:	hrtimer resolution
 * @__unused:		unused
 * @vdso_fix:		avoid the clock bug in VDSO
 * @vdso_shift: 	count of bit to be ignored
 * @arch_data:		architecture specific data (optional, defaults
 *			to an empty struct)
 *
@@ -104,7 +105,12 @@ struct vdso_data {
	s32			tz_minuteswest;
	s32			tz_dsttime;
	u32			hrtimer_res;
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
	u16			vdso_fix;
	u16			vdso_shift;
#else
	u32			__unused;
#endif

	struct arch_vdso_data	arch_data;
};
+16 −0
Original line number Diff line number Diff line
@@ -74,14 +74,30 @@ void update_vsyscall(struct timekeeper *tk)
	struct vdso_data *vdata = __arch_get_k_vdso_data();
	struct vdso_timestamp *vdso_ts;
	s32 clock_mode;
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
	u16 vdso_fix;
	u16 vdso_shift;
#endif
	u64 nsec;

	/* copy vsyscall data */
	vdso_write_begin(vdata);

	clock_mode = tk->tkr_mono.clock->vdso_clock_mode;
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
	vdso_fix = tk->tkr_mono.clock->vdso_fix;
	vdso_shift = tk->tkr_mono.clock->vdso_shift;
#endif
	vdata[CS_HRES_COARSE].clock_mode	= clock_mode;
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
	vdata[CS_HRES_COARSE].vdso_fix 		= vdso_fix;
	vdata[CS_HRES_COARSE].vdso_shift 	= vdso_shift;
#endif
	vdata[CS_RAW].clock_mode		= clock_mode;
#ifdef CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
	vdata[CS_RAW].vdso_fix 			= vdso_fix;
	vdata[CS_RAW].vdso_shift 		= vdso_shift;
#endif

	/* CLOCK_REALTIME also required for time() */
	vdso_ts		= &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME];