linux驱动中控制驱动的加载顺序.

主动控制驱动加载顺序.

编译进内核的驱动可以认为的调整驱动的加载顺序分为如下8个等级:

/*  
 * 一个“纯”的initcall不依赖于任何其他内容,它仅用于初始化那些无法静态初始化的变量。  
 *  
 * 这类initcall仅存在于内置代码中,不适用于模块。  
 * 请保持main.c中的initcall_level_names[]数组同步更新。  
 */
#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)

/*
 * 默认的优先级,使用module_init() 定义的驱动使用的这个优先级.
*/
#define __initcall(fn) device_initcall(fn)

如何使用这些加载顺序宏定义

通常我们使用module_init() 和 module_exit()  "函数" 定义驱动的注册和注销函数.其实module_init 也是一个宏定义:

module_init(drm_core_init);

/*  
 * module_init() - 驱动初始化入口点  
 * @x: 在内核启动时间或模块插入时运行的函数  
 *  
 * module_init() 将在 do_initcalls() 期间(如果是内建驱动)或模块插入时间(如果是模块)被调用。  
 * 每个模块只能有一个这样的入口点。  
 */
 #define module_init(x)	__initcall(x);

 #define __initcall(fn) device_initcall(fn)

结合上面的宏定义可知,默认的驱动注册有顺序是6.

如果定义其他初始化顺序只需要使用相应的宏定义声明驱动的注册和注销函数即可.

参考:

https://www.cnblogs.com/linhaostudy/p/9112264.html

<think>好的,用户想了解Linux内核驱动加载顺序。首先,我需要回忆一下Linux内核中驱动加载的基本机制。记得内核驱动加载顺序涉及到多个方面,比如编译方式、设备树、初始化级别等。可能需要从静态加载和动态加载两个方面来考虑。 静态编译进内核的驱动,它们的初始化函数是通过module_init宏定义的,这些函数会被链接到特定的初始化段中。内核启动时,会按照这些段的顺序来执行初始化函数。比如,arch_initcall、subsys_initcall、device_initcall等不同级别的初始化调用,这些决定了驱动加载顺序。每个级别内的驱动可能按链接顺序执行,但链接顺序可能受编译工具的影响,比如LD的链接脚本。 而动态加载的驱动,即通过insmod或modprobe加载的模块,它们的初始化函数是在模块插入时执行的,所以加载顺序取决于用户插入模块的顺序。不过,模块之间如果有依赖关系,modprobe会根据depmod生成的依赖关系来自动解决加载顺序。 另外,用户提到的引用中有提到initcall_debug和printk.time=y,这两个参数可以在启动时打印每个初始化函数的耗时和顺序,这对调试加载顺序很有帮助。引用2中的bootargs修改就是为了记录内核启动时各个模块的初始化时间,这样用户可以通过日志分析驱动加载顺序。 可能还需要考虑设备树(Device Tree)的影响,因为设备树中定义的设备节点会在内核初始化时被处理,这可能影响驱动的探测顺序。例如,某些总线上的设备会按照设备树中的顺序进行初始化,从而触发相应驱动的探测函数。 还有,驱动注册的机制,比如平台设备驱动、PCI驱动等,不同类型的驱动注册和匹配方式不同,可能会影响加载顺序。例如,平台驱动会在子系统初始化时注册,而PCI驱动可能在总线扫描时加载。 用户的问题可能涉及到如何控制和优化驱动加载顺序,特别是在系统启动时间优化或者解决驱动依赖问题时。需要解释清楚内核初始化的阶段,以及不同initcall级别的优先级,比如core_initcall比device_initcall更早执行。 另外,引用4提到了USB驱动的例子,lsmod可以查看已加载的模块,但动态模块的加载顺序由用户或系统服务控制,而静态部分则由内核初始化流程决定。可能需要提到内核的初始化阶段划分,以及如何通过修改驱动代码中的initcall宏来调整其加载顺序。 总结来说,回答需要分静态和动态两种情况,解释影响加载顺序的因素,如initcall级别、链接顺序、设备树、依赖关系等,并提到使用initcall_de调试的方法。同时结合用户提供的引用,特别是引用2中的启动参数设置,来说明如何实际获取加载顺序的信息。</think>### Linux内核驱动加载顺序解析 Linux内核驱动加载顺序由编译方式、初始化优先级和运行时依赖共同决定。以下是具体分析: #### 一、静态驱动加载顺序 1. **初始化优先级划分** 静态编译进内核的驱动通过`module_init`宏定义初始化函数,其优先级由**initcall级别**决定。内核定义了7个初始化级别(按执行顺序): $$core\_initcall \rightarrow postcore\_initcall \rightarrow arch\_initcall \rightarrow subsys\_initcall \rightarrow fs\_initcall \rightarrow device\_initcall \rightarrow late\_initcall$$ 每个级别的驱动按编译时的链接顺序执行[^2]。 2. **调试方法** 在启动参数中添加`initcall_debug`和`printk.time=y`,内核会打印所有初始化函数的耗时和顺序: ```bash # 修改bootargs示例 bootargs += "initcall_debug printk.time=y" [^2] ``` 输出日志格式类似: ``` [ 0.000001] calling init_mmio+0x0/0x1c @ 1 [ 0.000002] initcall init_mmio+0x0/0x1c returned 0 after 1 usecs ``` #### 二、动态模块加载顺序 1. **手动加载控制** 使用`insmod`或`modprobe`加载驱动时,顺序由用户显式指定: ```bash insmod driverA.ko # 先加载driverA insmod driverB.ko # 后加载driverB ``` 2. **依赖关系处理** `modprobe`会根据`/lib/modules/$(uname -r)/modules.dep`文件自动解决依赖: ```bash modprobe usbhid # 自动先加载hid和hid_generic模块[^4] ``` #### 三、其他影响因素 1. **设备树节点顺序** 设备树(`.dts`)中定义的设备节点按顺序初始化,例如: ```dts / { deviceA { ... }; // 先初始化 deviceB { ... }; // 后初始化 } ``` 2. **总线探测机制** PCI/USB等总线类型驱动加载顺序由总线枚举顺序决定,例如USB控制器初始化完成后才会加载USB设备驱动
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值