aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/irq_32.c
diff options
context:
space:
mode:
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);