public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Nicolin Chen <nicoleotsuka@gmail.com>
To: marc.zyngier@arm.com, mark.rutland@arm.com
Cc: catalin.marinas@arm.com, will.deacon@arm.com, oleg@redhat.com,
	cdall@linaro.org, tbaicar@codeaurora.org, julien.thierry@arm.com,
	Dave.Martin@arm.com, robin.murphy@arm.com, james.morse@arm.com,
	ard.biesheuvel@linaro.org, xiexiuqi@huawei.com, mingo@kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH RFC v1] arm64: Handle traps from accessing CNTVCT/CNTFRQ for CONFIG_COMPAT
Date: Wed, 10 Jan 2018 20:43:36 -0800	[thread overview]
Message-ID: <1515645816-14063-1-git-send-email-nicoleotsuka@gmail.com> (raw)

CONFIG_COMPAT allows ARM64 machine to run 32-bit instructions.
Since the ARCH_TIMER_USR_VCT_ACCESS_EN might be disabled if a
timer workaround is detected, accessing cntvct via mrrc will
also trigger a trap.

So this patch adds support to handle this situation.

Tested with a user program generated by 32-bit compiler:
  int main()
  {
      unsigned long long cval;
      asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
      return 0;
  }

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---

[ I also added cntfrq here for safety as theoretically it could
  trigger the trap as well. However, my another test case (with
  mrc insturction) doesn't seem to trigger a trap. So I would
  drop it in the next version if someone can confirm it's not
  required. Thanks -- Nicolin ]

 arch/arm64/include/asm/esr.h    | 25 +++++++++++++++++++
 arch/arm64/include/asm/ptrace.h | 15 ++++++++++++
 arch/arm64/kernel/entry.S       |  4 ++--
 arch/arm64/kernel/traps.c       | 53 +++++++++++++++++++++++++++++++++++++++--
 4 files changed, 93 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 014d7d8..55dea62 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -220,6 +220,31 @@
 		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
 		 ESR_ELx_SYS64_ISS_OP2_SHIFT))
 
+/* ISS fields for MRC and MRS are very similar, so reuse SYS64 macros */
+#define ESR_ELx_CP15_32_ISS_MRC_MASK	ESR_ELx_SYS64_ISS_SYS_MASK
+#define ESR_ELx_CP15_32_ISS_MRC_CNTFRQ	(ESR_ELx_SYS64_ISS_SYS_VAL(0, 0, 0, 14, 0) | \
+					 ESR_ELx_SYS64_ISS_DIR_READ)
+
+/* ISS field definitions for CP15 MRRC/MCRR instructions (same for CP14) */
+#define ESR_ELx_CP15_64_ISS_OPC1_SHIFT	16
+#define ESR_ELx_CP15_64_ISS_OPC1_MASK	(UL(0xf) << ESR_ELx_CP15_64_ISS_OPC1_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_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_MRRC_MASK	(ESR_ELx_CP15_64_ISS_OPC1_MASK | \
+					 ESR_ELx_CP15_64_ISS_CRM_MASK| \
+					 ESR_ELx_SYS64_ISS_DIR_MASK)
+
+#define ESR_ELx_CP15_64_ISS_MRRC_VAL(opc1, crm) \
+					(((opc1) << ESR_ELx_CP15_64_ISS_OPC1_SHIFT) | \
+					 ((crm) << ESR_ELx_CP15_64_ISS_CRM_SHIFT))
+
+#define ESR_ELx_CP15_64_ISS_MRRC_CNTVCT	(ESR_ELx_CP15_64_ISS_MRRC_VAL(1, 14) | \
+					 ESR_ELx_SYS64_ISS_DIR_READ)
+
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 6069d66..50caf11 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -243,6 +243,21 @@ static inline void pt_regs_write_reg(struct pt_regs *regs, int r,
 		regs->regs[r] = val;
 }
 
+/*
+ * Write two registers given architectural register index r and r2.
+ * Used by 32-bit MRRC and MCRR instrutions for 64-bit results
+ */
+static inline void pt_regs_write_regs(struct pt_regs *regs, int r, int r2,
+				      unsigned long val)
+{
+	if (r != 31 && r2 != 31) {
+		/* Save lower 32 bits to register r */
+		regs->regs[r] = val & 0xffffffff;
+		/* Save higher 32 bits to register r2 */
+		regs->regs[r2] = val >> 32;
+	}
+}
+
 /* Valid only for Kernel mode traps. */
 static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
 {
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 6d14b8f..9d6cd95 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -636,9 +636,9 @@ el0_sync_compat:
 	cmp	x24, #ESR_ELx_EC_UNKNOWN	// unknown exception in EL0
 	b.eq	el0_undef
 	cmp	x24, #ESR_ELx_EC_CP15_32	// CP15 MRC/MCR trap
-	b.eq	el0_undef
+	b.eq	el0_sys
 	cmp	x24, #ESR_ELx_EC_CP15_64	// CP15 MRRC/MCRR trap
-	b.eq	el0_undef
+	b.eq	el0_sys
 	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
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 3d3588f..211cce7 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -454,6 +454,17 @@ static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs)
 	arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
 }
 
