From 02fe2845d6a837ab02f0738f6cf4591a02cc88d4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jun 2011 11:44:06 +0100 Subject: [PATCH] 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 Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 43 +++++++++++++++------------------ arch/arm/kernel/entry-header.S | 19 --------------- arch/arm/kernel/hw_breakpoint.c | 12 ++++----- arch/arm/mm/alignment.c | 3 +++ arch/arm/mm/fault.c | 4 +++ 5 files changed, 31 insertions(+), 50 deletions(-) diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index d644d0240ad3..c46bafa2f6dc 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -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 ) diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 051166c2a932..4d6ad8348e89 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -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. diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 87acc25d7a3e..a927ca1f5566 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -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; diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 724ba3bce72c..be7c638b648b 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -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(); diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index bc0e1d88fd3b..20e5d5120609 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -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..