BACKPORT: arm64: Add CNTVCT_EL0 trap handler
authorMarc Zyngier <marc.zyngier@arm.com>
Wed, 1 Feb 2017 11:48:58 +0000 (11:48 +0000)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 9 Jan 2018 12:35:07 +0000 (13:35 +0100)
Since people seem to make a point in breaking the userspace visible
counter, we have no choice but to trap the access. Add the required
handler.

Acked-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
(cherry picked from commit 6126ce0588eb5a0752d5c8b5796a7fca324fd887)

Change-Id: I0705f47c85a78040df38df18f51a4a22500b904d
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
arch/arm64/include/asm/esr.h
arch/arm64/kernel/entry.S
arch/arm64/kernel/traps.c

index f772e15c47663f0aafa1b287e8b9ac6aa3a55d2c..f40f2f4a4e847c2614c52abfc2af9f87557e147a 100644 (file)
        ((ESR_ELx_EC_BRK64 << ESR_ELx_EC_SHIFT) | ESR_ELx_IL |  \
         ((imm) & 0xffff))
 
+/* ISS field definitions for System instruction traps */
+#define ESR_ELx_SYS64_ISS_RES0_SHIFT   22
+#define ESR_ELx_SYS64_ISS_RES0_MASK    (UL(0x7) << ESR_ELx_SYS64_ISS_RES0_SHIFT)
+#define ESR_ELx_SYS64_ISS_DIR_MASK     0x1
+#define ESR_ELx_SYS64_ISS_DIR_READ     0x1
+#define ESR_ELx_SYS64_ISS_DIR_WRITE    0x0
+
+#define ESR_ELx_SYS64_ISS_RT_SHIFT     5
+#define ESR_ELx_SYS64_ISS_RT_MASK      (UL(0x1f) << ESR_ELx_SYS64_ISS_RT_SHIFT)
+#define ESR_ELx_SYS64_ISS_CRM_SHIFT    1
+#define ESR_ELx_SYS64_ISS_CRM_MASK     (UL(0xf) << ESR_ELx_SYS64_ISS_CRM_SHIFT)
+#define ESR_ELx_SYS64_ISS_CRN_SHIFT    10
+#define ESR_ELx_SYS64_ISS_CRN_MASK     (UL(0xf) << ESR_ELx_SYS64_ISS_CRN_SHIFT)
+#define ESR_ELx_SYS64_ISS_OP1_SHIFT    14
+#define ESR_ELx_SYS64_ISS_OP1_MASK     (UL(0x7) << ESR_ELx_SYS64_ISS_OP1_SHIFT)
+#define ESR_ELx_SYS64_ISS_OP2_SHIFT    17
+#define ESR_ELx_SYS64_ISS_OP2_MASK     (UL(0x7) << ESR_ELx_SYS64_ISS_OP2_SHIFT)
+#define ESR_ELx_SYS64_ISS_OP0_SHIFT    20
+#define ESR_ELx_SYS64_ISS_OP0_MASK     (UL(0x3) << ESR_ELx_SYS64_ISS_OP0_SHIFT)
+#define ESR_ELx_SYS64_ISS_SYS_MASK     (ESR_ELx_SYS64_ISS_OP0_MASK | \
+                                        ESR_ELx_SYS64_ISS_OP1_MASK | \
+                                        ESR_ELx_SYS64_ISS_OP2_MASK | \
+                                        ESR_ELx_SYS64_ISS_CRN_MASK | \
+                                        ESR_ELx_SYS64_ISS_CRM_MASK)
+#define ESR_ELx_SYS64_ISS_SYS_VAL(op0, op1, op2, crn, crm) \
+                                       (((op0) << ESR_ELx_SYS64_ISS_OP0_SHIFT) | \
+                                        ((op1) << ESR_ELx_SYS64_ISS_OP1_SHIFT) | \
+                                        ((op2) << ESR_ELx_SYS64_ISS_OP2_SHIFT) | \
+                                        ((crn) << ESR_ELx_SYS64_ISS_CRN_SHIFT) | \
+                                        ((crm) << ESR_ELx_SYS64_ISS_CRM_SHIFT))
+
+#define ESR_ELx_SYS64_ISS_SYS_OP_MASK  (ESR_ELx_SYS64_ISS_SYS_MASK | \
+                                        ESR_ELx_SYS64_ISS_DIR_MASK)
+
+#define ESR_ELx_SYS64_ISS_SYS_CNTVCT   (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \
+                                        ESR_ELx_SYS64_ISS_DIR_READ)
+
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 
index 4473036955b7a724f3e9ed11d73f400fa5433b31..434ef71782240e158b12592d09eaa98ed50b92d8 100644 (file)
@@ -604,7 +604,7 @@ el0_sync:
        cmp     x24, #ESR_ELx_EC_FP_EXC64       // FP/ASIMD exception
        b.eq    el0_fpsimd_exc
        cmp     x24, #ESR_ELx_EC_SYS64          // configurable trap
-       b.eq    el0_undef
+       b.eq    el0_sys
        cmp     x24, #ESR_ELx_EC_SP_ALIGN       // stack alignment exception
        b.eq    el0_sp_pc
        cmp     x24, #ESR_ELx_EC_PC_ALIGN       // pc alignment exception
@@ -732,6 +732,16 @@ el0_undef:
        mov     x0, sp
        bl      do_undefinstr
        b       ret_to_user
+el0_sys:
+       /*
+        * System instructions, for trapped cache maintenance instructions
+        */
+       enable_dbg_and_irq
+       ct_user_exit
+       mov     x0, x25
+       mov     x1, sp
+       bl      do_sysinstr
+       b       ret_to_user
 el0_dbg:
        /*
         * Debug exception handling
index 9b42bb2214ee8a0838225f1742f2e3cf702ff206..42615da5b2e97700f16cb878795306e2f04c0b23 100644 (file)
@@ -409,6 +409,25 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
        arm64_notify_die("Oops - undefined instruction", regs, &info, 0);
 }
 
+static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs)
+{
+       int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;
+
+       if (rt != 31)
+               regs->regs[rt] = arch_counter_get_cntvct();
+       regs->pc += 4;
+}
+
+asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
+{
+       if ((esr & ESR_ELx_SYS64_ISS_SYS_OP_MASK) == ESR_ELx_SYS64_ISS_SYS_CNTVCT) {
+               cntvct_read_handler(esr, regs);
+               return;
+       }
+
+       do_undefinstr(regs);
+}
+
 long compat_arm_syscall(struct pt_regs *regs);
 
 asmlinkage long do_ni_syscall(struct pt_regs *regs)