Skip to content

Commit 75078ba

Browse files
committed
Merge branch 'for-next/timers' into for-next/core
* for-next/timers: arm64: Implement prctl(PR_{G,S}ET_TSC)
2 parents 2ef52ca + 3e9e67e commit 75078ba

File tree

4 files changed

+82
-18
lines changed

4 files changed

+82
-18
lines changed

arch/arm64/include/asm/processor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,5 +403,10 @@ long get_tagged_addr_ctrl(struct task_struct *task);
403403
#define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl(current)
404404
#endif
405405

406+
int get_tsc_mode(unsigned long adr);
407+
int set_tsc_mode(unsigned int val);
408+
#define GET_TSC_CTL(adr) get_tsc_mode((adr))
409+
#define SET_TSC_CTL(val) set_tsc_mode((val))
410+
406411
#endif /* __ASSEMBLY__ */
407412
#endif /* __ASM_PROCESSOR_H */

arch/arm64/include/asm/thread_info.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ void arch_setup_new_exec(void);
8181
#define TIF_SME 27 /* SME in use */
8282
#define TIF_SME_VL_INHERIT 28 /* Inherit SME vl_onexec across exec */
8383
#define TIF_KERNEL_FPSTATE 29 /* Task is in a kernel mode FPSIMD section */
84+
#define TIF_TSC_SIGSEGV 30 /* SIGSEGV on counter-timer access */
8485

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

101103
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
102104
_TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \

arch/arm64/kernel/process.c

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <linux/stacktrace.h>
4444

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

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

497-
if (is_compat_thread(task_thread_info(next)))
497+
if (test_ti_thread_flag(ti, TIF_TSC_SIGSEGV) ||
498+
has_erratum_handler(read_cntvct_el0) ||
499+
(IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040) &&
500+
this_cpu_has_cap(ARM64_WORKAROUND_1418040) &&
501+
is_compat_thread(ti)))
498502
sysreg_clear_set(cntkctl_el1, ARCH_TIMER_USR_VCT_ACCESS_EN, 0);
499503
else
500504
sysreg_clear_set(cntkctl_el1, 0, ARCH_TIMER_USR_VCT_ACCESS_EN);
501505
}
502506

503-
static void erratum_1418040_new_exec(void)
507+
static void cntkctl_thread_switch(struct task_struct *prev,
508+
struct task_struct *next)
509+
{
510+
if ((read_ti_thread_flags(task_thread_info(prev)) &
511+
(_TIF_32BIT | _TIF_TSC_SIGSEGV)) !=
512+
(read_ti_thread_flags(task_thread_info(next)) &
513+
(_TIF_32BIT | _TIF_TSC_SIGSEGV)))
514+
update_cntkctl_el1(next);
515+
}
516+
517+
static int do_set_tsc_mode(unsigned int val)
504518
{
519+
bool tsc_sigsegv;
520+
521+
if (val == PR_TSC_SIGSEGV)
522+
tsc_sigsegv = true;
523+
else if (val == PR_TSC_ENABLE)
524+
tsc_sigsegv = false;
525+
else
526+
return -EINVAL;
527+
505528
preempt_disable();
506-
erratum_1418040_thread_switch(current);
529+
update_thread_flag(TIF_TSC_SIGSEGV, tsc_sigsegv);
530+
update_cntkctl_el1(current);
507531
preempt_enable();
532+
533+
return 0;
508534
}
509535

510536
static void permission_overlay_switch(struct task_struct *next)
@@ -551,7 +577,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
551577
contextidr_thread_switch(next);
552578
entry_task_switch(next);
553579
ssbs_thread_switch(next);
554-
erratum_1418040_thread_switch(next);
580+
cntkctl_thread_switch(prev, next);
555581
ptrauth_thread_switch_user(next);
556582
permission_overlay_switch(next);
557583

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

674700
if (task_spec_ssb_noexec(current)) {
675701
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,
778804
return prot;
779805
}
780806
#endif
807+
808+
int get_tsc_mode(unsigned long adr)
809+
{
810+
unsigned int val;
811+
812+
if (is_compat_task())
813+
return -EINVAL;
814+
815+
if (test_thread_flag(TIF_TSC_SIGSEGV))
816+
val = PR_TSC_SIGSEGV;
817+
else
818+
val = PR_TSC_ENABLE;
819+
820+
return put_user(val, (unsigned int __user *)adr);
821+
}
822+
823+
int set_tsc_mode(unsigned int val)
824+
{
825+
if (is_compat_task())
826+
return -EINVAL;
827+
828+
return do_set_tsc_mode(val);
829+
}

arch/arm64/kernel/traps.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -607,18 +607,26 @@ static void ctr_read_handler(unsigned long esr, struct pt_regs *regs)
607607

608608
static void cntvct_read_handler(unsigned long esr, struct pt_regs *regs)
609609
{
610-
int rt = ESR_ELx_SYS64_ISS_RT(esr);
610+
if (test_thread_flag(TIF_TSC_SIGSEGV)) {
611+
force_sig(SIGSEGV);
612+
} else {
613+
int rt = ESR_ELx_SYS64_ISS_RT(esr);
611614

612-
pt_regs_write_reg(regs, rt, arch_timer_read_counter());
613-
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
615+
pt_regs_write_reg(regs, rt, arch_timer_read_counter());
616+
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
617+
}
614618
}
615619

616620
static void cntfrq_read_handler(unsigned long esr, struct pt_regs *regs)
617621
{
618-
int rt = ESR_ELx_SYS64_ISS_RT(esr);
622+
if (test_thread_flag(TIF_TSC_SIGSEGV)) {
623+
force_sig(SIGSEGV);
624+
} else {
625+
int rt = ESR_ELx_SYS64_ISS_RT(esr);
619626

620-
pt_regs_write_reg(regs, rt, arch_timer_get_rate());
621-
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
627+
pt_regs_write_reg(regs, rt, arch_timer_get_rate());
628+
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
629+
}
622630
}
623631

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

0 commit comments

Comments
 (0)