diff options
author | Andi Kleen <andi@firstfloor.org> | 2008-05-05 06:36:38 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-05-12 15:28:06 -0400 |
commit | 04b361abfdc522239e3a071f3afdebf5787d9f03 (patch) | |
tree | a98dbb398220ded0fa2bbc2a147d0edec7ec19f3 /arch/x86/kernel/irq_32.c | |
parent | ce17833183bf0a08ce3d174a2088eff0a06f2080 (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.c | 49 |
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; | |||
61 | static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; | 61 | static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; |
62 | #endif | 62 | #endif |
63 | 63 | ||
64 | static void stack_overflow(void) | ||
65 | { | ||
66 | printk("low stack detected by irq handler\n"); | ||
67 | dump_stack(); | ||
68 | } | ||
69 | |||
70 | static 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); |