Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: introduce handle_IRQ() not to dump exception stack

On Mon, Jul 11, 2011 at 3:52 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:

...

> The __exception annotation on a function causes this to happen:
>
> [<c002406c>] (asm_do_IRQ+0x6c/0x8c) from [<c0024b84>]
> (__irq_svc+0x44/0xcc)
> Exception stack(0xc3897c78 to 0xc3897cc0)
> 7c60: 4022d320 4022e000
> 7c80: 08000075 00001000 c32273c0 c03ce1c0 c2b49b78 4022d000 c2b420b4 00000001
> 7ca0: 00000000 c3897cfc 00000000 c3897cc0 c00afc54 c002edd8 00000013 ffffffff
>
> Where that stack dump represents the pt_regs for the exception which
> happened. Any function found in while unwinding will cause this to
> be printed.
>
> If you insert a C function between the IRQ assembly and asm_do_IRQ,
> the
> dump you get from asm_do_IRQ will be the stack for your function,
> not
> the pt_regs. That makes the feature useless.
>

When __irq_svc - or any of the other exception handling assembly code -
calls the C code, the stack pointer will be pointing at the pt_regs
structure.

All the entry points into C code from the exception handling code are
marked with __exception or __exception_irq_enter to indicate that they
are one of the functions which has pt_regs above them.

Normally, when you've entered asm_do_IRQ() you will have this stack
layout (higher address towards top):

pt_regs
asm_do_IRQ frame

If you insert a C function between the exception assembly code and
asm_do_IRQ, you end up with this stack layout instead:

pt_regs
your function frame
asm_do_IRQ frame

This means when we unwind, we'll get to asm_do_IRQ, and rather than
dumping out the pt_regs, we'll dump out your functions stack frame
instead, because that's what is above the asm_do_IRQ stack frame
rather than the expected pt_regs structure.

The fix is to introduce handle_IRQ() for no exception stack dump, so
it can be called with MULTI_IRQ_HANDLER is selected and a C function
is between the assembly code and the actual IRQ handling code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Eric Miao <eric.y.miao@gmail.com>

authored by

Russell King - ARM Linux and committed by
Eric Miao
a4841e39 fe0d4220

+15 -5
+1
arch/arm/include/asm/irq.h
··· 23 23 extern void migrate_irqs(void); 24 24 25 25 extern void asm_do_IRQ(unsigned int, struct pt_regs *); 26 + void handle_IRQ(unsigned int, struct pt_regs *); 26 27 void init_IRQ(void); 27 28 28 29 #endif
+14 -5
arch/arm/kernel/irq.c
··· 67 67 } 68 68 69 69 /* 70 - * do_IRQ handles all hardware IRQ's. Decoded IRQs should not 71 - * come via this function. Instead, they should provide their 72 - * own 'handler' 70 + * handle_IRQ handles all hardware IRQ's. Decoded IRQs should 71 + * not come via this function. Instead, they should provide their 72 + * own 'handler'. Used by platform code implementing C-based 1st 73 + * level decoding. 73 74 */ 74 - asmlinkage void __exception_irq_entry 75 - asm_do_IRQ(unsigned int irq, struct pt_regs *regs) 75 + void handle_IRQ(unsigned int irq, struct pt_regs *regs) 76 76 { 77 77 struct pt_regs *old_regs = set_irq_regs(regs); 78 78 ··· 95 95 96 96 irq_exit(); 97 97 set_irq_regs(old_regs); 98 + } 99 + 100 + /* 101 + * asm_do_IRQ is the interface to be used from assembly code. 102 + */ 103 + asmlinkage void __exception_irq_entry 104 + asm_do_IRQ(unsigned int irq, struct pt_regs *regs) 105 + { 106 + handle_IRQ(irq, regs); 98 107 } 99 108 100 109 void set_irq_flags(unsigned int irq, unsigned int iflags)