u boot向Linux核心傳遞引數tag原理分析

2021-09-11 20:19:35 字數 3137 閱讀 3458

u-boot最主要的功能是引導os,目前對linux支援的相對比較好,「引導」的意義不僅僅是拷貝核心,執行核心,還要給核心kernel傳遞板子的相關引數,打個比方,u-boot相當於是一名專業功底深厚的 「接待員」,他會先初始化好一些外圍裝置,比如說串列埠,sdram、nand flash、mmc等,初始化這些 外圍裝置也是為了最終迎接kernel的到來,比如初始化串列埠,自然是為了除錯列印,初始化sdram是為了執行u-boot 本身,是u-boot的 執行的根本,初始化nand flash和mmc主要是為了搬遷u-boot和kernel,試想,kernel都是燒寫在nand flash的,自然需要對應的驅動來讀寫nand flash。

u-boot在引導kernel的同時,還需要給kernel傳遞一些引數,這就相當於交代一些關鍵資訊,比如這塊板子的記憶體起始位址、記憶體大小、串列埠資訊、root的型別等等,kernel是個「大拿」,不要想著直接去修改kernel **來實現這些功能,這不現實,也不科學,所以最好是按照kernel的介面協議,傳遞板子資訊引數給kernel。

u-boot的最後一句**如下:

thekernel (0, machid, bd->bi_boot_params);
這條**就是引導核心kernel的終極**,向核心傳遞了3個引數,分別是0,machid、bd->bi_boot_params,去掉那個「0」其實就2個引數,寫到這裡你可以能懷疑,難道就這兩個引數嗎?答案是也 對也不對,對的是,確實只有這兩個引數,不對的是,這個bd->bi_boot_params是個指標,也就是是個位址,它指向了所有 傳遞給核心的 引數,指標這個 東西就沒譜了, 後面可以延伸n多個位址,也就是n個引數。

kernel規定,如果想要傳遞引數給kernel,就需要將引數儲存在struct tag型別的資料結構裡,可以有n 多個,tag的資料 結構定義如下:

///include/asm-arm/setup.h

struct tag u;

};//其中tag_header的定義如下:

struct tag_header ;

從上面的定義可知,tag_header作為「頭」,表示了這個tag的型別和大小,而後面的「共同體」代表了 幾種不同的定義,共同體的作用是為了找「 共同」,然後取最大空間公約數,上面的所有tag型別,並不是要全部賦值傳遞給kernel,而是根據移值板子的配置(mx28_evk.h),比如最常用,也是最基本的幾種tag:tag_core、tag_mem32、tag_cmdline,假設 我們就只傳遞這幾種tag,那麼我們就需要在thekernel函式之前對這幾種tag 進行初始化,去掉那個複雜的共同體表示方式,這三種tag的內容就如下:

//tag_core

struct tag ;

//tag_mem32

struct tag ;

//tag_cmdline

struct tag ;

我們只需要把這3個tag順序依次的存放到前面說的bd->bi_boot_params開始位址處即可。而且linux規定,tag列表的第一項必須是tag_core,最後一項必須是atag_nene,自然我們也要遵從這個「協議規定」,這沒什麼好說的,不遵守,linux就不認。我們來看下這3個tag,u-boot是如何初始化的。

前面講到thekernel是最後一條**,那麼初始化tag必然也是要在這條**之前的,我們在/lib_arm/bootm.c檔案中可以找到引導kernel函式:do_bootm_linux,去掉條件編譯如下所示:

int do_bootm_linux(int flag, int argc, char *ar**, bootm_headers_t *images)

show_boot_progress (15);

debug ("## transferring control to linux (at address %08lx) ...\n",

(ulong) thekernel);

//安裝tag_core

setup_start_tag (bd);

//安裝tag_mem32

setup_memory_tags (bd);

//安裝tag_cmdline

setup_commandline_tag (bd, commandline);

//tag操作結束

setup_end_tag (bd);

/* we assume that the kernel is in place */

printf ("\nstarting kernel ...\n\n");

cleanup_before_linux ();

thekernel (0, machid, bd->bi_boot_params);

/* does not return */

return 1;

}

從上面的**可以知道,總共操作了4種tag,分別為tag_core、tag_mem32、tag_cmdline、tag end(就是結束),

我們來分別看這個4中tag的操作函式:

static void setup_start_tag (bd_t *bd)

#ifdef config_setup_memory_tags

static void setup_memory_tags (bd_t *bd)

}#endif /* config_setup_memory_tags */

static void setup_commandline_tag (bd_t *bd, char *commandline)

static void setup_end_tag (bd_t *bd)

從上面的 **及順序就可以很好的驗證之前的分析,先 從atag_core開始,以atag_none結束,簡單分析可知:

(1)atag_core:將bd->bi_boot_params賦值到tag_core,以便告訴核心從**開始找引數。

(2)atag_mem:主要是告訴核心sdram的大小和開始位址。

(3)atag_cmdline:命令列引數,bootargs的賦值,這也是最重要的引數,kernel根據這個命令列引數來進行配置,這一點會再專門寫一篇文章來分析。

(4)atag_none:結束,所以tag型別為atag_none,大小為0.

UBOOT引導Linux核心及向核心傳遞引數的方式

一直以來沒有想過有什麼好的辦法通過暫存器向核心傳遞引數,直到今天讀uboot的實現方式。在uboot中,引導核心最常用的方法是bootm命令,bootm命令可以引導 uboot格式 的核心。先花點時間了解一下什麼是 uboot格式 的核心吧 用uboot自帶的mkimage命令生成的核心稱為 ubo...

UBOOT引導Linux核心及向核心傳遞引數的方式

一直以來沒有想過有什麼好的辦法通過暫存器向核心傳遞引數,直到今天讀uboot的實現方式。在uboot中,引導核心最常用的方法是bootm命令,bootm命令可以引導 uboot格式 的核心。先花點時間了解一下什麼是 uboot格式 的核心吧 用uboot自帶的mkimage命令生成的核心稱為 ubo...

U Boot如何向核心傳遞Flash的分割槽資訊

對於目前的u boot而言,是的.而且,設定了mtdparts變數之後,你可以在nand read write erase命令中直接使用分割槽的名字而不必指 定分割槽的偏移位置.set bootargs noinitrd console ttysac0 root dev mtdblock3 root...