分析kernel的initcall函式

2021-08-25 18:59:54 字數 3807 閱讀 9407

分析kernelinitcall函式

先來看看這些initcall函式的宣告:

/* include/linux/init.h */

/* initcalls are now grouped by functionality into separate

* subsections. ordering inside the subsections is determined

* by link order.

* for backwards compatibility, initcall() puts the call in

* the device init subsection.

#define __define_initcall(level,fn) \

static initcall_t __initcall_##fn __attribute_used__ \

__attribute__((__section__(".initcall" level ".init"))) = fn

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

#define __initcall(fn) device_initcall(fn)

#define __exitcall(fn) \

static exitcall_t __exitcall_##fn __exit_call = fn

#define console_initcall(fn) \

static initcall_t __initcall_##fn \

__attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn

#define security_initcall(fn) \

static initcall_t __initcall_##fn \

__attribute_used__ __attribute__((__section__(".security_initcall.init"))) = fn

#define module_init(x) __initcall(x); ß從這裡知道module_init的等級為6,相對靠後

#define module_exit(x) __exitcall(x);

可以發現這些*_initcall(fn)最終都是通過__define_initcall(level,fn)巨集定義生成的。

__define_initcall巨集定義如下:

#define __define_initcall(level,fn) \

static initcall_t __initcall_##fn __attribute_used__ \

__attribute__((__section__(".initcall" level ".init"))) = fn

這句話的意思為定義乙個initcall_t型的初始化函式,函式存放在.initcall」level」.init section內。.initcall」level」.init section定義在vmlinux.lds內。

/* arch/arm/kernel/vmlinux.lds */

__initcall_start = .;

*(.initcall1.init)

*(.initcall2.init)

*(.initcall3.init)

*(.initcall4.init)

*(.initcall5.init)

*(.initcall6.init)

*(.initcall7.init)

__initcall_end = .;

正好包括了上面init.h裡定義的從core_initcall到late_initcall等7個level等級的.initcall」level」.init section. 因此通過不同的*_initcall宣告的函式指標最終都會存放不同level等級的.initcall」level」.init section內。這些不同level的section按level等級高低依次存放。

下面我們再來看看,核心是什麼時候呼叫儲存在.initcall」level」.init section內的函式的。

核心是通過do_initcalls函式迴圈呼叫執行initcall.init section內的函式的,流程如下:

start_kernel -> rest_init -> kernel_thread -> init -> do_basic_setup -> do_initcalls

這裡要分析兩個函式: kernel_thread和do_initcalls,這兩個函式都定義在init/main.c內

1) kernel_thread

1.static void noinline rest_init(void)

2. __releases(kernel_lock)

3.第6行通過kernel_thread建立乙個核心執行緒執行init函式。(其實這裡建立的即linux的1號程序(init程序), 為linux中所有其他程序的父程序,有興趣的可以自己查資料)

2) do_initcalls

1.static void __init do_initcalls(void)

2.11.}

其中, initcall_t型別如下:

typedef int (*initcall_t)(void);

__initcall_start和__initcall_end定義在vmlinux.lds內,表示initcall section的起始和結束位址。

/* arch/arm/kernel/vmlinux.lds */

__initcall_start = .;

*(.initcall1.init)

*(.initcall2.init)

*(.initcall3.init)

*(.initcall4.init)

*(.initcall5.init)

*(.initcall6.init)

*(.initcall7.init)

__initcall_end = .;

因此,上面6-10行**的作用為按initcall level等級的順序,依次迴圈呼叫預先儲存在initcall section內的所有各個級別的初始化函式。這樣,kernel的initcall函式的原理我們就搞清楚了。

最後要注意的是rest_init是在start_kernel函式內最後部分才被呼叫執行的,rest_init前包含了kernel一系列的初始化工作。另外,這些不同level等級的initcall.init section本身有一定的執行順序,因此如果你的驅動依賴於特定的執行順序的話需要考慮到這一點。

分析kernel的initcall函式

先來看看這些initcall函式的宣告 include linux init.h initcalls are now grouped by functionality into separate subsections.ordering inside the subsections is deter...

Codeviz 分析kernel源程式

codeviz是一款開源的用於自動生成c c 源程式呼叫關係圖的工具,其主頁位址為 codeviz的實現原理是通過給gcc打補丁,而且不同版本的codeviz對應的gcc的版本也不一致。本文使用的是codeviz 1.0.11版本,codeviz 1.0.11.tar.gz。解壓後的目錄中compi...

關於Kernel的思考

學習播客 klda 推導得很通俗,下面的推導就是源於此篇部落格 第一部分 按照自己的理解,模仿抄!學習播客來完成一下klda的推導。第二部分 對於kernel的思考 klda 顧名思義,就是把kernel運用到了lda上,下面直接推導公式。原始空間資料 x 對映之後資料 phi x 1 j w fr...