static char __setup_str_##unique_id[] __initdata __aligned(1) = str

__setup這條宏在Linux Kernel中使用最多的地方就是定義處理Kernel的啓動參數的函數及數據結構,宏定義如下:

#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)

#define __setup_param(str, unique_id, fn, early) \
static char __setup_str_##unique_id[] __initdata __aligned(1) = str; \
static struct obs_kernel_param __setup_##unique_id \
__used __section(.init.setup) \
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_##unique_id, fn, early }


使用Kernel中的例子分析一下這兩條定義:

__setup("root=",root_dev_setup);

這條語句出現在init/do_mounts.c中,其作用是處理Kernel啓動時的像root=/dev/mtdblock3之類的參數的。

分解一下這條語句,首先變爲:

__setup_param("root=",root_dev_setup,root_dev_setup,0);

繼續分解,將得到下面這段代嗎:

static char __setup_str_root_dev_setup_id[] __initdata __aligned(1) = "root=";
static struct obs_kernel_param __setup_root_dev_setup_id
__used __section(.init.setup)
__attribute__((aligned((sizeof(long)))))
= { __setup_str_root_dev_setup_id, root_dev_setup, 0 };


這段代碼定義了兩個變量:字符數組變量__setup_str_root_dev_setup_id,其初始化內容爲"root=",由於該變量用 __initdata修飾,它將被放入.init.data輸入段;另一變量是結構變量__setup_root_dev_setup_id,其類型爲 struct obs_kernel_param, 該變理被放入輸入段.init.setup中。結構struct struct obs_kernel_param也在該文件中定義如下:

struct obs_kernel_param {
const char *str;
int (*setup_func)(char *);
int early;
};

變量__setup_root_dev_setup_id的三個成員分別被初始化爲:

__setup_str_root_dev_setup_id --> 前面定義的字符數組變量,初始內容爲"root="。

root_dev_setup --> 通過宏傳過來的處理函數。

0 -->常量0,該成員的作用以後分析。

現在不難想像內核啓動時怎麼處理啓動參數的了:通過__setup宏定義obs_kernel_param結構變量都被放入.init.setup段中,這樣一來實際是使.init.setup段變成一張表,Kernel在處理每一個啓動參數時,都會來查找這張表,與每一個數據項中的成員str進行比較,如果完全相同,就會調用該數據項的函數指針成員setup_func所指向的函數(該函數是在使用__setup宏定義該變量時傳入的函數參數),並將啓動參數如root=後面的內容傳給該處理函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章