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

Commit e51cbabd authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "arm64: Add CNTVCT_EL0 cp15 AArch32 trap handler"

parents 308e69db d2bc82c5
Loading
Loading
Loading
Loading
+78 −0
Original line number Diff line number Diff line
@@ -218,6 +218,84 @@
		 ESR_ELx_SYS64_ISS_CRM_SHIFT),			\
		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
		 ESR_ELx_SYS64_ISS_OP2_SHIFT))
/* 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)

/* 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 <asm/types.h>
+4 −0
Original line number Diff line number Diff line
@@ -157,8 +157,12 @@ static inline void forget_syscall(struct pt_regs *regs)
#ifdef CONFIG_COMPAT
#define compat_thumb_mode(regs) \
	(((regs)->pstate & COMPAT_PSR_T_BIT))
#define compat_arm_instr_set(regs) \
	(((regs)->pstate & (COMPAT_PSR_T_BIT | COMPAT_PSR_J_BIT)) == 0)
#else
#define compat_thumb_mode(regs) (0)
#define compat_arm_instr_set(regs) (0)

#endif

#define user_mode(regs)	\
+24 −2
Original line number Diff line number Diff line
@@ -708,9 +708,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_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
@@ -729,6 +729,28 @@ el0_svc_compat:
	mov     wsc_nr, #__NR_compat_syscalls
	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

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
+118 −0
Original line number Diff line number Diff line
@@ -531,6 +531,124 @@ asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
	do_undefinstr(regs);
}

#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);
}

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);

asmlinkage long do_ni_syscall(struct pt_regs *regs)