From 65a0707548cce5b054cc8c94bfaa1b0cc9776505 Mon Sep 17 00:00:00 2001 From: Neeraj Upadhyay Date: Tue, 10 Apr 2018 16:33:47 +0530 Subject: [PATCH] arm64: Add CNTVCT_EL0 cp15 AArch32 trap handler Cntvct access was disabled by default, in 'commit 7b4edf240be4 ("clocksource: arch_timer: make virtual counter access configurable"). There is a trap handler added for user access using mrs instruction in 'commit 9ce281d317a1 ("arm64: Add CNTVCT_EL0 trap handler")' However, el0 running in AArch32 can try to access cntvct using mrrc instruction. So, add a trap handler to support that. Change-Id: I788c03d87cd5a2d0e8d02da6662e2a1fb5e92827 Signed-off-by: Neeraj Upadhyay --- arch/arm64/include/asm/esr.h | 36 +++++++++++++++++++++ arch/arm64/kernel/entry.S | 13 +++++++- arch/arm64/kernel/traps.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index c68d0adfd41e..e52727cc9ce3 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -224,6 +224,42 @@ (ESR_ELx_CP15_32_ISS_SYS_VAL(0, 0, 14, 0) | \ ESR_ELx_CP15_32_ISS_DIR_READ) +/* ISS field definitions for CP15 AArch32 64-bit access traps */ +#define ESR_ELx_CP15_64_ISS_CV_SHIFT 24 +#define ESR_ELx_CP15_64_ISS_CV_MASK \ + (UL(0x1) << ESR_ELx_CP15_64_ISS_CV_SHIFT) +#define ESR_ELx_CP15_64_ISS_DIR_MASK 0x1 +#define ESR_ELx_CP15_64_ISS_DIR_READ 0x1 +#define ESR_ELx_CP15_64_ISS_DIR_WRITE 0x0 + +#define ESR_ELx_CP15_64_ISS_RT_SHIFT 5 +#define ESR_ELx_CP15_64_ISS_RT_MASK \ + (UL(0x1f) << ESR_ELx_CP15_64_ISS_RT_SHIFT) +#define ESR_ELx_CP15_64_ISS_CRM_SHIFT 1 +#define ESR_ELx_CP15_64_ISS_CRM_MASK \ + (UL(0xf) << ESR_ELx_CP15_64_ISS_CRM_SHIFT) +#define ESR_ELx_CP15_64_ISS_RT2_SHIFT 10 +#define ESR_ELx_CP15_64_ISS_RT2_MASK \ + (UL(0x1f) << ESR_ELx_CP15_64_ISS_RT2_SHIFT) +#define ESR_ELx_CP15_64_ISS_OP1_SHIFT 16 +#define ESR_ELx_CP15_64_ISS_OP1_MASK \ + (UL(0xf) << ESR_ELx_CP15_64_ISS_OP1_SHIFT) +#define ESR_ELx_CP15_64_ISS_COND_SHIFT 20 +#define ESR_ELx_CP15_64_ISS_COND_MASK \ + (UL(0xf) << ESR_ELx_CP15_64_ISS_COND_SHIFT) +#define ESR_ELx_CP15_64_ISS_SYS_MASK (ESR_ELx_CP15_64_ISS_OP1_MASK | \ + ESR_ELx_CP15_64_ISS_CRM_MASK) +#define ESR_ELx_CP15_64_ISS_SYS_VAL(op1, crm) \ + (((op1) << ESR_ELx_CP15_64_ISS_OP1_SHIFT) | \ + ((crm) << ESR_ELx_CP15_64_ISS_CRM_SHIFT)) + +#define ESR_ELx_CP15_64_ISS_SYS_OP_MASK (ESR_ELx_CP15_64_ISS_SYS_MASK | \ + ESR_ELx_CP15_64_ISS_DIR_MASK) + +#define ESR_ELx_CP15_64_ISS_SYS_CNTVCT \ + (ESR_ELx_CP15_64_ISS_SYS_VAL(1, 14) | \ + ESR_ELx_CP15_64_ISS_DIR_READ) + #ifndef __ASSEMBLY__ #include diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 845958be3b20..f8ba35d6baa0 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -603,7 +603,7 @@ el0_sync_compat: cmp x24, #ESR_ELx_EC_CP15_32 // CP15 MRC/MCR trap b.eq el0_cp15_32_compat cmp x24, #ESR_ELx_EC_CP15_64 // CP15 MRRC/MCRR trap - b.eq el0_undef + b.eq el0_cp15_64_compat cmp x24, #ESR_ELx_EC_CP14_MR // CP14 MRC/MCR trap b.eq el0_undef cmp x24, #ESR_ELx_EC_CP14_LS // CP14 LDC/STC trap @@ -633,6 +633,17 @@ el0_cp15_32_compat: bl do_cp15_32_instr_compat b ret_to_user +el0_cp15_64_compat: + /* + * AArch32 CP15 MRRC/MCRR trap handling + */ + enable_dbg_and_irq + ct_user_exit + mov x0, x25 + mov x1, sp + bl do_cp15_64_instr_compat + b ret_to_user + .align 6 el0_irq_compat: kernel_entry 0, 32 diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 6a3d83c51182..fcd2b33e00cf 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -659,6 +659,69 @@ asmlinkage void __exception do_cp15_32_instr_compat(unsigned int esr, force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0); } + +static void cntvct_cp15_64_read_handler(unsigned int esr, struct pt_regs *regs) +{ + int rt = + (esr & ESR_ELx_CP15_64_ISS_RT_MASK) >> ESR_ELx_CP15_64_ISS_RT_SHIFT; + int rt2 = + (esr & ESR_ELx_CP15_64_ISS_RT2_MASK) >> ESR_ELx_CP15_64_ISS_RT2_SHIFT; + int cv = + (esr & ESR_ELx_CP15_64_ISS_CV_MASK) >> ESR_ELx_CP15_64_ISS_CV_SHIFT; + int cond = + (esr & ESR_ELx_CP15_64_ISS_COND_MASK) >> + ESR_ELx_CP15_64_ISS_COND_SHIFT; + bool read_reg = 1; + + if (rt == 15 || rt2 == 15 || rt == rt2) + read_reg = 0; + + if ((rt == 13 || rt2 == 13) && !compat_arm_instr_set(regs)) + read_reg = 0; + + if (cv && cond != 0xf && + !(*aarch32_opcode_cond_checks[cond])(regs->pstate & 0xffffffff)) + read_reg = 0; + + if (read_reg) { + u64 cval = arch_counter_get_cntvct(); + + regs->regs[rt] = cval & 0xffffffff; + regs->regs[rt2] = cval >> 32; + } + regs->pc += 4; +} + +struct cp15_64_hook { + unsigned int esr_mask; + unsigned int esr_val; + void (*handler)(unsigned int esr, struct pt_regs *regs); +}; + +static struct cp15_64_hook cp15_64_hooks[] = { + { + /* Trap CP15 AArch32 read access to CNTVCT_EL0 */ + .esr_mask = ESR_ELx_CP15_64_ISS_SYS_OP_MASK, + .esr_val = ESR_ELx_CP15_64_ISS_SYS_CNTVCT, + .handler = cntvct_cp15_64_read_handler, + }, + {}, +}; + +asmlinkage void __exception do_cp15_64_instr_compat(unsigned int esr, + struct pt_regs *regs) +{ + struct cp15_64_hook *hook; + + for (hook = cp15_64_hooks; hook->handler; hook++) + if ((hook->esr_mask & esr) == hook->esr_val) { + hook->handler(esr, regs); + return; + } + + force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0); +} + #endif long compat_arm_syscall(struct pt_regs *regs);