Loading arch/arm64/include/asm/processor.h +5 −0 Original line number Diff line number Diff line Loading @@ -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 */ arch/arm64/include/asm/thread_info.h +2 −0 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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 | \ Loading arch/arm64/kernel/process.c +61 −12 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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, Loading Loading @@ -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); } arch/arm64/kernel/traps.c +14 −6 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading
arch/arm64/include/asm/processor.h +5 −0 Original line number Diff line number Diff line Loading @@ -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 */
arch/arm64/include/asm/thread_info.h +2 −0 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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 | \ Loading
arch/arm64/kernel/process.c +61 −12 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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, Loading Loading @@ -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); }
arch/arm64/kernel/traps.c +14 −6 Original line number Diff line number Diff line Loading @@ -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) { Loading