天天看點

linux驅動程式運作優先級,如何調整Linux核心啟動中的驅動初始化順序(late_initcall和module_init)...

在init.h 中有如下定義

#define pure_initcall(fn)  __define_initcall("0",fn,1)

#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)

#define module_init(x) __initcall(x);

#define __initcall(fn) device_initcall(fn)

所有的__init函數在區段.init.text區段中,同時還在.initcall.init中還儲存了一份函數指針,

在初始化時核心會通過這些函數指針調用這些__init函數指針,

并在整個初始化完成後,釋放整個init區段(包括.init.text,.initcall.init等)。

這些函數在核心初始化過程中的調用順序隻和這裡的函數指針的順序有關

中所述的這些函數本身在.init.text區段中的順序無關。

在2.6核心中,initcall.init區段又分成7個子區段

不同的區段,調用的順序不一樣,數字越小的優先級越高。

也就是說 late_initcall 還要在 module_init的後面。

具體添加一個新的優先級的步驟如下:

1.定義新的優先級include\linux\init.h中:

#define pure_initcall(fn)__define_initcall("0",fn,1)

#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)

#if 1

#define prev_device_initcall(fn)__define_initcall("6",fn,6)

#define prev_device_initcall_sync(fn) __define_initcall("6s",fn,6s)

#define device_initcall(fn)__define_initcall("7",fn,7)

#define device_initcall_sync(fn) __define_initcall("7s",fn,7s)

#define late_initcall(fn)__define_initcall("8",fn,8)

#define late_initcall_sync(fn)__define_initcall("8s",fn,8s)

#else

#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)

#endif

做到這裡,本以為可以了,但是編譯後,在system.map中,發現之前優先級為7的那幾個函數,被放到system.map最後了,而不是預想的,在優先級7之後,在

c001997c T __con_initcall_start

c001997c t __initcall_con_init

c001997c T __initcall_end

之前。最後,發現時沒有把對應的連結檔案中的宏加進去:

include\asm-generic\vmlinux.lds.h

#if 1

#define INITCALLS\

*(.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)\

*(.initcall8.init)\

*(.initcall8s.init)

#else

#define INITCALLS\

*(.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)

#endif

最後,再重新編譯,就可以實作我們要的,和afe相關的驅動初始化,都在網卡enc28j60_init之前了。也就可以在網卡裡面讀晶片ID了。當然,對應編譯生成的system.map檔案中,對應的通過module_init定義的驅動,優先級也都變成7了。而late_initcall對應優先級8了。注:目前開發闆arm的闆子,是以,對應的load 腳本在:linux-2.6.28.4\arch\arm\kernel\vmlinux.lds看起來,應該是這個檔案:linux-2.6.28.4\arch\arm\kernel\vmlinux.lds.S生成上面那個腳本的。vmlinux.lds中的這一行:

__initcall_start = .;

*(.initcallearly.init) __early_initcall_end = .; *(.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)

就是将之前那些對應的init類型的函數,展開,放到這對應的位置。