omapl138移植uboot系列之啓動內核原理(啓動內核第三篇)

uboot啓動內核原理

看完上一節,你應該已經學會如何啓動內核了,但只會啓動內核是不行的,我們的目的是令內核按照我們的想法去運行,這就不得不提一下內核傳參機制。

3.3.1 還是bootm

內核啓動不是無條件的,而是有一定的先決條件,這個條件由啓動內核的bootloader(我們這裏就是uboot)來構建保證。

Linux規定了一種“向我傳參“機制,那麼uboot要是還想啓動Linux內核就只能乖乖的遵守,上節我們只是講解了uboot通過bootm命令啓動內核,關於bootm所做的實際工作並未講解,其實bootm執行時,uboot實際執行的函數叫do_bootm函數,該函數位於cmd/bootm.c文件中(我們的uboot2017是在此目錄下,早一些的uboot版本位於cmd/cmd_bootm.c文件)。

do_bootm函數主要做了以下工作:

讀取內核鏡像頭信息,然後在頭信息的特定地址找MAGIC_NUM,由此來確定鏡像種類。

對鏡像進行校驗,校驗通過則進入下一步準備啓動內核;如果校驗失敗則認爲鏡像有問題,不能啓動。

再次讀取頭信息,由特定地址知道這個鏡像的各種信息(鏡像長度、鏡像種類、入口地址);第四步就去entrypoint處開始執行鏡像。

uboot本身設計時只支持uImage啓動,原來uboot的代碼也是這樣寫的。後來有了fdt方式之後,就把uImage方式命令爲LEGACY方式,fdt方式命令爲FIT方式。

找到do_bootm_linux函數,ep就是entrypoint的縮寫,就是程序入口。一個鏡像文件的起始執行部分不是在鏡像的開頭(鏡像開頭有n個字節的頭信息),真正的鏡像文件執行時第一句代碼在鏡像的中部某個字節處,相當於頭是有一定的偏移量的。這個偏移量記錄在頭信息中。

theKernel = (void (*)(int, int, uint))ep;將ep賦值給theKernel,則這個函數指向就指向了內存中加載的OS鏡像的真正入口地址(就是操作系統的第一句執行的代碼)。

3.3.2 內核傳參

theKernel函數啓動內核時,傳遞了三個變量,沒錯,這三個變量就是uboot向Linux內核傳遞的參數,從前往後分別放在了ARM的r0-r2寄存器上,內核啓動之後會去這三個寄存器上讀取uboot傳遞給它的參數並解析運行。

首先第一個參數,也是我目前認爲最雞肋的參數:向寄存器r0寫入數值“0“,對!沒錯!就是一個0,現在我也不明白爲什麼linus大神爲什麼會定義這麼一個參數,可能是作爲一個預留吧!也許哪天我境界到了就能領會大師的深意了。

和第一個參數相比,第二個參數就很有意義了,這也是很多人最容易疏忽的一個傳參:板卡機器碼。該機器碼一定要和kernel中的機器碼一致,否則內核啓動必然失敗!內核在編譯鏈接過程中,將各種處理器內核描述符組合成表,啓動後從機器描述符表中查詢有無r1寄存器指定的機器碼,如果沒有就將退出,所以這也說明了爲什麼在u-boot中機器碼一定要和內核中的機器碼一致,否則內核就無法啓動。

在介紹第三個傳參之前,我想先給大家介紹兩種Linux內核啓動的方式,因爲這決定了第三個參數,第一種是比較傳統的ATAGS傳參方式啓動內核,這也是我們選擇的內核啓動方式(另一種方式比較新,還沒有時間去深入研究..),第二種就是設備樹方式啓動內核,設備樹在Linux3.0以後的內核版本開始支持,關於Linux設備樹這裏不做過多講解。

我們使用的是ATAGS傳參,那麼就我們就要在內核啓動前將傳遞參數設置好放在一個內存地址處,然後將該地址賦值給r2寄存器,也即uboot的第三個傳參(如果是設備樹傳參,我們就將設備樹加載到DDR的地址賦值給r2寄存器)。

 

 

3.3.3 ATAGS傳參

 

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;

};

tag是一個結構體類型 ,在uboot和linux kernel中都有定義tag數據機構,而且定義是一樣的。

 

結構體tag_header和共用體tag_xxx。tag_header中有這個tag的size和類型編碼,kernel拿到一個tag後先分析tag_header得到tag的類型和大小,然後將tag中剩餘部分當作一個tag_xxx來處理, kernel接收到的傳參是若干個tag構成的,這些tag由tag_start起始,到tag_end結束。

(1)CONFIG_SETUP_MEMORY_TAGS,tag_mem,傳參內容是內存配置信息。

(2)CONFIG_CMDLINE_TAG,tag_cmdline,傳參內容是啓動命令行參數,也就是uboot環境變量的bootargs.

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