From f01ad8d1526921c826c0a21d6804bcef5daff0cd Mon Sep 17 00:00:00 2001 From: Lijuan Gao Date: Tue, 30 Mar 2021 19:25:30 +0800 Subject: [PATCH 1/2] arm: traps: emulate a MRRC instruction reading CNTVCT register Emulate CNTVCT access, so that userspace can get CNTVCT value, if the direct counter read is disabled. Also, keep direct access disabled by default for userspace. Change-Id: I70263c129386314880cb28d1e561146ce62d52b8 Signed-off-by: Neeraj Upadhyay Signed-off-by: Cong Zhang Signed-off-by: Shadab Naseem Signed-off-by: Lijuan Gao --- arch/arm/include/asm/traps.h | 1 + arch/arm/kernel/traps.c | 37 ++++++++++++++++++++++++++++ arch/arm64/include/asm/traps.h | 1 + drivers/clocksource/Kconfig | 2 +- drivers/clocksource/arm_arch_timer.c | 2 ++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h index 172b08ff3760..3f046a475abe 100644 --- a/arch/arm/include/asm/traps.h +++ b/arch/arm/include/asm/traps.h @@ -28,6 +28,7 @@ static inline int __in_irqentry_text(unsigned long ptr) ptr < (unsigned long)&__irqentry_text_end; } +extern void get_timer_count_hook_init(void); extern void __init early_trap_init(void *); extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame); extern void ptrace_break(struct pt_regs *regs); diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index c053abd1fb53..284affee152b 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -711,6 +712,42 @@ late_initcall(arm_mrc_hook_init); #endif +static int get_timer_count_trap(struct pt_regs *regs, unsigned int instr) +{ + u64 cval; + unsigned int res; + int rd = (instr >> 12) & 0xF; + int rn = (instr >> 16) & 0xF; + + res = arm_check_condition(instr, regs->ARM_cpsr); + if (res == ARM_OPCODE_CONDTEST_FAIL) { + regs->ARM_pc += 4; + return 0; + } + + if (rd == 15 || rn == 15) + return 1; + cval = __arch_counter_get_cntvct(); + regs->uregs[rd] = cval; + regs->uregs[rn] = cval >> 32; + regs->ARM_pc += 4; + return 0; +} + +static struct undef_hook get_timer_count_hook = { + .instr_mask = 0x0ff00fff, + .instr_val = 0x0c500f1e, + .cpsr_mask = MODE_MASK, + .cpsr_val = USR_MODE, + .fn = get_timer_count_trap, +}; + +void get_timer_count_hook_init(void) +{ + register_undef_hook(&get_timer_count_hook); +} +EXPORT_SYMBOL(get_timer_count_hook_init); + /* * A data abort trap was taken, but we did not handle the instruction. * Try to abort the user program, or panic if it was the kernel. diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index 59690613ac31..7e6a0061a389 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -110,4 +110,5 @@ static inline u32 arm64_ras_serror_get_severity(u32 esr) bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr); void __noreturn arm64_serror_panic(struct pt_regs *regs, u32 esr); +static inline void get_timer_count_hook_init(void) {} #endif diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 8546463f8874..e37cd76b6163 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -387,7 +387,7 @@ config SUN50I_ERRATUM_UNKNOWN1 config ARM_ARCH_TIMER_VCT_ACCESS bool "Support for ARM architected timer virtual counter access in userspace" - default !ARM64 + default n depends on ARM_ARCH_TIMER help This option enables support for reading the ARM architected timer's diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 3102c91eeef9..1dd13a6b80c4 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -1519,6 +1520,7 @@ static int __init arch_timer_mem_of_init(struct device_node *np) ret = arch_timer_mem_frame_register(frame); if (!ret && !arch_timer_needs_of_probing()) ret = arch_timer_common_init(); + get_timer_count_hook_init(); out: kfree(timer_mem); return ret; From 7c3d147b0b149a5ad7bb85713a7cd278c0a9882e Mon Sep 17 00:00:00 2001 From: Shadab Naseem Date: Fri, 24 Jan 2020 19:31:22 +0530 Subject: [PATCH 2/2] arm: traps: emulate a MRC instruction reading CNTFRQ register Emulate a MRC instruction reading CNTFRQ register. Change-Id: I054121896d2173fc064aa75b4398178b04a701f7 Signed-off-by: Shadab Naseem --- arch/arm/include/asm/traps.h | 1 + arch/arm/kernel/traps.c | 35 ++++++++++++++++++++++++++++ arch/arm64/include/asm/traps.h | 1 + drivers/clocksource/arm_arch_timer.c | 1 + 4 files changed, 38 insertions(+) diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h index 3f046a475abe..a72802232e17 100644 --- a/arch/arm/include/asm/traps.h +++ b/arch/arm/include/asm/traps.h @@ -28,6 +28,7 @@ static inline int __in_irqentry_text(unsigned long ptr) ptr < (unsigned long)&__irqentry_text_end; } +extern void get_timer_freq_hook_init(void); extern void get_timer_count_hook_init(void); extern void __init early_trap_init(void *); extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame); diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 284affee152b..02131086e0ae 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -748,6 +748,41 @@ void get_timer_count_hook_init(void) } EXPORT_SYMBOL(get_timer_count_hook_init); +static int get_freq_trap(struct pt_regs *regs, unsigned int instr) +{ + u32 fval; + unsigned int res; + int rd = (instr >> 12) & 0xF; + + res = arm_check_condition(instr, regs->ARM_cpsr); + if (res == ARM_OPCODE_CONDTEST_FAIL) { + regs->ARM_pc += 4; + return 0; + } + + if (rd == 15) + return 1; + + fval = arch_timer_get_cntfrq(); + regs->uregs[rd] = fval; + regs->ARM_pc += 4; + return 0; +} + +static struct undef_hook get_freq_hook = { + .instr_mask = 0x0fff0fff, + .instr_val = 0x0e1e0f10, + .cpsr_mask = MODE_MASK, + .cpsr_val = USR_MODE, + .fn = get_freq_trap, +}; + +void get_timer_freq_hook_init(void) +{ + register_undef_hook(&get_freq_hook); +} +EXPORT_SYMBOL(get_timer_freq_hook_init); + /* * A data abort trap was taken, but we did not handle the instruction. * Try to abort the user program, or panic if it was the kernel. diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index 7e6a0061a389..1bae296f8e28 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -111,4 +111,5 @@ static inline u32 arm64_ras_serror_get_severity(u32 esr) bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr); void __noreturn arm64_serror_panic(struct pt_regs *regs, u32 esr); static inline void get_timer_count_hook_init(void) {} +static inline void get_timer_freq_hook_init(void) {} #endif diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 1dd13a6b80c4..b65abd6590e1 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1521,6 +1521,7 @@ static int __init arch_timer_mem_of_init(struct device_node *np) if (!ret && !arch_timer_needs_of_probing()) ret = arch_timer_common_init(); get_timer_count_hook_init(); + get_timer_freq_hook_init(); out: kfree(timer_mem); return ret;