linux subsys_initcall
宏定義__define_initcall(level,fn)對(duì)于內(nèi)核的初始化很重要,他指示編譯器在編譯的時(shí)候,將一系列初始化函數(shù)的起始地址值按照一定的順序放在一個(gè)section中。在內(nèi)核初始化段,do_initcalls() 將按順序從該section中以函數(shù)指針的形式取出這些函數(shù)的起始地址,來(lái)依次完成相應(yīng)的初始化。于內(nèi)核某些部分的初始化需要依賴(lài)于其他某些部分的初始化的完成,因此這個(gè)順序排列常常很重要?!?/span>
下面將從__define_initcall(level,fn) 宏定義的代碼分析入手,依次分析名稱(chēng)為initcall.init的section的結(jié)構(gòu),最后分析內(nèi)核初始化函數(shù)do_initcalls()是怎樣利用宏定義__define_initcall(level,fn)及其相關(guān)的衍生的7個(gè)宏宏定義,來(lái)實(shí)現(xiàn)內(nèi)核某些部分的順序初始化的。
1、分析 __define_initcall(level,fn) 宏定義
1) 這個(gè)宏的定義位于inlclude\linux\init.h中:
#define __define_initcall(level,fn)? ?\
static initcall_t __initcall_##fn??\
__attribute__((__section__(".initcall" level ".init"))) \
= fn
其中 initcall_t 是個(gè)函數(shù)指針類(lèi)型:
typedef int (*initcall_t)(void);
而屬性 __attribute__((__section__())) 則表示把對(duì)象放在一個(gè)這個(gè)由括號(hào)中的名稱(chēng)所指代的section中。所以這個(gè)宏定義的的含義是:1) 聲明一個(gè)名稱(chēng)為_(kāi)_initcall_##fn的函數(shù)指針(其中##表示替換連接,);2) 將這個(gè)函數(shù)指針初始化為fn;3) 編譯的時(shí)候需要把這個(gè)函數(shù)指針變量放置到名稱(chēng)為 ".initcall" level ".init"的section中(比如level="1",代表這個(gè)section的名稱(chēng)是 ".initcall1.init")。
2) 舉例:__define_initcall(6, pci_init)
上述宏調(diào)用的含義是:1) 聲明一個(gè)函數(shù)指針__initcall_pic_init = pci_init;且 2) 這個(gè)指針變量__initcall_pic_init 需要放置到名稱(chēng)為 .initcall6.init的section中( 其實(shí)質(zhì)就是將 這個(gè)函數(shù)pic_init的首地址放置到了這個(gè)section中)。
3) 這個(gè)宏一般并不直接使用,而是被定義成下述其他更簡(jiǎn)單的7個(gè)衍生宏
這些衍生宏宏的定義也位于 inlclude\linux\Init.h 中:
#define core_initcall(fn)? ?? ?? ?__define_initcall("1",fn)
#define postcore_initcall(fn)? ???__define_initcall("2",fn)
#define arch_initcall(fn)? ?? ?? ?__define_initcall("3",fn)
#define subsys_initcall(fn)? ?? ? __define_initcall("4",fn)
#define fs_initcall(fn)? ?? ?? ???__define_initcall("5",fn)
#define device_initcall(fn)? ?? ? __define_initcall("6",fn)
#define late_initcall(fn)? ?? ?? ?__define_initcall("7",fn)
因此通過(guò)宏 core_initcall() 來(lái)聲明的函數(shù)指針,將放置到名稱(chēng)為.initcall1.init的section中,而通過(guò)宏 postcore_initcall() 來(lái)聲明的函數(shù)指針,將放置到名稱(chēng)為.initcall2.init的section中,依次類(lèi)推。
4) 舉例:device_initcall(pci_init)
解釋同上 1-2)。
2、和初始化調(diào)用有關(guān)section--initcall.init被分成了7個(gè)子section
1) 他們依次是.initcall1.init、.initcall2.init、...、.initcall7.init
2) 按照先后順序依次排列
3) 他們的定義在文檔vmlinux.lds.S中
例如 對(duì)于i386+,在i386\kernel\vmlinux.lds.S中有:
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
而在makefile 中有
LDFLAGS_vmlinux += -T arch/$(ARCH)/kernel/vmlinux.lds.s
4) 在這7個(gè)section總的開(kāi)始位置被標(biāo)識(shí)為_(kāi)_initcall_start,而在結(jié)尾被標(biāo)識(shí)為_(kāi)_initcall_end。
3、 內(nèi)核初始化函數(shù)do_basic_setup(): do_initcalls() 將從.initcall.init中,也就是這7個(gè)section中依次取出任何的函數(shù)指針,并調(diào)用這些函數(shù)指針?biāo)赶虻暮瘮?shù),來(lái)完成內(nèi)核的一些相關(guān)的初始化。
這個(gè)函數(shù)的定義位于init\main.c中:
extern initcall_t __initcall_start, __initcall_end;
static void __init do_initcalls(void)
{
initcall_t *call;
....
for (call = &__initcall_start; call??
***********************************************************************
假如您希望某個(gè)初始化函數(shù)在內(nèi)核初始化階段就被調(diào)用,那么您就應(yīng)該使用宏__define_initcall(level,fn) 或 其7個(gè)衍生宏來(lái)把這個(gè)初始化函數(shù)fn的起始地址按照初始化的順序放置到相關(guān)的section 中。 內(nèi)核初始化時(shí)的do_initcalls()將從這個(gè)section中按順序找到這些函數(shù)來(lái)執(zhí)行。
總結(jié)
以上是生活随笔為你收集整理的linux subsys_initcall的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 微信小程序商城毕业设计毕设作品(5)开题
- 下一篇: DM6446 OSD