|
43 | 43 | #include <linux/stacktrace.h>
|
44 | 44 |
|
45 | 45 | #include <asm/alternative.h>
|
| 46 | +#include <asm/arch_timer.h> |
46 | 47 | #include <asm/compat.h>
|
47 | 48 | #include <asm/cpufeature.h>
|
48 | 49 | #include <asm/cacheflush.h>
|
@@ -484,27 +485,52 @@ static void entry_task_switch(struct task_struct *next)
|
484 | 485 | }
|
485 | 486 |
|
486 | 487 | /*
|
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. |
490 | 492 | */
|
491 |
| -static void erratum_1418040_thread_switch(struct task_struct *next) |
| 493 | +static void update_cntkctl_el1(struct task_struct *next) |
492 | 494 | {
|
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); |
496 | 496 |
|
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))) |
498 | 502 | sysreg_clear_set(cntkctl_el1, ARCH_TIMER_USR_VCT_ACCESS_EN, 0);
|
499 | 503 | else
|
500 | 504 | sysreg_clear_set(cntkctl_el1, 0, ARCH_TIMER_USR_VCT_ACCESS_EN);
|
501 | 505 | }
|
502 | 506 |
|
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) |
504 | 518 | {
|
| 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 | + |
505 | 528 | preempt_disable();
|
506 |
| - erratum_1418040_thread_switch(current); |
| 529 | + update_thread_flag(TIF_TSC_SIGSEGV, tsc_sigsegv); |
| 530 | + update_cntkctl_el1(current); |
507 | 531 | preempt_enable();
|
| 532 | + |
| 533 | + return 0; |
508 | 534 | }
|
509 | 535 |
|
510 | 536 | static void permission_overlay_switch(struct task_struct *next)
|
@@ -551,7 +577,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
551 | 577 | contextidr_thread_switch(next);
|
552 | 578 | entry_task_switch(next);
|
553 | 579 | ssbs_thread_switch(next);
|
554 |
| - erratum_1418040_thread_switch(next); |
| 580 | + cntkctl_thread_switch(prev, next); |
555 | 581 | ptrauth_thread_switch_user(next);
|
556 | 582 | permission_overlay_switch(next);
|
557 | 583 |
|
@@ -669,7 +695,7 @@ void arch_setup_new_exec(void)
|
669 | 695 | current->mm->context.flags = mmflags;
|
670 | 696 | ptrauth_thread_init_user();
|
671 | 697 | mte_thread_init_user();
|
672 |
| - erratum_1418040_new_exec(); |
| 698 | + do_set_tsc_mode(PR_TSC_ENABLE); |
673 | 699 |
|
674 | 700 | if (task_spec_ssb_noexec(current)) {
|
675 | 701 | 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 | 804 | return prot;
|
779 | 805 | }
|
780 | 806 | #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 | +} |
0 commit comments