__define_initcall,subsys_initcall

來源:互聯網
上載者:User

linux subsys_initcall 轉載 

宏定義__define_initcall(level,fn)對於核心的初始化很重要,他指示編譯器在編譯的時候,將一系列初始化函數的起始地址值按照一定的順序放在一個section中。在核心初始化段,do_initcalls() 將按順序從該section中以函數指標的形式取出這些函數的起始地址,來依次完成相應的初始化。於核心某些部分的初始化需要依賴於其他某些部分的初始化的完成,因此這個順序排列常常很重要。 
  下面將從__define_initcall(level,fn) 宏定義的程式碼分析入手,依次分析名稱為initcall.init的

section的結構,最後分析核心初始化函數do_initcalls()是怎樣利用宏定義__define_initcall(level,fn)

及其相關的衍生的7個宏宏定義,來實現核心某些部分的順序初始化的。

1、分析 __define_initcall(level,fn) 宏定義
1) 這個宏的定義位於inlclude\linux\init.h中:
#define __define_initcall(level,fn)   \
static initcall_t __initcall_##fn  \
__attribute__((__section__(".initcall" level ".init"))) \
= fn
其中 initcall_t 是個函數指標類型:
typedef int (*initcall_t)(void);
而屬性 __attribute__((__section__())) 則表示把對象放在一個這個由括弧中的名稱所指代的section中。

所以這個宏定義的的含義是:1) 聲明一個名稱為__initcall_##fn的函數指標(其中##表示替換串連,);2)

將這個函數指標初始化為fn;3) 編譯的時候需要把這個函數指標變數放置到名稱為 ".initcall" level ".init"的section中(比如level="1",代表這個section的名s稱是 ".initcall1.init")。
2) 舉例:__define_initcall(6, pci_init)
上述宏調用的含義是:1) 聲明一個函數指標__initcall_pic_init = pci_init;且 2) 這個指標變數

__initcall_pic_init 需要放置到名稱為 .initcall6.init的section中( 其實質就是將 這個函數pic_init

的首地址放置到了這個section中)。
3) 這個宏一般並不直接使用,而是被定義成下述其他更簡單的7個衍生宏
這些衍生宏宏的定義也位於 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)
因此通過宏 core_initcall() 來聲明的函數指標,將放置到名稱為.initcall1.init的section中,而通過宏

postcore_initcall() 來聲明的函數指標,將放置到名稱為.initcall2.init的section中,依次類推。
4) 舉例:device_initcall(pci_init)
解釋同上 1-2)。
2、和初始化調用有關section--initcall.init被分成了7個子section
1) 他們依次是.initcall1.init、.initcall2.init、...、.initcall7.init
2) 按照先後順序依次排列
3) 他們的定義在文檔vmlinux.lds.S中
例如 對於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個section總的開始位置被標識為__initcall_start,而在結尾被標識為__initcall_end。
3、 核心初始化函數do_basic_setup(): do_initcalls() 將從.initcall.init中,也就是這7個section中依
次取出任何的函數指標,並調用這些函數指標所指向的函數,來完成核心的一些相關的初始化。
這個函數的定義位於init\main.c中:
extern initcall_t __initcall_start, __initcall_end;
static void __init do_initcalls(void)
{
initcall_t *call;
....
for (call = &__initcall_start; call 

***********************************************************************

假如您希望某個初始化函數在核心初始化階段就被調用,那麼您就應該使用宏__define_initcall(level,fn)

或 其7個衍生宏來把這個初始化函數fn的起始地址按照初始化的順序放置到相關的section 中。 核心初始化

時的do_initcalls()將從這個section中按順序找到這些函數來執行。
 
-------------------------------------------------------------

原文連結:http://hi.baidu.com/wdsfup/blog/item/5868d3dd182911e376c638c7.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.