內核命令處理

From http://blog.chinaunix.net/u3/111928/showart_2184040.html

參考文章:非常經典的文章

http://book.opensourceproject.org.cn/embedded/embeddedprime/index.html?page=opensource/0136130550/ch05lev1sec3.html

 本文原創 ,轉貼請註明出處,謝謝!

 本文分析對象: arm linux 2.6.29
 

0 處理 模型

Linux kernel 的啓動包 括很多組件的初始化和相關配置,這些配置參數一般是通過command line 進 行配置的。在進行後續分析之前,先來理解一下command line 的處理 模型:
要處理的對象是一個字符串,其中包含了各種配置信息,通常各個配置之間通過空格進行分離,每個配置的表達形式是 如:param=value1,value2 或者很簡單就是一個rw
那麼kernel 就需要提供對這些 參數進行處理的處理函數列表。根據參數的作用以及執行期的先後不同,這些處理函數被定義到不同的段中。針對每一個參數,Kernel 都會到相應的段中查找相應的處理函數,最終進行各個組件的配置。

1 配置 格式

常見的配置格式如:
 
console=ttySAC0,115200 root=nfs nfsroot=192.168.1.9:/source/rootfs initrd=0x10800000,0x14af47
 

2 配置 方式

2.1 Bootloader 動 態配置

bootloader 進行參數配 置,command line 將做爲atag_list 的一個節點傳遞到Kernel

2.2 Kernel 靜態配置

通過make menuconfig 進 行配置:運行後配置boot options->Default kernel command string 。該配置將被靜態編譯到Kernel 中, 通過變量default_command_line 訪問。

解 析配置

3.1 相關定義

根據執行的先後順序,可以將處理函數分爲三個大類,他們分別存在於下面三個段中(參考top/arch/arm/kernel/vmlinux.lds:
 
__setup_start = .; *(.init.setup) __setup_end = .;
 
__early_begin = .; *(.early_param.init) __early_end = .;
 
__start___param = .; *(__param) __stop___param = .;
 
這 三個段內存儲的不是參數,而是command line 參數所需要的處理函 數。

3.1.1 .early_param.init

.early_param.init ” 所定義的處理相對靠前一些,它所處理的參數例如:initrd=cachepolicy=nocache nowb ecc= vmalloc= mem= ,等等。
這些處理函數是通過__early_param 宏 來定義的,例如:

static void __init early_initrd(char **p)
{ …… }
__early_param("initrd=", early_initrd);
對於宏__early_param , 可以在top/arch/arm/include/asm/Setup.h 中 找到如下定義:
 
struct early_params {
    const char *arg;
    void (*fn)(char **p);
};
#define __early_param(name,fn) /
static struct early_params __early_##fn __used /
__attribute__((__section__(".early_param.init"))) = { name, fn }
 
 
 
.init.setup ”定義的 處理則要靠後一些,它所處理的參數例如:nfsroot= ip= ,等等。
這些處理函數是通過__setup 宏 來定義的,例如:
 
static int __init nfs_root_setup(char *line)
{ …… }
__setup("nfsroot=", nfs_root_setup);
 
對於宏__setup , 可以在top/include/linux/Init.h 中看到:
 
#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 }

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

/* NOTE: fn is as per module_param, not __setup! Emits warning if fn
 * returns non-zero. */
#define early_param(str, fn) /
    __setup_param(str, fn, fn, 1)
 
注意看的話,可以看到還有一個宏 early_param , 它與宏__setup 的定義相似,只不過最後一個宏參數是1 而不是01 表示需要提前處理的參數。

3.1.3  __param

這個段中保存的是build-in 類 型module 的配置參數。該宏直接用來修飾需要的變量。

3.2  解析

3.2.1 相關變量

相關的變量包括:
default_command_line
保存memuconfig 配置的參 數,如果bootloader 傳入了命令行參數,那麼這個新的配置將被更新到 該變量中。
boot_command_line
存在於.init.data 段。最 初是default_command_line 的拷貝。
command_line
存在於.init.data 段。在parse_cmdline() 中被賦值,數據來源是default_command_line
saved_command_line
用於保存沒有處理過的命令行參數,是boot_caommand_line 的 拷貝。
static_command_line
command_line 的拷 貝。

3.2.2 主要函數

函數名稱:parse_cmdline()
操作數據:default_command_line
函數列表: .early_param.init 段 (在__early_begin__early_end 之間)。
函數功能: 依據函數列表對default_command_line 中 的參數進行處理。
 
 
函數名稱:parse_early_param()
操作數據:boot_command_line
函數列表: .init.setup 段 中(__setup_start__setup_end 之間),主要是通過宏early_param 定 義的部分。
函數功能: 依據函數列表對boot_command_line 中 的參數進行處理。
注意parse_one() 的第四 個入參是0 ,而且第五個參數是NULL 。這裏沒有給出參數隊列,不會對boot_command_line 的 每個參數在參數隊列中進行對比查找,而是直接在do_early_param() 中 進行條件判斷,如果滿足下面的條件,那麼對該參數進行對應的操作:
 
if ((p->early && strcmp(param, p->str) == 0) ||
                  (strcmp(param, "console") == 0 &&
                   strcmp(p->str, "earlycon") == 0)
              )
 
 
函數名稱:parse_args()
操作數據:static_command_line
函數列表: __param 段 (__start___param__stop___param 之間)。
函數功能: 該操作將依據函數列表,對static_command_line 中 的參數進行相應的操作。這個操作在parse_one() 的第一部分代碼完 成:
 
for (i = 0; i < num_params; i++) {
          if (parameq(param, params[i].name)) {
                 DEBUGP("They are equal! Calling %p/n",
                        params[i].set);
                 return params[i].set(val, &params[i]);
          }
   }
 
接下來對於不被這個列表所支持的參數,將在unknown_bootoption() 中 進行處理。在unknown_bootoption() 中主要是obsolete_checksetup() 的操作。
 
 
函數名稱:obsolete_checksetup()
操作數據:static_command_line
函數列表: .init.setup 段 中(__setup_start__setup_end 之間),主要是通過宏__setup 定 義的部分。
函數功能: 該操作將依據函數列表,對static_command_line 中 的參數進行相應的操作。如果是在parse_early_param() 中已 經處理的操作,那麼這裏不再處理;如果是查找到的條目中沒有操作函數,那麼這表示是過時的數據定義(有些早期的代碼,沒有定義這個函數);如果不是以上兩 種情形,那麼利用找到的函數對參數進行處理。

3.2.3 圖示


發佈了303 篇原創文章 · 獲贊 21 · 訪問量 188萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章