]> Git Repo - linux.git/commitdiff
Merge branch 'for-next/timers' into for-next/core
authorWill Deacon <[email protected]>
Thu, 12 Sep 2024 12:44:03 +0000 (13:44 +0100)
committerWill Deacon <[email protected]>
Thu, 12 Sep 2024 12:44:03 +0000 (13:44 +0100)
* for-next/timers:
  arm64: Implement prctl(PR_{G,S}ET_TSC)

1  2 
arch/arm64/include/asm/processor.h
arch/arm64/kernel/process.c
arch/arm64/kernel/traps.c

index e6376f97927321dff3a16c3af1fbfc9c9039444a,347bd3464fcbef3a5fa5a16cbe815649b2fc8715..1438424f00643708c26b0439fd697b6d97fc3ff9
@@@ -184,7 -184,6 +184,7 @@@ struct thread_struct 
        u64                     sctlr_user;
        u64                     svcr;
        u64                     tpidr2_el0;
 +      u64                     por_el0;
  };
  
  static inline unsigned int thread_get_vl(struct thread_struct *thread,
@@@ -403,5 -402,10 +403,10 @@@ long get_tagged_addr_ctrl(struct task_s
  #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 */
index f365b033a64958f8dab67b2f9b4aabe158f9c7cd,1b6bbf839bb5ed74f0fd79169c5604bcd727bca6..0540653fbf382bf8a0984a7e9f97cafbedc3251b
@@@ -43,6 -43,7 +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>
@@@ -271,21 -272,12 +272,21 @@@ static void flush_tagged_addr_state(voi
                clear_thread_flag(TIF_TAGGED_ADDR);
  }
  
 +static void flush_poe(void)
 +{
 +      if (!system_supports_poe())
 +              return;
 +
 +      write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0);
 +}
 +
  void flush_thread(void)
  {
        fpsimd_flush_thread();
        tls_thread_flush();
        flush_ptrace_hw_breakpoint(current);
        flush_tagged_addr_state();
 +      flush_poe();
  }
  
  void arch_release_task_struct(struct task_struct *tsk)
@@@ -380,9 -372,6 +381,9 @@@ int copy_thread(struct task_struct *p, 
                if (system_supports_tpidr2())
                        p->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
  
 +              if (system_supports_poe())
 +                      p->thread.por_el0 = read_sysreg_s(SYS_POR_EL0);
 +
                if (stack_start) {
                        if (is_compat_thread(task_thread_info(p)))
                                childregs->compat_sp = stack_start;
@@@ -484,40 -473,54 +485,65 @@@ static void entry_task_switch(struct ta
  }
  
  /*
-  * 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)
 +{
 +      if (!system_supports_poe())
 +              return;
 +
 +      current->thread.por_el0 = read_sysreg_s(SYS_POR_EL0);
 +      if (current->thread.por_el0 != next->thread.por_el0) {
 +              write_sysreg_s(next->thread.por_el0, SYS_POR_EL0);
 +      }
 +}
 +
  /*
   * __switch_to() checks current->thread.sctlr_user as an optimisation. Therefore
   * this function must be called with preemption disabled and the update to
@@@ -551,9 -554,8 +577,9 @@@ struct task_struct *__switch_to(struct 
        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);
  
        /*
         * Complete any pending TLB or cache maintenance on this CPU in case
@@@ -669,7 -671,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 -780,26 +804,26 @@@ int arch_elf_adjust_prot(int prot, cons
        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);
+ }
index 9a11bb0db284450101d25c0b3c3fd520d92f7106,baf02ac437f83c02ffea581adbace2b585553ea5..563cbce11126960a810d22b1cac024787f283a4e
@@@ -273,12 -273,6 +273,12 @@@ void arm64_force_sig_fault(int signo, i
                force_sig_fault(signo, code, (void __user *)far);
  }
  
 +void arm64_force_sig_fault_pkey(unsigned long far, const char *str, int pkey)
 +{
 +      arm64_show_signal(SIGSEGV, str);
 +      force_sig_pkuerr((void __user *)far, pkey);
 +}
 +
  void arm64_force_sig_mceerr(int code, unsigned long far, short lsb,
                            const char *str)
  {
@@@ -607,18 -601,26 +607,26 @@@ static void ctr_read_handler(unsigned l
  
  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());
-       arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
+               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)
  {
-       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());
-       arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
+               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)
This page took 0.0712 seconds and 4 git commands to generate.