android底层驱动学习之 module_init的内核调用顺序
来源:互联网 发布:查看所有node版本号 编辑:程序博客网 时间:2024/06/13 04:57
1.一个驱动开始总有一 个init函数,那是怎么样实现的呢?-----基于将模块编译进内核方式的
可以看到在每个驱动都有module_init(要init的函数指针即函数名),在我focaltech_core.c是这样的:
module_init(fts_ts_init);2.追code可以看到以下流程:
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn------------------------这个还不是很懂,先放放,有空再研究
最终我们看到的是module_init的真身,__define_initcall(level,fn,id),仔细推敲这个真身,知道这是个宏,它把传给module_init的函数名组装成以__initcall为前缀的、以6为后缀的函数名,并把这个函数定义到代码段.initcall6.init里面。
3.那.initcall6.init这个是什么鸟呢,发现在字符串的文件vmlinux.lds.h存在以下定义:
#define INITCALLS\
*(.initcallearly.init)\
VMLINUX_SYMBOL(__early_initcall_end) = .;\
*(.initcall0.init)\
*(.initcall0s.init)\
*(.initcall1.init)\
*(.initcall1s.init)\
*(.initcall2.init)\
*(.initcall2s.init)\
*(.initcall3.init)\
*(.initcall3s.init)\
*(.initcall4.init)\
*(.initcall4s.init)\
*(.initcall5.init)\
*(.initcall5s.init)\
*(.initcallrootfs.init)\
*(.initcall6.init)\
*(.initcall6s.init)\
*(.initcall7.init)\
*(.initcall7s.init)
现在看到了.initcall6.init,这个东西相当于一个代码存储区,将驱动的init要执行的函数代码存在这里。
4.那接下来是不是应该来看看内核初始化流程,这样才能知道这段代码什么时候调用:
内核启动流程如下所示
在init/main.c里面,start_kernel----rest_init----- kernel_init---- do_basic_setup---- do_initcalls----有如下代码段:
static void __init do_initcalls(void)
{
initcall_t *fn;
for (fn = __early_initcall_end; fn < __initcall_end; fn++)
do_one_initcall(*fn);
}
在上述代码中,__early_initcall_end,__initcall_end在INITCALLS内定义,见下,他们代表的是一些初始化函数的指针数组起始与结束地址,执行函数do_initcalls时,包含在这各指针数组里面的函数顺序的被调用以执行一些必要的初始化工作。至此,明白的各initcall的执行时刻了吧。
在vmlinux.lds.S里面
__initcall_start = .;
INITCALLS
__initcall_end = .;
__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;
__security_initcall_start = .;
*(.security_initcall.init)
__security_initcall_end = .;
INITCALLS在__initcall_start = .与__initcall_end = .之间,表示INITCALLS宏内涵的相关段代码顺序存放在这里,module_init所代表段的镶嵌
5.以上是对于模块编译进内核的,如果通过insmod的方式呢?
insmod 是靠一个在kernel/module.c里定义的系统调用来实现的。
1. 此系统调用(sys_init_module )分配内核存储空间(kernel memory)给相关的模块,这个内存分配动作是由vmalloc完成;
2. 然后将该模块内容拷贝到这块存储空间里;
3. 接着声明内核引用该模块;
4. 呼叫该模块的初始化涵数
这样,一个插入模块的过程就完成了。
该函数准确应该是在 Linux/kernel/module.c里, 但是在里面你不会找到sys_init_module这个函数,因为这个函数是通过一个宏来实现的,
> /* This is where the real work happens */
> SYSCALL_DEFINE3(init_module, void __user *, umod,
> unsigned long, len, const char __user *, uargs)
这个宏就代表了sys_init_module这个函数。
请看SYSCALL_DEFINE3的定义有这么一句if (mod->init != NULL)
ret =do_one_initcall(mod->init);
是不是看到和上面类似的了,对,这个函数do_one_initcall在之前do_initcalls是有调用的。
至此应该明白了module_init的实现过程了。
- android底层驱动学习之 module_init的内核调用顺序
- module_init的内核调用顺序
- module_init的内核调用顺序
- module_init的内核调用顺序
- 内核驱动之module_init
- module_init的调用顺序
- android底层驱动学习之如何通过debugfs创建文件的方式来调试内核信息
- android底层驱动学习之内核信息的输出以及控制方式
- android底层驱动学习之从应用程序如何到底层driver的调用
- android底层驱动学习之linux输入子系统的理解
- android底层驱动学习之log的输出
- linux内核驱动 之 module_init解析 (上)
- linux内核驱动 之 module_init解析 (上)
- 驱动之module_init/module_exit
- 驱动之module_init/module_exit
- 驱动之module_init/module_exit
- 驱动之module_init/module_exit
- 驱动之module_init/module_exit
- Java中的几种排序方法
- solrj优化的问题(filtercache)
- 《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.7)
- https证书
- JSONP跨域原理
- android底层驱动学习之 module_init的内核调用顺序
- 生活语录
- 线索二叉树的建立和遍历
- 【hadoop】大规模中文网站聚类kmeans的mapreduce实现(上)
- python 划分数据集为训练集和测试集
- SystemInfo.deviceUniqueIdentifier
- Android个人学习小结2016.11
- 矩阵填数
- iOS之navigation bar 显示错乱问题