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函数,从而初始化设备。
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函数,从而初始化设备。
相关文章推荐
- Linux netfilter 学习笔记 之十一 ip层netfilter的NAT模块初始化以及NAT原理
- Linux netfilter 学习笔记 之十一 ip层netfilter的NAT模块初始化以及NAT原理
- Linux 路由 学习笔记 之五 策略规则相关的数据结构以及ipv4策略规则的初始化
- Linux netfilter 学习笔记 之十一 ip层netfilter的NAT模块初始化以及NAT原理
- [学习指导] linux 启动过程以及 /etc/rc.d/init.d/目录的一点理解
- 菜鸟学习linux笔记与练习-----第一天。一些初级命令以及基本用户管理
- 7,Linux学习笔记--Linux引导流程解析
- 【linux学习笔记之一】linux系统目录结构以及常用系统命令
- Linux 学习笔记_5_Linux引导流程解析_1
- [linux内存]伙伴系统学习笔记(二)--内存系统初始化
- python cookbook第三版学习笔记四:文本以及字符串令牌解析
- Linux netfilter 学习笔记 之八 ip层netfilter的连接跟踪模块初始化
- Linux 学习笔记 (一)在VMware 中安装 Ubtuntu 以及 VMware tools
- Zigbee系列 学习笔记三(初始化程序解析)
- 学习Linux-4.12内核网路协议栈(1.4)——协议栈的初始化(proto_init)
- Linux中__init、__devinit等初始化宏解析和入口函数
- 转自IBM学习 浅析 Linux 初始化 init 系统,第 3 部分 Systemd
- Linux学习笔记 --- Centos7下查看CPU个数以及核数
- 【linux学习笔记之一】linux系统目录结构以及常用系统命令
- linux 内核学习----------模块(LKM:loading kernel module)