内核模块静态加载的顺序
Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢?
Linux系统使用两种方式去加载系统中的模块:动态和静态。
静态加载:将所有模块的程序编译到Linux内核中,由do_initcall函数加载
核心进程(/init/main.c)kernel_init do_basic_setup() do_initcalls()该函数中会将在__initcall_start和__initcall_end之间定义的各个模块依次加载。
/arch/powerpc/kernel/vmlinux.lds文件,找到.initcall.init段:
.initcall.init : {
__initcall_start = .;
*(.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)
__initcall_end = .;
}
可以看出在这两个宏之间依次排列了14个等级的宏,由于这其中的宏是按先后顺序链接的,所以也就表示,这14个宏有优先级:0>1>1s>2>2s………>7>7s。
#define pure_initcall(fn) __define_initcall("0",fn,0)
#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
module_init(fbtft_driver_module_init);
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
//我们平时用的module_init在静态编译时就相当于device_initcall。
可以在最新的代码版本查看 device_initcall 等的定义
举个例子,在2.6.24的内核中:
gianfar_device使用的是arch_initcall,而gianfar_driver使用的是module_init,
因为arch_initcall的优先级大于module_init,所以gianfar设备驱动的device先于driver在总线上添加。
驱动模块之间的加载顺序:
查看System.map里的链接顺序,静态加载的模块命名为__initcall_xxx_init6:
c0949ba4 t __initcall_hid_init6
c0949ba8 t __initcall_fbtft_driver_module_init6
c0949bac t __initcall_flexfb_init6
c0949bb0 t __initcall_extcon_class_init6
这里链接的顺序,即是initcall list里调用的顺序。
而链接的顺序和Makefile里的顺序有关。
比如fbtft的Makefile中, fbtft 就排在 flexfb的前面。