+#ifdef CONFIG_COMPAT
+static void cntvct_read_32_handler(unsigned int esr, struct pt_regs *regs)
+{
+	int rt2 = (esr & ESR_ELx_CP15_64_ISS_RT2_MASK) >> ESR_ELx_CP15_64_ISS_RT2_SHIFT;
+	int rt = (esr & ESR_ELx_CP15_64_ISS_RT_MASK) >> ESR_ELx_CP15_64_ISS_RT_SHIFT;
+
+	pt_regs_write_regs(regs, rt, rt2, arch_counter_get_cntvct());
+	arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
+}
+#endif
+
 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;
@@ -495,11 +506,49 @@ static struct sys64_hook sys64_hooks[] = {
 	{},
 };
 
+#ifdef CONFIG_COMPAT
+static struct sys64_hook cp15_32_hooks[] = {
+	{
+		/* Trap read access to CNTFRQ via 32-bit insturction MRC */
+		.esr_mask = ESR_ELx_CP15_32_ISS_MRC_MASK,
+		.esr_val = ESR_ELx_CP15_32_ISS_MRC_CNTFRQ,
+		.handler = cntfrq_read_handler,
+	},
+	{},
+};
+
+static struct sys64_hook cp15_64_hooks[] = {
+	{
+		/* Trap read access to CNTVCT via 32-bit insturction MRRC */
+		.esr_mask = ESR_ELx_CP15_64_ISS_MRRC_MASK,
+		.esr_val = ESR_ELx_CP15_64_ISS_MRRC_CNTVCT,
+		.handler = cntvct_read_32_handler,
+	},
+	{},
+};
+#endif
+
 asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
 {
-	struct sys64_hook *hook;
+	struct sys64_hook *hook = NULL;
+
+	switch (ESR_ELx_EC(esr)) {
+#ifdef CONFIG_COMPAT
+	case ESR_ELx_EC_CP15_32:
+		hook = cp15_32_hooks;
+		break;
+	case ESR_ELx_EC_CP15_64:
+		hook = cp15_64_hooks;
+		break;
+#endif
+	case ESR_ELx_EC_SYS64:
+		hook = sys64_hooks;
+		break;
+	default:
+		break;
+	}
 
-	for (hook = sys64_hooks; hook->handler; hook++)
+	for (; hook && hook->handler; hook++)
 		if ((hook->esr_mask & esr) == hook->esr_val) {
 			hook->handler(esr, regs);
 			return;
-- 
2.1.4

             reply	other threads:[~2018-01-11  4:43 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-11  4:43 Nicolin Chen [this message]
2018-01-11  8:51 ` [PATCH RFC v1] arm64: Handle traps from accessing CNTVCT/CNTFRQ for CONFIG_COMPAT Marc Zyngier
2018-01-16 20:32   ` Nicolin Chen
2018-01-16 21:19     ` Marc Zyngier
2018-01-16 21:37       ` Nicolin Chen
2018-01-17  2:13         ` Nicolin Chen
2018-01-17  9:03           ` Marc Zyngier
2018-01-17 20:41             ` Nicolin Chen
2018-01-17 23:35               ` Robin Murphy
2018-01-17 23:39                 ` Nicolin Chen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1515645816-14063-1-git-send-email-nicoleotsuka@gmail.com \
    --to=nicoleotsuka@gmail.com \
    --cc=Dave.Martin@arm.com \
    --cc=ard.biesheuvel@linaro.org \
    --cc=catalin.marinas@arm.com \
    --cc=cdall@linaro.org \
    --cc=james.morse@arm.com \
    --cc=julien.thierry@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marc.zyngier@arm.com \
    --cc=mark.rutland@arm.com \
    --cc=mingo@kernel.org \
    --cc=oleg@redhat.com \
    --cc=robin.murphy@arm.com \
    --cc=tbaicar@codeaurora.org \
    --cc=will.deacon@arm.com \
    --cc=xiexiuqi@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox