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

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

* for-next/timers:
  arm64: Implement prctl(PR_{G,S}ET_TSC)
parents 2ef52ca0 3e9e67e1
...@@ -403,5 +403,10 @@ long get_tagged_addr_ctrl(struct task_struct *task); ...@@ -403,5 +403,10 @@ long get_tagged_addr_ctrl(struct task_struct *task);
#define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl(current) #define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl(current)
#endif #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 /* __ASSEMBLY__ */
#endif /* __ASM_PROCESSOR_H */ #endif /* __ASM_PROCESSOR_H */
...@@ -81,6 +81,7 @@ void arch_setup_new_exec(void); ...@@ -81,6 +81,7 @@ void arch_setup_new_exec(void);
#define TIF_SME 27 /* SME in use */ #define TIF_SME 27 /* SME in use */
#define TIF_SME_VL_INHERIT 28 /* Inherit SME vl_onexec across exec */ #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_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_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
...@@ -97,6 +98,7 @@ void arch_setup_new_exec(void); ...@@ -97,6 +98,7 @@ void arch_setup_new_exec(void);
#define _TIF_SVE (1 << TIF_SVE) #define _TIF_SVE (1 << TIF_SVE)
#define _TIF_MTE_ASYNC_FAULT (1 << TIF_MTE_ASYNC_FAULT) #define _TIF_MTE_ASYNC_FAULT (1 << TIF_MTE_ASYNC_FAULT)
#define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) #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 | \ #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
#include <asm/alternative.h> #include <asm/alternative.h>
#include <asm/arch_timer.h>
#include <asm/compat.h> #include <asm/compat.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
...@@ -484,27 +485,52 @@ static void entry_task_switch(struct task_struct *next) ...@@ -484,27 +485,52 @@ static void entry_task_switch(struct task_struct *next)
} }
/* /*
* ARM erratum 1418040 handling, affecting the 32bit view of CNTVCT. * Handle sysreg updates for ARM erratum 1418040 which affects the 32bit view of
* Ensure access is disabled when switching to a 32bit task, ensure * CNTVCT, various other errata which require trapping all CNTVCT{,_EL0}
* access is enabled when switching to a 64bit task. * 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) || struct thread_info *ti = task_thread_info(next);
!this_cpu_has_cap(ARM64_WORKAROUND_1418040))
return;
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); sysreg_clear_set(cntkctl_el1, ARCH_TIMER_USR_VCT_ACCESS_EN, 0);
else else
sysreg_clear_set(cntkctl_el1, 0, ARCH_TIMER_USR_VCT_ACCESS_EN); 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(); preempt_disable();
erratum_1418040_thread_switch(current); update_thread_flag(TIF_TSC_SIGSEGV, tsc_sigsegv);
update_cntkctl_el1(current);
preempt_enable(); preempt_enable();
return 0;
} }
static void permission_overlay_switch(struct task_struct *next) static void permission_overlay_switch(struct task_struct *next)
...@@ -551,7 +577,7 @@ struct task_struct *__switch_to(struct task_struct *prev, ...@@ -551,7 +577,7 @@ 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(next); cntkctl_thread_switch(prev, next);
ptrauth_thread_switch_user(next); ptrauth_thread_switch_user(next);
permission_overlay_switch(next); permission_overlay_switch(next);
...@@ -669,7 +695,7 @@ void arch_setup_new_exec(void) ...@@ -669,7 +695,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(); do_set_tsc_mode(PR_TSC_ENABLE);
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,
...@@ -778,3 +804,26 @@ int arch_elf_adjust_prot(int prot, const struct arch_elf_state *state, ...@@ -778,3 +804,26 @@ int arch_elf_adjust_prot(int prot, const struct arch_elf_state *state,
return prot; return prot;
} }
#endif #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);
}
...@@ -607,18 +607,26 @@ static void ctr_read_handler(unsigned long esr, struct pt_regs *regs) ...@@ -607,18 +607,26 @@ static void ctr_read_handler(unsigned long esr, struct pt_regs *regs)
static void cntvct_read_handler(unsigned long esr, struct pt_regs *regs) static void cntvct_read_handler(unsigned long esr, struct pt_regs *regs)
{ {
int rt = ESR_ELx_SYS64_ISS_RT(esr); 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()); pt_regs_write_reg(regs, rt, arch_timer_read_counter());
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
}
} }
static void cntfrq_read_handler(unsigned long esr, struct pt_regs *regs) static void cntfrq_read_handler(unsigned long esr, struct pt_regs *regs)
{ {
int rt = ESR_ELx_SYS64_ISS_RT(esr); 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()); pt_regs_write_reg(regs, rt, arch_timer_get_rate());
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
}
} }
static void mrs_handler(unsigned long esr, struct pt_regs *regs) static void mrs_handler(unsigned long esr, struct pt_regs *regs)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment