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 <neeraju@codeaurora.org>
Signed-off-by: Cong Zhang <congzhan@codeaurora.org>
Signed-off-by: Shadab Naseem <snaseem@codeaurora.org>
Signed-off-by: Lijuan Gao <lijuang@codeaurora.org>
This commit is contained in:
Lijuan Gao 2021-03-30 19:25:30 +08:00
commit f01ad8d152
5 changed files with 42 additions and 1 deletions

View file

@ -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);

View file

@ -28,6 +28,7 @@
#include <linux/irq.h>
#include <linux/atomic.h>
#include <asm/arch_timer.h>
#include <asm/cacheflush.h>
#include <asm/exception.h>
#include <asm/unistd.h>
@ -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.

View file

@ -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

View file

@ -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

View file

@ -26,6 +26,7 @@
#include <linux/acpi.h>
#include <asm/arch_timer.h>
#include <asm/traps.h>
#include <asm/virt.h>
#include <clocksource/arm_arch_timer.h>
@ -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;