aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/irq_32.c
diff options
context:
space:
mode:
authorAndi Kleen <andi@firstfloor.org>2008-05-05 06:36:38 -0400
committerIngo Molnar <mingo@elte.hu>2008-05-12 15:28:06 -0400
commit04b361abfdc522239e3a071f3afdebf5787d9f03 (patch)
treea98dbb398220ded0fa2bbc2a147d0edec7ec19f3 /arch/x86/kernel/irq_32.c
parentce17833183bf0a08ce3d174a2088eff0a06f2080 (diff)
i386: Execute stack overflow warning on interrupt stack v2
Previously the reporting printk would run on the process stack, which risks overflow an already low stack. Instead execute it on the interrupt stack. This makes it more likely for the printk to make it actually out. It adds one not taken test/branch more to the interrupt path when stack overflow checking is enabled. We could avoid that by duplicating more code, but that seemed not worth it. Based on an observation by Eric Sandeen. v2: Fix warnings in some configs Signed-off-by: Andi Kleen <andi@firstfloor.org> Cc: mingo@elte.hu Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/irq_32.c')
-rw-r--r--arch/x86/kernel/irq_32.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 147352df28b9..3f76561da815 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -61,6 +61,26 @@ static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
61static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; 61static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
62#endif 62#endif
63 63
64static void stack_overflow(void)
65{
66 printk("low stack detected by irq handler\n");
67 dump_stack();
68}
69
70static inline void call_on_stack2(void *func, void *stack,
71 unsigned long arg1, unsigned long arg2)
72{
73 unsigned long bx;
74 asm volatile(
75 " xchgl %%ebx,%%esp \n"
76 " call *%%edi \n"
77 " movl %%ebx,%%esp \n"
78 : "=a" (arg1), "=d" (arg2), "=b" (bx)
79 : "0" (arg1), "1" (arg2), "2" (stack),
80 "D" (func)
81 : "memory", "cc", "ecx");
82}
83
64/* 84/*
65 * do_IRQ handles all normal device IRQ's (the special 85 * do_IRQ handles all normal device IRQ's (the special
66 * SMP cross-CPU interrupts have their own specific 86 * SMP cross-CPU interrupts have their own specific
@@ -76,6 +96,7 @@ unsigned int do_IRQ(struct pt_regs *regs)
76 union irq_ctx *curctx, *irqctx; 96 union irq_ctx *curctx, *irqctx;
77 u32 *isp; 97 u32 *isp;
78#endif 98#endif
99 int overflow = 0;
79 100
80 if (unlikely((unsigned)irq >= NR_IRQS)) { 101 if (unlikely((unsigned)irq >= NR_IRQS)) {
81 printk(KERN_EMERG "%s: cannot handle IRQ %d\n", 102 printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
@@ -92,11 +113,8 @@ unsigned int do_IRQ(struct pt_regs *regs)
92 113
93 __asm__ __volatile__("andl %%esp,%0" : 114 __asm__ __volatile__("andl %%esp,%0" :
94 "=r" (sp) : "0" (THREAD_SIZE - 1)); 115 "=r" (sp) : "0" (THREAD_SIZE - 1));
95 if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { 116 if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN)))
96 printk("do_IRQ: stack overflow: %ld\n", 117 overflow = 1;
97 sp - sizeof(struct thread_info));
98 dump_stack();
99 }
100 } 118 }
101#endif 119#endif
102 120
@@ -112,8 +130,6 @@ unsigned int do_IRQ(struct pt_regs *regs)
112 * current stack (which is the irq stack already after all) 130 * current stack (which is the irq stack already after all)
113 */ 131 */
114 if (curctx != irqctx) { 132 if (curctx != irqctx) {
115 int arg1, arg2, bx;
116
117 /* build the stack frame on the IRQ stack */ 133 /* build the stack frame on the IRQ stack */
118 isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); 134 isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
119 irqctx->tinfo.task = curctx->tinfo.task; 135 irqctx->tinfo.task = curctx->tinfo.task;
@@ -127,18 +143,19 @@ unsigned int do_IRQ(struct pt_regs *regs)
127 (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) | 143 (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
128 (curctx->tinfo.preempt_count & SOFTIRQ_MASK); 144 (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
129 145
130 asm volatile( 146 /* Execute warning on interrupt stack */
131 " xchgl %%ebx,%%esp \n" 147 if (unlikely(overflow))
132 " call *%%edi \n" 148 call_on_stack2(stack_overflow, isp, 0, 0);
133 " movl %%ebx,%%esp \n" 149
134 : "=a" (arg1), "=d" (arg2), "=b" (bx) 150 call_on_stack2(desc->handle_irq, isp, irq, (unsigned long)desc);
135 : "0" (irq), "1" (desc), "2" (isp),
136 "D" (desc->handle_irq)
137 : "memory", "cc", "ecx"
138 );
139 } else 151 } else
140#endif 152#endif
153 {
154 /* AK: Slightly bogus here */
155 if (overflow)
156 stack_overflow();
141 desc->handle_irq(irq, desc); 157 desc->handle_irq(irq, desc);
158 }
142 159
143 irq_exit(); 160 irq_exit();
144 set_irq_regs(old_regs); 161 set_irq_regs(old_regs);