summaryrefslogtreecommitdiff
path: root/arch/arm/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/traps.c')
-rw-r--r--arch/arm/kernel/traps.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index bc698383e822..cdefc69c656b 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -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>
@@ -697,6 +698,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);
+
/*
* 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.