--- linux/arch/i386/kernel/irq.c 2005-06-17 21:48:29.000000000 +0200 +++ linux-ssi/arch/i386/kernel/irq.c 2009-01-15 13:09:45.000000000 +0100 @@ -41,6 +41,23 @@ static union irq_ctx *hardirq_ctx[NR_CPUS]; static union irq_ctx *softirq_ctx[NR_CPUS]; +#ifdef CONFIG_DEBUG_STACKOVERFLOW +static union irq_ctx *overflow_ctx[NR_CPUS]; +#endif +#ifdef CONFIG_KDB +const char *kdba_irq_ctx_type(int cpu, struct thread_info *tinfo) +{ + if (tinfo == &hardirq_ctx[cpu]->tinfo) + return "hardirq_ctx"; + if (tinfo == &softirq_ctx[cpu]->tinfo) + return "softirq_ctx"; +#ifdef CONFIG_DEBUG_STACKOVERFLOW + if (tinfo == &overflow_ctx[cpu]->tinfo) + return "overflow_ctx"; +#endif + return NULL; +} +#endif /* CONFIG_KDB */ #endif /* @@ -53,6 +70,7 @@ /* high bits used in ret_from_ code */ int irq = regs->orig_eax & 0xff; #ifdef CONFIG_4KSTACKS + int arg1, arg2, ebx; union irq_ctx *curctx, *irqctx; u32 *isp; #endif @@ -66,9 +84,38 @@ __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (THREAD_SIZE - 1)); if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) { +#if CONFIG_4KSTACKS + /* use a special stack for overflow warning, + we want to avoid overflowing while telling + the user about the problem! */ + + curctx = (union irq_ctx *) current_thread_info(); + irqctx = overflow_ctx[smp_processor_id()]; + + if (curctx == irqctx) { + panic("double overflow"); + } + + /* build the stack frame on the oflow stack */ + isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); + irqctx->tinfo.task = curctx->tinfo.task; + irqctx->tinfo.previous_esp = current_stack_pointer; + + asm volatile( + " xchgl %%ebx,%%esp \n" + " call __overflow \n" + " movl %%ebx,%%esp \n" + : "=a" (arg1), "=d" (arg2), "=b" (ebx) + : "0" (irq), "1" (esp), "2" (isp) + : "memory", "cc", "ecx" + ); + + printk ("Back from overflow\n"); +#else printk("do_IRQ: stack overflow: %ld\n", esp - sizeof(struct thread_info)); dump_stack(); +#endif } } #endif @@ -109,6 +156,17 @@ return 1; } +#ifdef CONFIG_DEBUG_STACKOVERFLOW +#ifdef CONFIG_4KSTACKS +static fastcall void __overflow (int irq, long esp) +{ + printk("do_IRQ: stack overflow: %ld\n", + esp - sizeof(struct thread_info)); + dump_stack(); +} +#endif +#endif + #ifdef CONFIG_4KSTACKS /* @@ -121,6 +179,10 @@ static char hardirq_stack[NR_CPUS * THREAD_SIZE] __attribute__((__aligned__(THREAD_SIZE))); +#ifdef CONFIG_DEBUG_STACKOVERFLOW +static char overflow_stack[NR_CPUS * THREAD_SIZE] + __attribute__((__aligned__(THREAD_SIZE))); +#endif /* * allocate per-cpu stacks for hardirq and for softirq processing */ @@ -151,6 +213,20 @@ printk("CPU %u irqstacks, hard=%p soft=%p\n", cpu,hardirq_ctx[cpu],softirq_ctx[cpu]); +#ifdef CONFIG_DEBUG_STACKOVERFLOW + + irqctx = (union irq_ctx*) &overflow_stack[cpu*THREAD_SIZE]; + irqctx->tinfo.task = NULL; + irqctx->tinfo.exec_domain = NULL; + irqctx->tinfo.cpu = cpu; + irqctx->tinfo.preempt_count = HARDIRQ_OFFSET; /* ? */ + irqctx->tinfo.addr_limit = MAKE_MM_SEG(0); + + overflow_ctx[cpu] = irqctx; + + printk("CPU %u irqstacks, overflow=%p\n", + cpu,overflow_ctx[cpu]); +#endif } extern asmlinkage void __do_softirq(void);