您的位置:首页 > 运维架构 > Linux

Linux 学习笔记1 --- kernel初始化以及module_init(x)解析

2012-01-13 22:39 477 查看
粗略的看了下,kernel大致的初始化流程为:

setup.c kernel/\arch\parisc\kernel start_parisc // init arm

main .c kernel/init/ start_kernel // init

main .c kernel/init/ rest_init

main .c kernel/init/ kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

wait untill kernel_thread is ready

main .c kernel_init

main .c do_basic_setup

main .c do_initcalls

main .c do_one_initcall

在do_initcalls函数中,会有这样一个调用:

for (fn = __early_initcall_end; fn < __initcall_end; fn++)

do_one_initcall(*fn);

那么 __early_initcall_end和 __initcall_end是怎么来的呢?还得从 module_init(x)这个宏说起。

每个模块最后都会写上这个宏,来指明自己的初始化函数,是怎么样生效的呢?

打开 init.h ,看到如下定义:

#define __init __section(.init.text) __cold notrace // __init开头的函数均会被放置到init.txt,并且只会被调用一次

#define device_initcall(fn)
__define_initcall("6",fn,6) // device的level为6

#define __define_initcall(level,fn) static initcall_t __initcall_##fn __attribute_used__ __attribute__((__section__(".initcall" level ".init"))) = fn

#define module_init(x) __initcall(x);

#define __initcall(fn) device_initcall(fn)

由上面的宏定义关系不难得出module_init的真正表达式:

module_init(x) = static initcall_t __initcall_x6 __attribute_used__ __attribute__((__section__(".initcall" 6".init"))) = x

即定义了initcall_t类型的变量 _initcall_x 保存了X的地址,并 将其存放在 .initcall6.init,运行时由连接器vmlinux.lds 装入指定内存。

或许有些读者想到了,__early_initcall_end和 __initcall_end 存放的就是指定的内存地址,实现方法见vmlinux.lds.h:

#define INIT_CALLS \

VMLINUX_SYMBOL(__initcall_start) = .; \

INITCALLS \

VMLINUX_SYMBOL(__initcall_end) = .;

其含义时,是让__initcall_start指向代码节.initcall.init的节首,而__initcall_end指向.initcall.init的节尾.

而INITCALLS的首地址在上面被,__early_initcall_end保存,故在上述do_initcalls的循环中,vmlinux将可执行的init文件都装入指定的内存地址,按照初始化的优先级,依次调用各自模块的init函数,从而初始化设备。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