linux内核驱动 之 module_init解析 (上)
来源:互联网 发布:土建计价软件 编辑:程序博客网 时间:2024/05/22 01:58
linux内核驱动 之 module_init解析 (上)
linux内核驱动 之 module_init解析 (上)
转自:
http://blog.csdn.net/richard_liujh/article/details/45669207
写过linux驱动的程序猿都知道module_init() 这个函数。那么我们来了解一下module_init这个函数的具体功能和执行过程
在kernel源码目录中找到include\linux\init.h文件
- <span style=“font-family:SimSun;font-size:14px;”>/**
- * module_init() - driver initialization entry point
- * @x: function to be run at kernel boot time or module insertion
- *
- * module_init() will either be called during do_initcalls() (if
- * builtin) or at module insertion time (if a module). There can only
- * be one per module.
- */
- #define module_init(x) __initcall(x);</span>
module_init(x)是一个宏定义,那么_initcall(x)又是什么呢?
- #define __initcall(fn) device_initcall(fn)
完整的宏定义如下:
__define_initcall:
- /* initcalls are now grouped by functionality into separate
- * subsections. Ordering inside the subsections is determined
- * by link order.
- * For backwards compatibility, initcall() puts the call in
- * the device init subsection.
- *
- * The `id’ arg to __define_initcall() is needed so that multiple initcalls
- * can point at the same handler without causing duplicate-symbol build errors.
- */
- #define __define_initcall(fn, id) \
- static initcall_t __initcall_##fn##id __used \
- __attribute__((__section__(”.initcall” #id “.init”))) = fn
initcalls:
- </pre><pre name=“code” class=“cpp”>/
- * A ”pure” initcall has no dependencies on anything else, and purely
- * initializes variables that couldn’t be statically initialized.
- *
- * This only exists for built-in code, not for modules.
- * Keep main.c:initcall_level_names[] in sync.
- */
- #define pure_initcall(fn) __define_initcall(fn, 0)
- #define core_initcall(fn) __define_initcall(fn, 1)
- #define core_initcall_sync(fn) __define_initcall(fn, 1s)
- #define postcore_initcall(fn) __define_initcall(fn, 2)
- #define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
- #define arch_initcall(fn) __define_initcall(fn, 3)
- #define arch_initcall_sync(fn) __define_initcall(fn, 3s)
- #define subsys_initcall(fn) __define_initcall(fn, 4)
- #define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
- #define fs_initcall(fn) __define_initcall(fn, 5)
- #define fs_initcall_sync(fn) __define_initcall(fn, 5s)
- #define rootfs_initcall(fn) __define_initcall(fn, rootfs)
- #define device_initcall(fn) __define_initcall(fn, 6)
- #define device_initcall_sync(fn) __define_initcall(fn, 6s)
- #define late_initcall(fn) __define_initcall(fn, 7)
- #define late_initcall_sync(fn) __define_initcall(fn, 7s)
- #define __initcall(fn) device_initcall(fn)
Note:下面用xxx_initcall来代表pure_initcall,core_initcall、core_initcall_sync … …
我们可以看到非常多的xxx_initcall宏函数定义,他们都是通过__define_initcall 实现的。在__define_initcall里面包含了两个参数,一个是fn,另一个则是id。那么,这么多的宏又有何用??
我们来到init\main.c文件中可以找到函数do_initcalls
- static void __init do_initcalls(void)
- {
- int level;
- for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
- do_initcall_level(level);
- }
所以,我们先来解释一下这些宏有什么用
还是从我们最熟悉的地方module_init(fn)开始说起,其中fn是module_init的参数,fn是一个函数指针(函数名)。
module_init(fn)—> __initcall(fn) —> device_initcall(fn) —> __define_initcall(fn, 6)
所以当我们写module_init(fn)最终我们可以简化成以下内容(假设module_init的参数为test_init)
module_init(test_init) —> __define_initcall(test_init, 6)
- #define __define_initcall(fn, id) \
- static initcall_t __initcall_##fn##id __used \
- __attribute__((__section__(”.initcall” #id “.init”))) = fn
简单补充:
符号作用举例
是不是看起来更加头疼,那么我们说简单一点。通过__attribute__(__section__)设置函数属性,也就是将test_init放在.initcall6.init段中。这个段在哪用?这就要涉及到链接脚本了。
大家可以到kernel目录arch中,根据自己的处理器平台找到对应的链接脚本。例如我现在的平台是君正m200(mips架构),可能大部分是arm架构。
在arch/mips/kernel/vmlinux.lds这个链接脚本里面有如下一段代码
- __init_begin = .;
- . = ALIGN(4096); .init.text : AT(ADDR(.init.text) - 0) { _sinittext = .; *(.init.text) *(.cpuinit.text) *(.meminit.text) _einittext = .; }
- .init.data : AT(ADDR(.init.data) - 0) { *(.init.data) *(.cpuinit.data) *(.meminit.data) *(.init.rodata) *(.cpuinit.rodata) *(.meminit.rodata) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .; . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .; __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .; __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .; . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info) }
- . = ALIGN(4);
- __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init)
.initcall0.init .initcall0s.init .initcall1.init .initcall1s.init …… .initcall7.init .initcall7s.init
上面的内容都出现在了链接脚本中,而0,0s,1,1s,2,2s …… 6,6s,7,7s 有没有觉得在哪里见过? 我们回顾一下initcalls里面的定义
- #define pure_initcall(fn) __define_initcall(fn, 0)
- #define core_initcall(fn) __define_initcall(fn, 1)
- #define core_initcall_sync(fn) __define_initcall(fn, 1s)
- #define postcore_initcall(fn) __define_initcall(fn, 2)
- #define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
- #define arch_initcall(fn) __define_initcall(fn, 3)
- #define arch_initcall_sync(fn) __define_initcall(fn, 3s)
- #define subsys_initcall(fn) __define_initcall(fn, 4)
- #define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
- #define fs_initcall(fn) __define_initcall(fn, 5)
- #define fs_initcall_sync(fn) __define_initcall(fn, 5s)
- #define rootfs_initcall(fn) __define_initcall(fn, rootfs)
- #define device_initcall(fn) __define_initcall(fn, 6)
- #define device_initcall_sync(fn) __define_initcall(fn, 6s)
- #define late_initcall(fn) __define_initcall(fn, 7)
- #define late_initcall_sync(fn) __define_initcall(fn, 7s)
在kernel启动过程中,会调用do_initcalls函数一次调用我们通过xxx_initcall注册的各种函数,优先级高的先执行。所以我们通过module_init注册的函数在kernel启动的时候会被顺序执行。
由于时间原因,只能把具体执行过程放在linux内核很吊之 module_init解析 (下)再分析了。
- dysh1985
- 2012-05-24 09:46
- 14338
-
Kernel启动时 驱动是如何加载的module_init,加载的次序如何;略见本文
Init.h中有相关initcall的启动次序,在system.map中可看出具体的__initcall指针的前后次序
- lijiuliang
- 2012-10-13 23:31
- 4329
-
Linux内核很吊之 module_init解析 (下)
转自: http://blog.csdn.net/richard_liujh/article/details/46758073忙了一段时间,终于有时间把inux内核很吊之 module_ini…- UranusC
- 2017-01-23 13:58
- 95
-
一步步将vim改造成C/C++开发环境(IDE)
我的vim IDE界面: 1、安装Vim和Vim基本插件首先安装好Vim和Vim的基本插件。这些使用apt-get安装即可:lingd@ubuntu:~/arm$sudo apt-…- yinjiabin
- 2012-12-04 10:21
- 7850
-
一步一步的打造好用的Vim(图解)
一步一步的打造好用的Vim(图解)作者:草帽的后花园——小懒虫 转载请注明:草帽的后花园 首先,创建这个文档,是一直都有的想法,有两个原因,一个是为了自己保存,…- backgarden_straw
- 2012-09-12 16:06
- 1108
-
Linux内核很吊之 module_init解析 (下)
分析module_init 的作用。和module_init注册函数过程,以及注册函数被执行的过程。- Richard_LiuJH
- 2015-07-04 22:00
- 1998
-
linux内核驱动中_IO, _IOR, _IOW, _IOWR 宏的用法与解析
在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值。cmd除了可区别数字外,还包含有助于处理的几种相应信息。 cmd的大小为 32位,共分 4 个…- yuyin86
- 2012-03-14 08:51
- 342
-
linux内核驱动中_IO, _IOR, _IOW, _IOWR 宏的用法与解析
在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值。cmd除了可区别数字外,还包含有助于处理的几种相应信息。 cmd的大小为 32位,共分 4 个…- cuijianzhongswust
- 2011-11-25 09:12
- 603
-
linux内核驱动中_IO, _IOR, _IOW, _IOWR 宏的用法与解析
在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值。cmd除了可区别数字外,还包含有助于处理的几种相应信息。 cmd的大小为 32位,共分 4 个…- lionfire
- 2011-07-28 17:41
- 831
-
LINUX内核驱动第三版
- 2013-11-20 16:06
- 986KB
- 下载
-
[zip文件] 国嵌—嵌入式LINUX内核驱动深入班
- 2014-04-13 11:56
- 27.65MB
- 下载
-
Linux内核模块分析(module_init宏)
我们在学习Linux驱动开发时,首先需要了解Linux的模块化机制(module),但是module并不仅仅用于支撑驱动的加载和卸载。一个最简单的模块例子如下:// filename: HelloWo…- luckydarcy
- 2016-05-17 03:25
- 674
-
嵌入式LINUX内核驱动进阶班实验手册_实验1.1
- 2011-03-12 12:07
- 6.00MB
- 下载
-
Linux内核驱动模块编程指南
- 2008-09-20 11:58
- 50KB
- 下载
-
linux内核段属性机制(以subsys_initcall和module_init为例)
linux内核段属性机制以subsys_initcall和module_init为例- TongxinV
- 2017-01-27 11:04
- 614
- 原创
- 1
- 粉丝
- 0
- 喜欢
- 0
- 码云
- 未开通
他的最新文章
更多文章- 数组指针和指针数组的区别
- 2017年提升之年
- Linux内核很吊之 module_init解析 (下)
在线课程
-
Presto服务治理与架构优化在京东的实践应用
讲师:王哲涵
-
【免费直播】Python最佳学习路线
讲师:韦玮
热门文章
- linux内核驱动 之 module_init解析 (上) 425
- Linux内核很吊之 module_init解析 (下) 95
- 2017年提升之年 59
- 数组指针和指针数组的区别 58
- linux内核驱动 之 module_init解析 (上)
- linux内核驱动 之 module_init解析 (上)
- linux驱动 之 module_init解析 (上)
- linux驱动 之 module_init解析 (上)
- 内核驱动之module_init
- Linux内核很吊之 module_init解析 (下)
- Linux内核很吊之 module_init解析 (下)
- Linux内核很吊之 module_init解析 (下)
- Linux内核很吊之 module_init解析 (下)
- Linux内核很吊之 module_init解析 (下)
- linux驱动 之 module_init解析 一
- Linux内核很吊之 module_init解析 二
- linux驱动模块 之 module_init()
- linux kernel驱动之module_init
- Linux驱动中module_init宏的解析
- linux内核驱动设备初始化执行过程(module_init执行过程)
- Linux内核模块分析(module_init宏)
- android底层驱动学习之 module_init的内核调用顺序
- 6.移动端事件--阻止冒泡
- myeclipse安装activiti插件
- 171014 数据库建模(mysql5.0)
- windows编译-spidermonkey
- 10.14 考试 T2 第k大区间
- linux内核驱动 之 module_init解析 (上)
- [LeetCode] 650. 2 Keys Keyboard
- Java开发练习2,类与对象
- 【bzoj 5055】膜法师(树状数组)
- 多源数据融合学习
- typedef的使用方法
- 为什么要使用代理模式
- Java 通过正则表达式实现简单xml文件解析
- Spring的三种注入方式