Skip to content

Commit

Permalink
ARM: entry: avoid enabling interrupts in prefetch/data abort handlers
Browse files Browse the repository at this point in the history
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: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King committed Jul 2, 2011
1 parent 8b41861 commit 02fe284
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 50 deletions.
43 changes: 19 additions & 24 deletions arch/arm/kernel/entry-armv.S
Original file line number Diff line number Diff line change
Expand Up @@ -185,20 +185,15 @@ ENDPROC(__und_invalid)
__dabt_svc:
svc_entry

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

dabt_helper

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

Expand All @@ -211,6 +206,12 @@ __dabt_svc:
@ restore SPSR and restart the instruction
@
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
UNWIND(.fnend )
ENDPROC(__dabt_svc)
Expand Down Expand Up @@ -307,16 +308,11 @@ ENDPROC(__und_svc)
__pabt_svc:
svc_entry

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

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

Expand All @@ -329,6 +325,12 @@ __pabt_svc:
@ restore SPSR and restart the instruction
@
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
UNWIND(.fnend )
ENDPROC(__pabt_svc)
Expand Down Expand Up @@ -412,11 +414,6 @@ __dabt_usr:
kuser_cmpxchg_check
dabt_helper

@
@ IRQs on, then call the main handler
@
debug_entry r1
enable_irq
mov r2, sp
adr lr, BSYM(ret_from_exception)
b do_DataAbort
Expand Down Expand Up @@ -663,8 +660,6 @@ ENDPROC(__und_usr_unknown)
__pabt_usr:
usr_entry
pabt_helper
debug_entry r1
enable_irq @ Enable interrupts
mov r2, sp @ regs
bl do_PrefetchAbort @ call abort handler
UNWIND(.fnend )
Expand Down
19 changes: 0 additions & 19 deletions arch/arm/kernel/entry-header.S
Original file line number Diff line number Diff line change
Expand Up @@ -165,25 +165,6 @@
.endm
#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
* have in theory up to 7 arguments to a function - r0 to r6.
Expand Down
12 changes: 5 additions & 7 deletions arch/arm/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,16 +796,18 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)

/*
* 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,
struct pt_regs *regs)
{
int ret = 0;
u32 dscr;

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

if (interrupts_enabled(regs))
local_irq_enable();

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

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

return ret;
Expand Down
3 changes: 3 additions & 0 deletions arch/arm/mm/alignment.c
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
int isize = 4;
int thumb2_32b = 0;

if (interrupts_enabled(regs))
local_irq_enable();

instrptr = instruction_pointer(regs);

fs = get_fs();
Expand Down
4 changes: 4 additions & 0 deletions arch/arm/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
tsk = current;
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
* context, we must not take the fault..
Expand Down

0 comments on commit 02fe284

Please sign in to comment.