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

Commit 02fe2845 authored by Russell King's avatar Russell King
Browse files

ARM: entry: avoid enabling interrupts in prefetch/data abort handlers



Avoid enabling interrupts if the parent context had interrupts enabled
in the abort handler assembly code, and move this into the breakpoint/
page/alignment fault handlers instead.

This gets rid of some special-casing for the breakpoint fault handlers
from the low level abort handler path.

Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 8b418616
Loading
Loading
Loading
Loading
+19 −24
Original line number Original line Diff line number Diff line
@@ -185,20 +185,15 @@ ENDPROC(__und_invalid)
__dabt_svc:
__dabt_svc:
	svc_entry
	svc_entry


	@
#ifdef CONFIG_TRACE_IRQFLAGS
	@ get ready to re-enable interrupts if appropriate
	bl	trace_hardirqs_off
	@
#endif
	mrs	r9, cpsr
	tst	r5, #PSR_I_BIT
	biceq	r9, r9, #PSR_I_BIT


	dabt_helper
	dabt_helper


	@
	@
	@ set desired IRQ state, then call main handler
	@ call main handler
	@
	@
	debug_entry r1
	msr	cpsr_c, r9
	mov	r2, sp
	mov	r2, sp
	bl	do_DataAbort
	bl	do_DataAbort


