Linux驱动中module_init宏的解析

来源:互联网 发布:约拿情结 知乎 编辑:程序博客网 时间:2024/05/22 01:40
内核include/linux/init.h中,module_init展开如下:
#define module_init(x) __initcall(x);
__initcall(x)展开如下:
#define __initcall(fn) device_initcall(fn)
device_initcall(fn)展开如下:
#define device_initcall(fn)        __define_initcall(fn, 6)
__define_initcall(fn, 6)展开:
#define __define_initcall(fn, id) \
    static initcall_t __initcall_##fn##id __used \
    __attribute__((__section__(".initcall" #id ".init"))) = fn

所以,module_init最终会被展开为:
#define module_init(x)   static initcall_t __initcall_x6 __used \
    __attribute__((__section__(".initcall6.init"))) = fn;

被module_init宏修饰的函数会被放在.initcall6.init段中,在arch/arm/kernel/vmlinux.lds.S中的init.data段中:
    .init.data : {
#ifndef CONFIG_XIP_KERNEL
        INIT_DATA
#endif
        INIT_SETUP(16)
        INIT_CALLS
        CON_INITCALL
        SECURITY_INITCALL
        INIT_RAM_FS
    }

而INIT_CALLS定义在include/asm-generic/vmlinux.lds.h中:
#define INIT_CALLS                            \
        VMLINUX_SYMBOL(__initcall_start) = .;            \
        *(.initcallearly.init)                    \
        INIT_CALLS_LEVEL(0)                    \
        INIT_CALLS_LEVEL(1)                    \
        INIT_CALLS_LEVEL(2)                    \
        INIT_CALLS_LEVEL(3)                    \
        INIT_CALLS_LEVEL(4)                    \
        INIT_CALLS_LEVEL(5)                    \
        INIT_CALLS_LEVEL(rootfs)                \
        INIT_CALLS_LEVEL(6)                    \
        INIT_CALLS_LEVEL(7)                    \
        VMLINUX_SYMBOL(__initcall_end) = .;

 INIT_CALLS_LEVEL(n)展开:
#define INIT_CALLS_LEVEL(level)                        \
        VMLINUX_SYMBOL(__initcall##level##_start) = .;        \
        *(.initcall##level##.init)                \
        *(.initcall##level##s.init)                \

所以,被module_init修饰的宏最终会被放在.init.data段中,这个段在内核初始化的时候会被调用。在init/main.c中通过调用do_initcalls函数来实现对module_init宏的调用:
int __init_or_module do_one_initcall(initcall_t fn)
{
    int count = preempt_count();
    int ret;
    char msgbuf[64];

    if (initcall_debug)
        ret = do_one_initcall_debug(fn);
    else
        ret = fn();

    msgbuf[0] = 0;

    if (preempt_count() != count) {
        sprintf(msgbuf, "preemption imbalance ");
        preempt_count_set(count);
    }
    if (irqs_disabled()) {
        strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
        local_irq_enable();
    }
    WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf);

    return ret;
}

static initcall_t *initcall_levels[] __initdata = {
    __initcall0_start,
    __initcall1_start,
    __initcall2_start,
    __initcall3_start,
    __initcall4_start,
    __initcall5_start,
    __initcall6_start,
    __initcall7_start,
    __initcall_end,
};

static void __init do_initcall_level(int level)
{
    extern const struct kernel_param __start___param[], __stop___param[];
    initcall_t *fn;

    strcpy(initcall_command_line, saved_command_line);
    parse_args(initcall_level_names[level],
           initcall_command_line, __start___param,
           __stop___param - __start___param,
           level, level,
           &repair_env_string);

    for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
        do_one_initcall(*fn);
}

static void __init do_initcalls(void)
{
    int level;

    for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
        do_initcall_level(level);
}
0 0
原创粉丝点击