@@ -416,11 +416,6 @@ ENDPROC(__irq_usr)
__und_usr:
usr_entry uaccess=0
- @ IRQs must be enabled before attempting to read the instruction from
- @ user space since that could cause a page/translation fault if the
- @ page table was modified by another CPU.
- enable_irq
-
tst r5, #PSR_T_BIT @ Thumb mode?
mov r1, #2 @ set insn size to 2 for Thumb
bne 0f @ handle as Thumb undef exception
@@ -847,6 +842,7 @@ vector_\name:
@
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
+ orr r0, r0, #PSR_I_BIT
msr spsr_cxsf, r0
@
@@ -17,8 +17,18 @@ noinstr asmlinkage void arm_und_handler(struct pt_regs *regs)
{
irqentry_state_t state = irqentry_enter(regs);
+ /*
+ * IRQs must be enabled before attempting to read the instruction from
+ * user space since that could cause a page/translation fault if the
+ * page table was modified by another CPU.
+ */
+
+ local_irq_enable();
+
do_undefinstr(regs);
+ local_irq_disable();
+
irqentry_exit(regs, state);
}
@@ -27,8 +37,12 @@ noinstr asmlinkage void arm_dabt_handler(unsigned long addr, unsigned int fsr,
{
irqentry_state_t state = irqentry_enter(regs);
+ local_irq_enable();
+
do_DataAbort(addr, fsr, regs);
+ local_irq_disable();
+
irqentry_exit(regs, state);
}
@@ -37,8 +51,12 @@ noinstr asmlinkage void arm_pabt_handler(unsigned long addr, unsigned int ifsr,
{
irqentry_state_t state = irqentry_enter(regs);
+ local_irq_enable();
+
do_PrefetchAbort(addr, ifsr, regs);
+ local_irq_disable();
+
irqentry_exit(regs, state);
}
@@ -515,7 +515,6 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason)
pr_crit("Bad mode in %s handler detected\n", handler[reason]);
die("Oops - bad mode", regs, 0);
- local_irq_disable();
panic("bad mode");
}
When dabt, pabt or und exceptions occur on ARM, ordinary interrupts (IRQs) can still happen. This isn't nice for the kernels context tracker, which expect (when using generic entry at least) that any nested IRQs happens between irqentry_enter() and irqentry_exit(), else it thinks something is fishy. This change blocks interrupts in the pabt, dabt, und and abt exception paths (all of them really) by unconditionally setting PSR_I_BIT in the early exception handler, until after context has been established with irqentry_enter() and before it is exited with irqentry_exit(). Inside the context-tracked exception handler we enable IRQs again, and once we leave it we disable them while exiting the exception. The local_irq_disable() in bad_mode() can be dropped since we are now disabling IRQs in the early assembly exception handler for all exceptions. This seems like not perfect: it seems an interrupt could still occur right before CPSR is set, or right after the userspace registers are restored in ret_from_exception. I would like to know if there is some way to set up these exceptions to inherently block IRQs when handled, until we explicitly allow them between irqentry_enter() and irqentry_exit() or if this is simply the best we can do on ARM for these exceptions to make the context tracker happy. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- arch/arm/kernel/entry-armv.S | 6 +----- arch/arm/kernel/entry.c | 18 ++++++++++++++++++ arch/arm/kernel/traps.c | 1 - 3 files changed, 19 insertions(+), 6 deletions(-)