arm: traps: emulate a MRC instruction reading CNTFRQ register

Emulate a MRC instruction reading CNTFRQ register.

Change-Id: I054121896d2173fc064aa75b4398178b04a701f7
Signed-off-by: Shadab Naseem <snaseem@codeaurora.org>
This commit is contained in:
Shadab Naseem 2020-01-24 19:31:22 +05:30 • committed by Lijuan Gao
commit 7c3d147b0b
4 changed files with 38 additions and 0 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_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);

View file

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

View file

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

View file

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