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

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

Merge "arm: traps: emulate a MRC instruction reading CNTFRQ register"

parents d36384aa 6bd5f11e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ static inline int __in_irqentry_text(unsigned long ptr)
	       ptr < (unsigned long)&__irqentry_text_end;
}

extern void get_timer_freq_hook_init(void);
extern void get_timer_count_hook_init(void);
extern void __init early_trap_init(void *);
extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
+72 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <linux/irq.h>

#include <linux/atomic.h>
#include <asm/arch_timer.h>
#include <asm/cacheflush.h>
#include <asm/exception.h>
#include <asm/unistd.h>
@@ -736,6 +737,77 @@ late_initcall(arm_mrc_hook_init);

#endif

static int get_timer_count_trap(struct pt_regs *regs, unsigned int instr)
{
	u64 cval;
	unsigned int res;
	int rd = (instr >> 12) & 0xF;
	int rn =  (instr >> 16) & 0xF;

	res = arm_check_condition(instr, regs->ARM_cpsr);
	if (res == ARM_OPCODE_CONDTEST_FAIL) {
		regs->ARM_pc += 4;
		return 0;
	}

	if (rd == 15 || rn == 15)
		return 1;
	cval = arch_counter_get_cntvct();
	regs->uregs[rd] = cval;
	regs->uregs[rn] = cval >> 32;
	regs->ARM_pc += 4;
	return 0;
}

static struct undef_hook get_timer_count_hook = {
	.instr_mask	= 0x0ff00fff,
	.instr_val	= 0x0c500f1e,
	.cpsr_mask	= MODE_MASK,
	.cpsr_val	= USR_MODE,
	.fn		= get_timer_count_trap,
};

void get_timer_count_hook_init(void)
{
	register_undef_hook(&get_timer_count_hook);
}
EXPORT_SYMBOL(get_timer_count_hook_init);

static int get_freq_trap(struct pt_regs *regs, unsigned int instr)
{
	u32 fval;
	unsigned int res;
	int rd = (instr >> 12) & 0xF;

	res = arm_check_condition(instr, regs->ARM_cpsr);
	if (res == ARM_OPCODE_CONDTEST_FAIL) {
		regs->ARM_pc += 4;
		return 0;
	}

	if (rd == 15)
		return 1;

	fval = arch_timer_get_cntfrq();
	regs->uregs[rd] = fval;
	regs->ARM_pc += 4;
	return 0;
}

static struct undef_hook get_freq_hook = {
	.instr_mask	= 0x0fff0fff,
	.instr_val	= 0x0e1e0f10,
	.cpsr_mask	= MODE_MASK,
	.cpsr_val	= USR_MODE,
	.fn		= get_freq_trap,
};

void get_timer_freq_hook_init(void)
{
	register_undef_hook(&get_freq_hook);
}
EXPORT_SYMBOL(get_timer_freq_hook_init);

/*
 * A data abort trap was taken, but we did not handle the instruction.
 * Try to abort the user program, or panic if it was the kernel.
+2 −0
Original line number Diff line number Diff line
@@ -120,4 +120,6 @@ static inline u32 arm64_ras_serror_get_severity(u32 esr)

bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr);
void __noreturn arm64_serror_panic(struct pt_regs *regs, u32 esr);
static inline void get_timer_count_hook_init(void) {}
static inline void get_timer_freq_hook_init(void) {}
#endif
+8 −0
Original line number Diff line number Diff line
@@ -376,6 +376,14 @@ config SUN50I_ERRATUM_UNKNOWN1
	  the Allwinner A64 SoC. The workaround will only be active if the
	  allwinner,erratum-unknown1 property is found in the timer node.

config ARM_ARCH_TIMER_VCT_ACCESS
	bool "Support for ARM architected timer virtual counter access in userspace"
	default n
	depends on ARM_ARCH_TIMER
	help
	  This option enables support for reading the ARM architected timer's
	  virtual counter in userspace.

config ARM_GLOBAL_TIMER
	bool "Support for the ARM global timer" if COMPILE_TEST
	select TIMER_OF if OF
+5 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/acpi.h>

#include <asm/arch_timer.h>
#include <asm/traps.h>
#include <asm/virt.h>

#include <clocksource/arm_arch_timer.h>
@@ -871,7 +872,8 @@ static void arch_counter_set_user_access(void)
	 * need to be workaround. The vdso may have been already
	 * disabled though.
	 */
	if (arch_timer_this_cpu_has_cntvct_wa())
	if (arch_timer_this_cpu_has_cntvct_wa() ||
	    !IS_ENABLED(CONFIG_ARM_ARCH_TIMER_VCT_ACCESS))
		pr_info("CPU%d: Trapping CNTVCT access\n", smp_processor_id());
	else
		cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
@@ -1519,6 +1521,8 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
	ret = arch_timer_mem_frame_register(frame);
	if (!ret && !arch_timer_needs_of_probing())
		ret = arch_timer_common_init();
	get_timer_count_hook_init();
	get_timer_freq_hook_init();
out:
	kfree(timer_mem);
	return ret;