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

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