Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d764241 authored by Neeraj Upadhyay's avatar Neeraj Upadhyay
Browse files

arm64: Add CNTFRQ_EL0 cp15 AArch32 trap handler



As cntfrq and cntvct share the same control bit, cntfrq_el0
access was disabled by default, in
'commit 7b4edf24 ("clocksource: arch_timer: make virtual
counter access configurable")'. There is a trap handler added
for user access using mrs instruction in
'commit e9632ce8 ("arm64: Add CNTFRQ_EL0 trap handler")'.
However, el0 running in AArch32 can try to access cntfrq
using mrc instruction. So, add a trap handler to support that.

Change-Id: I60d65b73961f3e35377a5601b7bfe5db37947f68
Signed-off-by: default avatarNeeraj Upadhyay <neeraju@codeaurora.org>
parent 2b029ca3
Loading
Loading
Loading
Loading
+43 −0
Original line number Original line Diff line number Diff line
@@ -181,6 +181,49 @@
#define ESR_ELx_SYS64_ISS_SYS_CNTFRQ	(ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \
#define ESR_ELx_SYS64_ISS_SYS_CNTFRQ	(ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \
					 ESR_ELx_SYS64_ISS_DIR_READ)
					 ESR_ELx_SYS64_ISS_DIR_READ)


/* ISS field definitions for CP15 AArch32 access traps */
#define ESR_ELx_CP15_32_ISS_CV_SHIFT	24
#define ESR_ELx_CP15_32_ISS_CV_MASK \
				(UL(0x1) << ESR_ELx_CP15_32_ISS_CV_SHIFT)
#define ESR_ELx_CP15_32_ISS_DIR_MASK	0x1
#define ESR_ELx_CP15_32_ISS_DIR_READ	0x1
#define ESR_ELx_CP15_32_ISS_DIR_WRITE	0x0

#define ESR_ELx_CP15_32_ISS_RT_SHIFT	5
#define ESR_ELx_CP15_32_ISS_RT_MASK \
				(UL(0x1f) << ESR_ELx_CP15_32_ISS_RT_SHIFT)
#define ESR_ELx_CP15_32_ISS_CRM_SHIFT	1
#define ESR_ELx_CP15_32_ISS_CRM_MASK \
				(UL(0xf) << ESR_ELx_CP15_32_ISS_CRM_SHIFT)
#define ESR_ELx_CP15_32_ISS_CRN_SHIFT	10
#define ESR_ELx_CP15_32_ISS_CRN_MASK \
				(UL(0xf) << ESR_ELx_CP15_32_ISS_CRN_SHIFT)
#define ESR_ELx_CP15_32_ISS_OP1_SHIFT	14
#define ESR_ELx_CP15_32_ISS_OP1_MASK \
				(UL(0x7) << ESR_ELx_CP15_32_ISS_OP1_SHIFT)
#define ESR_ELx_CP15_32_ISS_OP2_SHIFT	17
#define ESR_ELx_CP15_32_ISS_OP2_MASK \
				(UL(0x7) << ESR_ELx_CP15_32_ISS_OP2_SHIFT)
#define ESR_ELx_CP15_32_ISS_COND_SHIFT	20
#define ESR_ELx_CP15_32_ISS_COND_MASK \
				(UL(0xf) << ESR_ELx_CP15_32_ISS_COND_SHIFT)
#define ESR_ELx_CP15_32_ISS_SYS_MASK	(ESR_ELx_CP15_32_ISS_OP1_MASK | \
					 ESR_ELx_CP15_32_ISS_OP2_MASK | \
					 ESR_ELx_CP15_32_ISS_CRN_MASK | \
					 ESR_ELx_CP15_32_ISS_CRM_MASK)
#define ESR_ELx_CP15_32_ISS_SYS_VAL(op1, op2, crn, crm) \
				(((op1) << ESR_ELx_CP15_32_ISS_OP1_SHIFT) | \
				 ((op2) << ESR_ELx_CP15_32_ISS_OP2_SHIFT) | \
				 ((crn) << ESR_ELx_CP15_32_ISS_CRN_SHIFT) | \
				 ((crm) << ESR_ELx_CP15_32_ISS_CRM_SHIFT))

#define ESR_ELx_CP15_32_ISS_SYS_OP_MASK	(ESR_ELx_CP15_32_ISS_SYS_MASK | \
					 ESR_ELx_CP15_32_ISS_DIR_MASK)

#define ESR_ELx_CP15_32_ISS_SYS_CNTFRQ	\
				(ESR_ELx_CP15_32_ISS_SYS_VAL(0, 0, 14, 0) | \
				 ESR_ELx_CP15_32_ISS_DIR_READ)

