LINUX核心中的xx_initcall初始化標號
田海立@CSDN 2011-07-02
LINUX核心中有很多的初始化指示標誌postcore_initcall(), arch_initcall(), subsys_initcall(), device_initcall(), etc. 這些起什麼作用呢。查閱原始碼(android goldfish-2.6.29)並搜尋網上相關文章,對此做一總結。 初始化標號
先看這些宏的定義(定義在檔案include/linux/init.h中) [cpp] view plain copy #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)
__define_initcall
這些宏都用到了__define_initcall(),再看看它的定義(同樣定義在檔案include/linux/init.h中) [cpp] view plain copy #define __define_initcall(level,fn,id) \ static initcall_t __initcall_##fn##id __used \ __attribute__((__section__(".initcall" level ".init"))) = fn
這其中initcall_t是函數指標,原型如下, [cpp] view plain copy typedef int (*initcall_t)(void);
而屬性 __attribute__((__section__())) 則表示把對象放在一個這個由括弧中的名稱所指代的section中。
所以__define_initcall的含義是:
1) 聲明一個名稱為__initcall_##fn的函數指標;
2) 將這個函數指標初始化為fn;
3) 編譯的時候需要把這個函數指標變數放置到名稱為 ".initcall" level ".init"的section中。
3. 放置.initcall.init SECTION
明確了__define_initcall的含義,就知道了是分別將這些初始化標號修飾的函數指標放到各自的section中的。
SECTION“.initcall”level”.init”被放入INITCALLS(include/asm-generic/vmlinux.lds.h) [cpp] view plain copy #define INITCALLS \ *(.initcallearly.init) \ VMLINUX_SYMBOL(__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)
__initcall_start和__initcall_end以及INITCALLS中定義的SECTION都是在arch/xxx/kernel/vmlinux.lds.S中放在.init段的。 [plain] view plain copy SECTIONS { .init : { __initcall_start = .; INITCALLS __initcall_end = .; } }
4. 初始化.initcallxx.init裡的函數
而這些SECTION裡的函數在初始化時被順序執行(init核心線程->do_basic_setup()[main.c#778]->do_initcalls())。
程式(init/main.c檔案do_initcalls()函數)如下,do_initcalls()把.initcallXX.init中的函數按順序都執行一遍。 [cpp] view plain copy for (call = __early_initcall_end; call < __initcall_end; call++) do_one_initcall(*call);
*************************** 本文完 *****************************