linux 内核 call,关于linux 内核中的initcall

本文详细介绍了Linux内核中__init函数的初始化流程及其在不同区段中的调用顺序。阐述了从2.4到2.6内核版本中initcall机制的变化,以及如何通过特定宏定义将函数安排在特定阶段执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

找了一个相对比较浅显易懂的,转了下来。

如下:

参考:http://blog.163.com/gpg119/blog/static/9153415320089824938513/

late_initcall

所有的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数指针,并在整个初始化完成后,释放整个init区段(包括.init.text,.initcall.init等)。

注意,这些函数在内核初始化过程中的调用顺序只和这里的函数指针的顺序有关,和1)中所述的这些函数本身在.init.text区段中的顺序无关。在2.4内核中,这些函数指针的顺序也是和链接的顺序有关的,是不确定的。在2.6内核中,initcall.init区段又分成7个子区段,分别是

.initcall1.init

.initcall2.init

.initcall3.init

.initcall4.init

.initcall5.init

.initcall6.init

.initcall7.init

当需要把函数fn放到.initcall1.init区段时,只要声明core_initcall(fn);即可。

其他的各个区段的定义方法分别是:

core_initcall(fn) --->.initcall1.init

postcore_initcall(fn) --->.initcall2.init

arch_initcall(fn) --->.initcall3.init

subsys_initcall(fn) --->.initcall4.init

fs_initcall(fn) --->.initcall5.init

device_initcall(fn) --->.initcall6.init

late_initcall(fn) --->.initcall7.init

而与2.4兼容的initcall(fn)则等价于device_initcall(fn)。各个子区段之间的顺序是确定的,即先调用.initcall1.init中的函数指针,再调用.initcall2.init中的函数指针,等等。而在每个子区段中的函数指针的顺序是和链接顺序相关的,是不确定的。

在内核中,不同的init函数被放在不同的子区段中,因此也就决定了它们的调用顺序。这样也就解决了一些init函数之间必须保证一定的调用顺序的问题。按照include/linux/init.h文件所写的,我在驱动里偿试了这样两种方式:

__define_initcall("7", fn);

late_initcall(fn);

都可以把我的驱动调整到最后调用。实际上上面两个是一回事:

#define late_initcall(fn) __define_initcall("7", fn)

linux 2.6中把initcall又分成了若干种类,主要用来区别不同的initcall的调用次序,由于initcall中的调用次序是随机的,所以不能保证某些重要的初始化先运行。

分成了以下几个initcall,按执行顺序先后排列:

pure_initcall:最先运行的,不依赖于任何其他初始化函数。

core_initcall

core_initcall_sync

postcore_initcall

postcore_initcall_sync

arch_initcall

arch_initcall_sync

subsys_initcall

subsys_initcall_sync

fs_initcall

fs_initcall_sync

rootfs_initcall

device_initcall

device_initcall_sync

late_initcall

late_initcall_sync

可以看一下些x86中pci初始化的代码,首先是pci_access_init,这个函数是arch_initcall的,然后是pci_legacy_init,这个函数是subsys_initcall的,然后是pcibios_irq_init,这个函数也是subsys_initcall的,然后是pcibios_assign_resources这个函数是fs_initcall的,最后才是pci_init,这个函数是device_initcall的,这样就把整个pci初始化过程分开了。

阅读(1935) | 评论(0) | 转发(7) |

<think>好的,我现在需要回答用户关于Linux内核中静态编译驱动加载顺序的问题。用户提到了System.map中的INIT_CALL段和一些引用,我得先理解这些资料。 首先,用户提供的引用中提到了static initcall_t和System.map中的INIT_CALL段。记得在内核初始化过程中,initcall机制负责调用不同级别的初始化函数。静态编译的驱动应该属于这些initcall的一部分。引用3中的例子显示驱动模块的初始化函数被命名为__initcall_xxx_init6,这里的数字6可能代表优先级。 接下来,我需要确定加载顺序的规则。根据Linux内核的文档,initcall有多个级别,比如early、core、postcore等,每个级别对应不同的优先级。数字越小,优先级越高,执行越早。例如,__initcall_init0是最早的,而__initcall_init7可能更晚。所以,在System.map里看到的_init6应该属于第6级,也就是较晚执行的级别。 然后,驱动模块的加载顺序取决于它们在各自初始化级别中的链接顺序。链接顺序由内核构建系统根据Makefile和Kconfig中的定义确定。如果多个驱动在同一个initcall级别,它们的初始化函数按链接顺序执行,也就是在System.map中出现的顺序。比如引用3中的例子,hid_init6在fbtft_driver_module_init6之前,所以hid驱动会先加载。 用户可能需要知道如何查看这些信息,所以需要指导他们查看System.map文件中的符号,或者使用sortextable工具来查看.initcall.init段的顺序。另外,编写驱动时可以通过module_init宏指定不同的优先级,比如使用device_initcall来将驱动放到第6级。 最后,生成相关问题时要涵盖initcall机制、修改加载顺序的方法、调试技巧以及动态与静态加载的区别。确保回答准确,并正确引用用户提供的资料。</think>### Linux内核静态编译驱动加载顺序规则解析 Linux内核中静态编译驱动的加载顺序由**initcall机制**和**链接顺序**共同决定,以下是具体实现原理和确认方法: 1. **initcall优先级机制** - 内核定义了7个初始化级别(从0到6),数字越小优先级越高: $$ \text{early} \rightarrow \text{core} \rightarrow \text{postcore} \rightarrow \text{arch} \rightarrow \text{subsys} \rightarrow \text{fs} \rightarrow \text{device} \rightarrow \text{late} $$ - 驱动初始化函数通过宏声明优先级,如: ```c module_init(func); // 默认device_initcall级别(6) device_initcall(func); // 明确指定级别6 ``` 2. **System.map确认方法**(引用[2][3]) - 在编译生成的System.map文件中搜索`__initcall`: ``` c0949ba4 t __initcall_hid_init6 c0949ba8 t __initcall_fbtft_driver_module_init6 ``` 这里`_init6`表示级别6,地址顺序`c0949ba4 < c0949ba8`表明`hid_init6`先于`fbtft`执行 3. **链接顺序决定因素** - 同级别驱动的加载顺序由内核构建系统的链接顺序决定 - 链接顺序取决于: * Makefile中obj-y的声明顺序 * Kconfig配置的依赖关系 * 文件在文件系统中的存储顺序(对未排序的filesystem) 4. **调试技巧** - 查看初始化顺序: ```bash sortextable vmlinux | grep __initcall | less ``` - 查看实际执行顺序: ```bash dmesg | grep "initcall " ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值