#ifndef __ASSEMBLY__
#ifndef __ASSEMBLY__
#include <asm/types.h>
#include <asm/types.h>


+4 −0
Original line number Original line Diff line number Diff line
@@ -130,8 +130,12 @@ struct pt_regs {
#ifdef CONFIG_COMPAT
#ifdef CONFIG_COMPAT
#define compat_thumb_mode(regs) \
#define compat_thumb_mode(regs) \
	(((regs)->pstate & COMPAT_PSR_T_BIT))
	(((regs)->pstate & COMPAT_PSR_T_BIT))
#define compat_arm_instr_set(regs) \
	(((regs)->pstate & (COMPAT_PSR_T_BIT | COMPAT_PSR_J_BIT)) == 0)
#else
#else
#define compat_thumb_mode(regs) (0)
#define compat_thumb_mode(regs) (0)
#define compat_arm_instr_set(regs) (0)

#endif
#endif


#define user_mode(regs)	\
#define user_mode(regs)	\
+12 −1
Original line number Original line Diff line number Diff line
@@ -601,7 +601,7 @@ el0_sync_compat:
	cmp	x24, #ESR_ELx_EC_UNKNOWN	// unknown exception in EL0
	cmp	x24, #ESR_ELx_EC_UNKNOWN	// unknown exception in EL0
	b.eq	el0_undef
	b.eq	el0_undef
	cmp	x24, #ESR_ELx_EC_CP15_32	// CP15 MRC/MCR trap
	cmp	x24, #ESR_ELx_EC_CP15_32	// CP15 MRC/MCR trap
	b.eq	el0_undef
	b.eq	el0_cp15_32_compat
	cmp	x24, #ESR_ELx_EC_CP15_64	// CP15 MRRC/MCRR trap
	cmp	x24, #ESR_ELx_EC_CP15_64	// CP15 MRRC/MCRR trap
	b.eq	el0_undef
	b.eq	el0_undef
	cmp	x24, #ESR_ELx_EC_CP14_MR	// CP14 MRC/MCR trap
	cmp	x24, #ESR_ELx_EC_CP14_MR	// CP14 MRC/MCR trap
@@ -622,6 +622,17 @@ el0_svc_compat:
	mov     sc_nr, #__NR_compat_syscalls
	mov     sc_nr, #__NR_compat_syscalls
	b	el0_svc_naked
	b	el0_svc_naked


el0_cp15_32_compat:
	/*
	 * AArch32 CP15 MRC/MCR trap handling
	 */
	enable_dbg_and_irq
	ct_user_exit
	mov	x0, x25
	mov	x1, sp
	bl	do_cp15_32_instr_compat
	b	ret_to_user

	.align	6
	.align	6
el0_irq_compat:
el0_irq_compat:
	kernel_entry 0, 32
	kernel_entry 0, 32
+55 −0
Original line number Original line Diff line number Diff line
@@ -606,6 +606,61 @@ asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
	force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
	force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
}
}


#ifdef CONFIG_COMPAT
static void cntfrq_cp15_32_read_handler(unsigned int esr, struct pt_regs *regs)
{
	int rt =
	  (esr & ESR_ELx_CP15_32_ISS_RT_MASK) >> ESR_ELx_CP15_32_ISS_RT_SHIFT;
	int cv =
	  (esr & ESR_ELx_CP15_32_ISS_CV_MASK) >> ESR_ELx_CP15_32_ISS_CV_SHIFT;
	int cond =
	  (esr & ESR_ELx_CP15_32_ISS_COND_MASK) >>
		ESR_ELx_CP15_32_ISS_COND_SHIFT;
	bool read_reg = 1;

	if (rt == 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)
		regs->regs[rt] = read_sysreg(cntfrq_el0);
	regs->pc += 4;
}

struct cp15_32_hook {
	unsigned int esr_mask;
	unsigned int esr_val;
	void (*handler)(unsigned int esr, struct pt_regs *regs);
};

static struct cp15_32_hook cp15_32_hooks[] = {
	{
		/* Trap CP15 AArch32 read access to CNTFRQ_EL0 */
		.esr_mask = ESR_ELx_CP15_32_ISS_SYS_OP_MASK,
		.esr_val = ESR_ELx_CP15_32_ISS_SYS_CNTFRQ,
		.handler = cntfrq_cp15_32_read_handler,
	},
	{},
};

asmlinkage void __exception do_cp15_32_instr_compat(unsigned int esr,
						    struct pt_regs *regs)
{
	struct cp15_32_hook *hook;

	for (hook = cp15_32_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);
long compat_arm_syscall(struct pt_regs *regs);


asmlinkage long do_ni_syscall(struct pt_regs *regs)
asmlinkage long do_ni_syscall(struct pt_regs *regs)