arm64: Add CNTFRQ_EL0 trap handler
authorMarc Zyngier <marc.zyngier@arm.com>
Mon, 24 Apr 2017 08:04:03 +0000 (09:04 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Mon, 24 Apr 2017 11:22:25 +0000 (12:22 +0100)
We now trap accesses to CNTVCT_EL0 when the counter is broken
enough to require the kernel to mediate the access. But it
turns out that some existing userspace (such as OpenMPI) do
probe for the counter frequency, leading to an UNDEF exception
as CNTVCT_EL0 and CNTFRQ_EL0 share the same control bit.

The fix is to handle the exception the same way we do for CNTVCT_EL0.

Fixes: a86bd139f2ae ("arm64: arch_timer: Enable CNTVCT_EL0 trap if workaround is enabled")
Reported-by: Hanjun Guo <guohanjun@huawei.com>
Tested-by: Hanjun Guo <guohanjun@huawei.com>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/esr.h
arch/arm64/kernel/traps.c

index ad42e79a5d4d4d08e57b64c16c4f2339e3539ec6..85997c0e544312a3d4e60157c4ba30d4d93239bd 100644 (file)
 
 #define ESR_ELx_SYS64_ISS_SYS_CNTVCT   (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \
                                         ESR_ELx_SYS64_ISS_DIR_READ)
+
+#define ESR_ELx_SYS64_ISS_SYS_CNTFRQ   (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \
+                                        ESR_ELx_SYS64_ISS_DIR_READ)
+
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 
index 1de444e6c6697ca716516f6df59e57917642129c..d4d6ae02cd558d6d2d7ff6a89db7cc9490e6cccf 100644 (file)
@@ -513,6 +513,14 @@ static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs)
        regs->pc += 4;
 }
 
+static void cntfrq_read_handler(unsigned int esr, struct pt_regs *regs)
+{
+       int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;
+
+       pt_regs_write_reg(regs, rt, read_sysreg(cntfrq_el0));
+       regs->pc += 4;
+}
+
 struct sys64_hook {
        unsigned int esr_mask;
        unsigned int esr_val;
@@ -537,6 +545,12 @@ static struct sys64_hook sys64_hooks[] = {
                .esr_val = ESR_ELx_SYS64_ISS_SYS_CNTVCT,
                .handler = cntvct_read_handler,
        },
+       {
+               /* Trap read access to CNTFRQ_EL0 */
+               .esr_mask = ESR_ELx_SYS64_ISS_SYS_OP_MASK,
+               .esr_val = ESR_ELx_SYS64_ISS_SYS_CNTFRQ,
+               .handler = cntfrq_read_handler,
+       },
        {},
 };