Commit 75078ba2 authored by Will Deacon's avatar Will Deacon
Browse files

Merge branch 'for-next/timers' into for-next/core

* for-next/timers:
  arm64: Implement prctl(PR_{G,S}ET_TSC)
parents 2ef52ca0 3e9e67e1
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -403,5 +403,10 @@ long get_tagged_addr_ctrl(struct task_struct *task);
#define GET_TAGGED_ADDR_CTRL()		get_tagged_addr_ctrl(current)
#endif

int get_tsc_mode(unsigned long adr);
int set_tsc_mode(unsigned int val);
#define GET_TSC_CTL(adr)        get_tsc_mode((adr))
#define SET_TSC_CTL(val)        set_tsc_mode((val))

#endif /* __ASSEMBLY__ */
#endif /* __ASM_PROCESSOR_H */
+2 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ void arch_setup_new_exec(void);
#define TIF_SME			27	/* SME in use */
#define TIF_SME_VL_INHERIT	28	/* Inherit SME vl_onexec across exec */
#define TIF_KERNEL_FPSTATE	29	/* Task is in a kernel mode FPSIMD section */
#define TIF_TSC_SIGSEGV		30	/* SIGSEGV on counter-timer access */

#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
@@ -97,6 +98,7 @@ void arch_setup_new_exec(void);
#define _TIF_SVE		(1 << TIF_SVE)
#define _TIF_MTE_ASYNC_FAULT	(1 << TIF_MTE_ASYNC_FAULT)
#define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
#define _TIF_TSC_SIGSEGV	(1 << TIF_TSC_SIGSEGV)

#define _TIF_WORK_MASK		(_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
				 _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
+61 −12
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include <linux/stacktrace.h>

#include <asm/alternative.h>
#include <asm/arch_timer.h>
#include <asm/compat.h>
#include <asm/cpufeature.h>
#include <asm/cacheflush.h>
@@ -484,27 +485,52 @@ static void entry_task_switch(struct task_struct *next)
}

/*
 * ARM erratum 1418040 handling, affecting the 32bit view of CNTVCT.
 * Ensure access is disabled when switching to a 32bit task, ensure
 * access is enabled when switching to a 64bit task.
 * Handle sysreg updates for ARM erratum 1418040 which affects the 32bit view of
 * CNTVCT, various other errata which require trapping all CNTVCT{,_EL0}
 * accesses and prctl(PR_SET_TSC). Ensure access is disabled iff a workaround is
 * required or PR_TSC_SIGSEGV is set.
 */
static void erratum_1418040_thread_switch(struct task_struct *next)
static void update_cntkctl_el1(struct task_struct *next)
{
	if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040) ||
	    !this_cpu_has_cap(ARM64_WORKAROUND_1418040))
		return;
	struct thread_info *ti = task_thread_info(next);

	if (is_compat_thread(task_thread_info(next)))
	if (test_ti_thread_flag(ti, TIF_TSC_SIGSEGV) ||
	    has_erratum_handler(read_cntvct_el0) ||
	    (IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040) &&
	     this_cpu_has_cap(ARM64_WORKAROUND_1418040) &&
	     is_compat_thread(ti)))
		sysreg_clear_set(cntkctl_el1, ARCH_TIMER_USR_VCT_ACCESS_EN, 0);
	else
		sysreg_clear_set(cntkctl_el1, 0, ARCH_TIMER_USR_VCT_ACCESS_EN);
}

static void erratum_1418040_new_exec(void)
static void cntkctl_thread_switch(struct task_struct *prev,
				  struct task_struct *next)
{
	if ((read_ti_thread_flags(task_thread_info(prev)) &
	     (_TIF_32BIT | _TIF_TSC_SIGSEGV)) !=
	    (read_ti_thread_flags(task_thread_info(next)) &
	     (_TIF_32BIT | _TIF_TSC_SIGSEGV)))
		update_cntkctl_el1(next);
}

static int do_set_tsc_mode(unsigned int val)
{
	bool tsc_sigsegv;

	if (val == PR_TSC_SIGSEGV)
		tsc_sigsegv = true;
	else if (val == PR_TSC_ENABLE)
		tsc_sigsegv = false;
	else
		return -EINVAL;

	preempt_disable();
	erratum_1418040_thread_switch(current);
	update_thread_flag(TIF_TSC_SIGSEGV, tsc_sigsegv);
	update_cntkctl_el1(current);
	preempt_enable();

	return 0;
}

static void permission_overlay_switch(struct task_struct *next)
@@ -551,7 +577,7 @@ 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(next);
	cntkctl_thread_switch(prev, next);
	ptrauth_thread_switch_user(next);
	permission_overlay_switch(next);

@@ -669,7 +695,7 @@ void arch_setup_new_exec(void)
	current->mm->context.flags = mmflags;
	ptrauth_thread_init_user();
	mte_thread_init_user();
	erratum_1418040_new_exec();
	do_set_tsc_mode(PR_TSC_ENABLE);

	if (task_spec_ssb_noexec(current)) {
		arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,
@@ -778,3 +804,26 @@ int arch_elf_adjust_prot(int prot, const struct arch_elf_state *state,
	return prot;
}
#endif

int get_tsc_mode(unsigned long adr)
{
	unsigned int val;

	if (is_compat_task())
		return -EINVAL;

	if (test_thread_flag(TIF_TSC_SIGSEGV))
		val = PR_TSC_SIGSEGV;
	else
		val = PR_TSC_ENABLE;

	return put_user(val, (unsigned int __user *)adr);
}

int set_tsc_mode(unsigned int val)
{
	if (is_compat_task())
		return -EINVAL;

	return do_set_tsc_mode(val);
}
+14 −6
Original line number Diff line number Diff line
@@ -607,19 +607,27 @@ static void ctr_read_handler(unsigned long esr, struct pt_regs *regs)

static void cntvct_read_handler(unsigned long esr, struct pt_regs *regs)
{
	if (test_thread_flag(TIF_TSC_SIGSEGV)) {
		force_sig(SIGSEGV);
	} else {
		int rt = ESR_ELx_SYS64_ISS_RT(esr);

		pt_regs_write_reg(regs, rt, arch_timer_read_counter());
		arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
	}
}

static void cntfrq_read_handler(unsigned long esr, struct pt_regs *regs)
{
	if (test_thread_flag(TIF_TSC_SIGSEGV)) {
		force_sig(SIGSEGV);
	} else {
		int rt = ESR_ELx_SYS64_ISS_RT(esr);

		pt_regs_write_reg(regs, rt, arch_timer_get_rate());
		arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
	}
}

static void mrs_handler(unsigned long esr, struct pt_regs *regs)
{