aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-06-25 06:44:06 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-07-02 05:56:00 -0400
commit02fe2845d6a837ab02f0738f6cf4591a02cc88d4 (patch)
treee50d06a1ab73a2735dd145edde458463b1da4a37 /arch
parent8b4186160b7894ca4583f702a562856d5d9e9118 (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kernel/entry-armv.S43
-rw-r--r--arch/arm/kernel/entry-header.S19
-rw-r--r--arch/arm/kernel/hw_breakpoint.c12
-rw-r--r--arch/arm/mm/alignment.c3
-rw-r--r--arch/arm/mm/fault.c4
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)
185__dabt_svc: 185__dabt_svc:
186 svc_entry 186 svc_entry
187 187
188 @ 188#ifdef CONFIG_TRACE_IRQFLAGS
189 @ get ready to re-enable interrupts if appropriate 189 bl trace_hardirqs_off
190 @ 190#endif
191 mrs r9, cpsr
192 tst r5, #PSR_I_BIT
193 biceq r9, r9, #PSR_I_BIT
194 191
195 dabt_helper 192 dabt_helper
196 193
197 @ 194 @
198 @ set desired IRQ state, then call main handler 195 @ call main handler
199 @ 196 @
200 debug_entry r1
201 msr cpsr_c, r9
202 mov r2, sp 197 mov r2, sp
203 bl do_DataAbort 198 bl do_DataAbort
204 199
@@ -211,6 +206,12 @@ __dabt_svc:
211 @ restore SPSR and restart the instruction 206 @ restore SPSR and restart the instruction
212 @ 207 @
213 ldr r5, [sp, #S_PSR] 208 ldr r5, [sp, #S_PSR]
209#ifdef CONFIG_TRACE_IRQFLAGS
210 tst r5, #PSR_I_BIT
211 bleq trace_hardirqs_on
212 tst r5, #PSR_I_BIT
213 blne trace_hardirqs_off
214#endif
214 svc_exit r5 @ return from exception 215 svc_exit r5 @ return from exception
215 UNWIND(.fnend ) 216 UNWIND(.fnend )
216ENDPROC(__dabt_svc) 217ENDPROC(__dabt_svc)
@@ -307,16 +308,11 @@ ENDPROC(__und_svc)
307__pabt_svc: 308__pabt_svc:
308 svc_entry 309 svc_entry
309 310
310 @ 311#ifdef CONFIG_TRACE_IRQFLAGS
311 @ re-enable interrupts if appropriate 312 bl trace_hardirqs_off
312 @ 313#endif
313 mrs r9, cpsr
314 tst r5, #PSR_I_BIT
315 biceq r9, r9, #PSR_I_BIT
316 314
317 pabt_helper 315 pabt_helper
318 debug_entry r1
319 msr cpsr_c, r9 @ Maybe enable interrupts
320 mov r2, sp @ regs 316 mov r2, sp @ regs
321 bl do_PrefetchAbort @ call abort handler 317 bl do_PrefetchAbort @ call abort handler
322 318
@@ -329,6 +325,12 @@ __pabt_svc:
329 @ restore SPSR and restart the instruction 325 @ restore SPSR and restart the instruction
330 @ 326 @
331 ldr r5, [sp, #S_PSR] 327 ldr r5, [sp, #S_PSR]
328#ifdef CONFIG_TRACE_IRQFLAGS
329 tst r5, #PSR_I_BIT
330 bleq trace_hardirqs_on
331 tst r5, #PSR_I_BIT
332 blne trace_hardirqs_off
333#endif
332 svc_exit r5 @ return from exception 334 svc_exit r5 @ return from exception
333 UNWIND(.fnend ) 335 UNWIND(.fnend )
334ENDPROC(__pabt_svc) 336ENDPROC(__pabt_svc)
@@ -412,11 +414,6 @@ __dabt_usr:
412 kuser_cmpxchg_check 414 kuser_cmpxchg_check
413 dabt_helper 415 dabt_helper
414 416
415 @
416 @ IRQs on, then call the main handler
417 @
418 debug_entry r1
419 enable_irq
420 mov r2, sp 417 mov r2, sp
421 adr lr, BSYM(ret_from_exception) 418 adr lr, BSYM(ret_from_exception)
422 b do_DataAbort 419 b do_DataAbort
@@ -663,8 +660,6 @@ ENDPROC(__und_usr_unknown)
663__pabt_usr: 660__pabt_usr:
664 usr_entry 661 usr_entry
665 pabt_helper 662 pabt_helper
666 debug_entry r1
667 enable_irq @ Enable interrupts
668 mov r2, sp @ regs 663 mov r2, sp @ regs
669 bl do_PrefetchAbort @ call abort handler 664 bl do_PrefetchAbort @ call abort handler
670 UNWIND(.fnend ) 665 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 @@
165 .endm 165 .endm
166#endif /* !CONFIG_THUMB2_KERNEL */ 166#endif /* !CONFIG_THUMB2_KERNEL */
167 167
168 @
169 @ Debug exceptions are taken as prefetch or data aborts.
170 @ We must disable preemption during the handler so that
171 @ we can access the debug registers safely.
172 @
173 .macro debug_entry, fsr
174#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT)
175 ldr r4, =0x40f @ mask out fsr.fs
176 and r5, r4, \fsr
177 cmp r5, #2 @ debug exception
178 bne 1f
179 get_thread_info r10
180 ldr r6, [r10, #TI_PREEMPT] @ get preempt count
181 add r11, r6, #1 @ increment it
182 str r11, [r10, #TI_PREEMPT]
1831:
184#endif
185 .endm
186
187/* 168/*
188 * These are the registers used in the syscall handler, and allow us to 169 * These are the registers used in the syscall handler, and allow us to
189 * have in theory up to 7 arguments to a function - r0 to r6. 170 * 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:
796 796
797/* 797/*
798 * Called from either the Data Abort Handler [watchpoint] or the 798 * Called from either the Data Abort Handler [watchpoint] or the
799 * Prefetch Abort Handler [breakpoint] with preemption disabled. 799 * Prefetch Abort Handler [breakpoint] with interrupts disabled.
800 */ 800 */
801static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, 801static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
802 struct pt_regs *regs) 802 struct pt_regs *regs)
@@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
804 int ret = 0; 804 int ret = 0;
805 u32 dscr; 805 u32 dscr;
806 806
807 /* We must be called with preemption disabled. */ 807 preempt_disable();
808 WARN_ON(preemptible()); 808
809 if (interrupts_enabled(regs))
810 local_irq_enable();
809 811
810 /* We only handle watchpoints and hardware breakpoints. */ 812 /* We only handle watchpoints and hardware breakpoints. */
811 ARM_DBG_READ(c1, 0, dscr); 813 ARM_DBG_READ(c1, 0, dscr);
@@ -824,10 +826,6 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
824 ret = 1; /* Unhandled fault. */ 826 ret = 1; /* Unhandled fault. */
825 } 827 }
826 828
827 /*
828 * Re-enable preemption after it was disabled in the
829 * low-level exception handling code.
830 */
831 preempt_enable(); 829 preempt_enable();
832 830
833 return ret; 831 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)
727 int isize = 4; 727 int isize = 4;
728 int thumb2_32b = 0; 728 int thumb2_32b = 0;
729 729
730 if (interrupts_enabled(regs))
731 local_irq_enable();
732
730 instrptr = instruction_pointer(regs); 733 instrptr = instruction_pointer(regs);
731 734
732 fs = get_fs(); 735 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)
285 tsk = current; 285 tsk = current;
286 mm = tsk->mm; 286 mm = tsk->mm;
287 287
288 /* Enable interrupts if they were enabled in the parent context. */
289 if (interrupts_enabled(regs))
290 local_irq_enable();
291
288 /* 292 /*
289 * If we're in an interrupt or have no user 293 * If we're in an interrupt or have no user
290 * context, we must not take the fault.. 294 * context, we must not take the fault..