arm: traps: emulate a MRCC instruction reading CNTPCT register

A user space application is planned to support feature for
synchronized timestamp among debug packets across peripherals.
As part of the feature, it is responsible for providing physical
timer count value to user space. If memory mapped timer is used
in ARM arch, Usersapce can't read the physical timer count directly
with a MRCC ASM instruction. So Kernel traps the instruction and
returns the physical timer count.

Change-Id: Ia3f0d9c8c06ca9e2204187890c0c57c8640e4f7e
Signed-off-by: Se Wang (Patrick) Oh <sewango@codeaurora.org>
This commit is contained in:
Se Wang (Patrick) Oh 2015-05-28 12:37:22 -07:00 committed by Gerrit - the friendly Code Review server
parent 186318ca45
commit f892e83902
4 changed files with 41 additions and 0 deletions

View File

@ -46,6 +46,7 @@ static inline int in_exception_text(unsigned long ptr)
return in ? : __in_irqentry_text(ptr);
}
extern void get_pct_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 task_struct *tsk, struct pt_regs *regs);

View File

@ -28,6 +28,7 @@
#include <linux/bug.h>
#include <linux/atomic.h>
#include <asm/arch_timer.h>
#include <asm/cacheflush.h>
#include <asm/exception.h>
#include <asm/unistd.h>
@ -733,6 +734,42 @@ late_initcall(arm_mrc_hook_init);
#endif
static int get_pct_trap(struct pt_regs *regs, unsigned int instr)
{
u64 cntpct;
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;
cntpct = arch_counter_get_cntpct();
regs->uregs[rd] = cntpct;
regs->uregs[rn] = cntpct >> 32;
regs->ARM_pc += 4;
return 0;
}
static struct undef_hook get_pct_hook = {
.instr_mask = 0x0ff00fff,
.instr_val = 0x0c500f0e,
.cpsr_mask = MODE_MASK,
.cpsr_val = USR_MODE,
.fn = get_pct_trap,
};
void get_pct_hook_init(void)
{
register_undef_hook(&get_pct_hook);
}
EXPORT_SYMBOL(get_pct_hook_init);
void __bad_xchg(volatile void *ptr, int size)
{
printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",

View File

@ -40,4 +40,5 @@ static inline int in_exception_text(unsigned long ptr)
ptr < (unsigned long)&__exception_text_end;
}
static inline void get_pct_hook_init(void) {}
#endif

View File

@ -23,6 +23,7 @@
#include <linux/sched_clock.h>
#include <asm/arch_timer.h>
#include <asm/traps.h>
#include <asm/virt.h>
#include <clocksource/arm_arch_timer.h>
@ -790,6 +791,7 @@ static void __init arch_timer_mem_init(struct device_node *np)
arch_timer_detect_rate(base, np);
arch_timer_mem_register(base, irq);
arch_timer_common_init();
get_pct_hook_init();
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_init);