Linux内核模块静态加载的顺序

内核模块静态加载的顺序

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的前面。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章