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:
|
__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 )
|
||||||
|
@ -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.
|
||||||
|
@ -796,7 +796,7 @@ unlock:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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;
|
||||||
|
@ -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();
|
||||||
|
@ -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..
|
||||||
|
Loading…
Reference in New Issue
Block a user