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: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
8b4186160b
commit
02fe2845d6
@ -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
|
||||
|
||||
@ -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)
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
@ -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
|
||||
@ -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 )
|
||||
|
@ -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.
|
||||
|
@ -796,7 +796,7 @@ unlock:
|
||||
|
||||
/*
|
||||
* 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)
|
||||
@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
|
||||
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);
|
||||
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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..
|
||||
|
Loading…
Reference in New Issue
Block a user