Chinaunix首页 | 论坛 | 博客
  • 博客访问: 189785
  • 博文数量: 76
  • 博客积分: 2510
  • 博客等级: 少校
  • 技术积分: 831
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-31 00:52
文章分类

全部博文(76)

文章存档

2010年(58)

2009年(18)

我的朋友

分类:

2010-03-27 13:40:38


内核栈


如果thread_info结构的大小为4KB时,当前进程的内核栈将被用于所有类型的内核控制路径,包括异常,硬软中断和如tasklet等可延迟的函数

如果thread_info结构的大小为4KB时,内核将使用三种类型的内核栈:
异常栈
硬中断请求栈
软中断请求栈



F:\workspace\linux-2.6.27.45\linux-2.6.27.45\arch\x86\kernel\irq_32.c

#ifdef CONFIG_4KSTACKS
/*
 * per-CPU IRQ handling contexts (thread information and stack)
 */

union irq_ctx {
    struct thread_info tinfo;
    u32 stack[THREAD_SIZE/sizeof(u32)];
};

static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;

static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;

static void call_on_stack(void *func, void *stack)
{
    asm volatile("xchgl    %%ebx,%%esp    \n"
         "call    *%%edi        \n"
         "movl    %%ebx,%%esp    \n"
         : "=b" (stack)
         : "0" (stack),
         "D"(func)
         : "memory", "cc", "edx", "ecx", "eax");
}

static inline int
execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
{
    union irq_ctx *curctx, *irqctx;
    u32 *isp, arg1, arg2;

    curctx = (union irq_ctx *) current_thread_info();
    irqctx = hardirq_ctx[smp_processor_id()];

    /*
     * this is where we switch to the IRQ stack. However, if we are
     * already using the IRQ stack (because we interrupted a hardirq
     * handler) we can't do that and just have to keep using the
     * current stack (which is the irq stack already after all)
     */

    if (unlikely(curctx == irqctx))
        return 0;

    /* build the stack frame on the IRQ stack */
    isp = (u32 *) ((char*)irqctx + sizeof(*irqctx));
    irqctx->tinfo.task = curctx->tinfo.task;
    irqctx->tinfo.previous_esp = current_stack_pointer;

    /*
     * Copy the softirq bits in preempt_count so that the
     * softirq checks work in the hardirq context.
     */

    irqctx->tinfo.preempt_count =
        (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
        (curctx->tinfo.preempt_count & SOFTIRQ_MASK);

    if (unlikely(overflow))
        call_on_stack(print_stack_overflow, isp);

    asm volatile("xchgl    %%ebx,%%esp    \n"
         "call    *%%edi        \n"
         "movl    %%ebx,%%esp    \n"
         : "=a" (arg1), "=d" (arg2), "=b" (isp)
         : "0" (irq), "1" (desc), "2" (isp),
            "D" (desc->handle_irq)
         : "memory", "cc", "ecx");
    return 1;
}

/*
 * allocate per-cpu stacks for hardirq and for softirq processing
 */

void __cpuinit irq_ctx_init(int cpu)
{
    union irq_ctx *irqctx;

    if (hardirq_ctx[cpu])
        return;

    irqctx = (union irq_ctx*) &hardirq_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);

    hardirq_ctx[cpu] = irqctx;

    irqctx = (union irq_ctx*) &softirq_stack[cpu*THREAD_SIZE];
    irqctx->tinfo.task        = NULL;
    irqctx->tinfo.exec_domain    = NULL;
    irqctx->tinfo.cpu        = cpu;
    irqctx->tinfo.preempt_count    = 0;
    irqctx->tinfo.addr_limit    = MAKE_MM_SEG(0);

    softirq_ctx[cpu] = irqctx;

    printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n",
     cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
}

void irq_ctx_exit(int cpu)
{
    hardirq_ctx[cpu] = NULL;
}

asmlinkage void do_softirq(void)
{
    unsigned long flags;
    struct thread_info *curctx;
    union irq_ctx *irqctx;
    u32 *isp;

    if (in_interrupt())
        return;

    local_irq_save(flags);

    if (local_softirq_pending()) {
        curctx = current_thread_info();
        irqctx = softirq_ctx[smp_processor_id()];
        irqctx->tinfo.task = curctx->task;
        irqctx->tinfo.previous_esp = current_stack_pointer;

        /* build the stack frame on the softirq stack */
        isp = (u32*) ((char*)irqctx + sizeof(*irqctx));

        call_on_stack(__do_softirq, isp);
        /*
         * Shouldnt happen, we returned above if in_interrupt():
         */

        WARN_ON_ONCE(softirq_count());
    }

    local_irq_restore(flags);
}

#else
static inline int
execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) { return 0; }
#endif



内核栈大小设置
F:\workspace\linux-2.6.27.45\linux-2.6.27.45\include\asm-x86\page_32.h

#ifdef CONFIG_4KSTACKS
#define THREAD_ORDER    0
#else
#define THREAD_ORDER    1
#endif
#define THREAD_SIZE     (PAGE_SIZE << THREAD_ORDER)



进程内核栈
F:\workspace\linux-2.6.27.45\linux-2.6.27.45\include\linux\sched.h

union thread_union {
    struct thread_info thread_info;
    unsigned long stack[THREAD_SIZE/sizeof(long)];
};


阅读(786) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~