u-boot學習(五):u-boot啟動內核
u-boot的目的是啟動內核。內核位於Flash中,那麽u-boot就要將內核轉移到內存中。然後執行命令執行之。這些操作是由bootcmd命令完畢的。
bootcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0
nand read.jffs2 0x30007FC0 kernel 從Flash讀出內核,kernel代表從kernel分區讀出內核到0x30007FC0。
1、為什麽會用0x30007FC0這麽怪的地址呢,由於真實的內核映像文件是uImage文件。它包括:頭部+真正的內核。而頭部大小正好是64字節。64字節+0x30007FC0正好是0x30008000,這個0x30008000就是真正內核的載入地址,這樣安排。就不用又一次移動內核了。
2、另一個概念就是kernel分區。事實上這是分區的概念,我們在include/configs/100ask24x0.h中將分區寫死,分區的名字並不重要。重要的是起始地址以及分區的大小。
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:[email protected](bootloader)," "128k(params)," "2m(kernel)," "-(root)"bootm 0x30007FC0命令在讀取完內核後啟動內核,調用do_bootm函數。它有零個作用:
1、依據頭部移動內核到合適的位置(上面分析了,此處不需移動)。
2、啟動do_bootm_linux。它也有兩個作用:告訴內核一些參數,即設置啟動參數;跳到入口地址啟動內核。
Bootloader與內核的交互是單向的。Bootloader將各類參數傳給內核。
因為它們不能同一時候執行。傳遞辦法僅僅有一個:Bootloader將參數放在某個約定的地方後。再啟動內核,內核啟動後從這個地方獲得參數。
除了約定好參數存放的地址外,還要規定參數的結構。內核期望以標記列表的形式來傳遞啟動參數。
標記,就是一種數據結構;標記列表,就是挨著存放的多個標記。標記列表以標記ATAG_CORE開始,以標記ATAG_NONE結束。標記的數據結構為tag,它由一個tag_header結構和一個聯合(union)組成。
tag_header結構表示標記的類型及長度,比方是表示內存還是表示命令行參數等。
對於不同類型的標記使用不同的聯合(union)。比方表示內存時使用tag_mem32。表示命令時使用tag_cmdline。數據結構tag和tag_header定義在inlcude/asm/setup.h頭文件裏。
struct tag_header { u32 size; u32 tag; }; struct tag { struct tag_header hdr; union { struct tag_core core; struct tag_mem32 mem; struct tag_videotext videotext; struct tag_ramdisk ramdisk; struct tag_initrd initrd; struct tag_serialnr serialnr; struct tag_revision revision; struct tag_videolfb videolfb; struct tag_cmdline cmdline; /* * Acorn specific */ struct tag_acorn acorn; /* * DC21285 specific */ struct tag_memclk memclk; } u; };能夠利用這些結構設置標記ATAG_CORE、設置內存標記、設置命令行標記、設置標記ATAG_CORE。源代碼中的setup_memory_tags、setup_commadnline_tag函數完畢內存標記和命令標記的設置,一般設置這兩個標記就能夠了。
設置完標記後,最後通過theKernel(0, bd->bi_arch_number, bd->bi_boot_params)調用內核。當中,theKernel指向內核存放的地址(對於ARM架構的CPU。一般是上面提到的0x30008000),bd->bi_arch_number就是第二階段代碼中board_init函數設置的機器類型ID,而bd->bi_boot_params就是標記列表的開始地址。
參考:韋東山 《嵌入式Linux應用開發全然手冊》
u-boot學習(五):u-boot啟動內核