@@ -211,6 +206,12 @@ __dabt_svc:
	@ restore SPSR and restart the instruction
	@ restore SPSR and restart the instruction
	@
	@
	ldr	r5, [sp, #S_PSR]
	ldr	r5, [sp, #S_PSR]
#ifdef CONFIG_TRACE_IRQFLAGS
	tst	r5, #PSR_I_BIT
	bleq	trace_hardirqs_on
	tst	r5, #PSR_I_BIT
	blne	trace_hardirqs_off
#endif
	svc_exit r5				@ return from exception
	svc_exit r5				@ return from exception
 UNWIND(.fnend		)
 UNWIND(.fnend		)
ENDPROC(__dabt_svc)
ENDPROC(__dabt_svc)
@@ -307,16 +308,11 @@ ENDPROC(__und_svc)
__pabt_svc:
__pabt_svc:
	svc_entry
	svc_entry


	@
#ifdef CONFIG_TRACE_IRQFLAGS
	@ re-enable interrupts if appropriate
	bl	trace_hardirqs_off
	@
#endif
	mrs	r9, cpsr
	tst	r5, #PSR_I_BIT
	biceq	r9, r9, #PSR_I_BIT


	pabt_helper
	pabt_helper
	debug_entry r1
	msr	cpsr_c, r9			@ Maybe enable interrupts
	mov	r2, sp				@ regs
	mov	r2, sp				@ regs
	bl	do_PrefetchAbort		@ call abort handler
	bl	do_PrefetchAbort		@ call abort handler


@@ -329,6 +325,12 @@ __pabt_svc:
	@ restore SPSR and restart the instruction
	@ restore SPSR and restart the instruction
	@
	@
	ldr	r5, [sp, #S_PSR]
	ldr	r5, [sp, #S_PSR]
#ifdef CONFIG_TRACE_IRQFLAGS
	tst	r5, #PSR_I_BIT
	bleq	trace_hardirqs_on
	tst	r5, #PSR_I_BIT
	blne	trace_hardirqs_off
#endif
	svc_exit r5				@ return from exception
	svc_exit r5				@ return from exception
 UNWIND(.fnend		)
 UNWIND(.fnend		)
ENDPROC(__pabt_svc)
ENDPROC(__pabt_svc)
@@ -412,11 +414,6 @@ __dabt_usr:
	kuser_cmpxchg_check
	kuser_cmpxchg_check
	dabt_helper
	dabt_helper


	@
	@ IRQs on, then call the main handler
	@
	debug_entry r1
	enable_irq
	mov	r2, sp
	mov	r2, sp
	adr	lr, BSYM(ret_from_exception)
	adr	lr, BSYM(ret_from_exception)
	b	do_DataAbort
	b	do_DataAbort
@@ -663,8 +660,6 @@ ENDPROC(__und_usr_unknown)
__pabt_usr:
__pabt_usr:
	usr_entry
	usr_entry
	pabt_helper
	pabt_helper
	debug_entry r1
	enable_irq				@ Enable interrupts
	mov	r2, sp				@ regs
	mov	r2, sp				@ regs
	bl	do_PrefetchAbort		@ call abort handler
	bl	do_PrefetchAbort		@ call abort handler
 UNWIND(.fnend		)
 UNWIND(.fnend		)
+0 −19
Original line number Original line Diff line number Diff line
@@ -165,25 +165,6 @@
	.endm
	.endm
#endif	/* !CONFIG_THUMB2_KERNEL */
#endif	/* !CONFIG_THUMB2_KERNEL */


	@
	@ Debug exceptions are taken as prefetch or data aborts.
	@ We must disable preemption during the handler so that
	@ we can access the debug registers safely.
	@
	.macro	debug_entry, fsr
#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT)
	ldr	r4, =0x40f		@ mask out fsr.fs
	and	r5, r4, \fsr
	cmp	r5, #2			@ debug exception
	bne	1f
	get_thread_info r10
	ldr	r6, [r10, #TI_PREEMPT]	@ get preempt count
	add	r11, r6, #1		@ increment it
	str	r11, [r10, #TI_PREEMPT]
1:
#endif
	.endm

/*
/*
 * These are the registers used in the syscall handler, and allow us to
 * These are the registers used in the syscall handler, and allow us to
 * have in theory up to 7 arguments to a function - r0 to r6.
 * have in theory up to 7 arguments to a function - r0 to r6.
+5 −7
Original line number Original line Diff line number Diff line
@@ -796,7 +796,7 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)


/*
/*
 * Called from either the Data Abort Handler [watchpoint] or the
 * Called from either the Data Abort Handler [watchpoint] or the
 * Prefetch Abort Handler [breakpoint] with preemption disabled.
 * Prefetch Abort Handler [breakpoint] with interrupts disabled.
 */
 */
static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
				 struct pt_regs *regs)
				 struct pt_regs *regs)
@@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
	int ret = 0;
	int ret = 0;
	u32 dscr;
	u32 dscr;


	/* We must be called with preemption disabled. */
	preempt_disable();
	WARN_ON(preemptible());

	if (interrupts_enabled(regs))
		local_irq_enable();


	/* We only handle watchpoints and hardware breakpoints. */
	/* We only handle watchpoints and hardware breakpoints. */
	ARM_DBG_READ(c1, 0, dscr);
	ARM_DBG_READ(c1, 0, dscr);
@@ -824,10 +826,6 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
		ret = 1; /* Unhandled fault. */
		ret = 1; /* Unhandled fault. */
	}
	}


	/*
	 * Re-enable preemption after it was disabled in the
	 * low-level exception handling code.
	 */
	preempt_enable();
	preempt_enable();


	return ret;
	return ret;
+3 −0
Original line number Original line Diff line number Diff line
@@ -727,6 +727,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
	int isize = 4;
	int isize = 4;
	int thumb2_32b = 0;
	int thumb2_32b = 0;


	if (interrupts_enabled(regs))
		local_irq_enable();

	instrptr = instruction_pointer(regs);
	instrptr = instruction_pointer(regs);


	fs = get_fs();
	fs = get_fs();
+4 −0
Original line number Original line Diff line number Diff line
@@ -285,6 +285,10 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
	tsk = current;
	tsk = current;
	mm  = tsk->mm;
	mm  = tsk->mm;


	/* Enable interrupts if they were enabled in the parent context. */
	if (interrupts_enabled(regs))
		local_irq_enable();

	/*
	/*
	 * If we're in an interrupt or have no user
	 * If we're in an interrupt or have no user
	 * context, we must not take the fault..
	 * context, we must not take the fault..