# 内核模块静态加载的顺序 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。 ~~~ 举个例子,在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的前面。