1. 程式人生 > >uboot之uboot中環境變數

uboot之uboot中環境變數

一、環境變數基礎

    1、環境變數的作用

        讓我們可以不用修改uboot的原始碼,而是通過修改環境變數來影響uboot執行時的一些資料和特性。譬如說通過

        修改bootdelay環境變數就可以更改系統開機自動啟動時倒數的秒數。

    2、環境變數優先順序

        (1)uboot程式碼當中有一個值,環境變數中也有一個值。uboot程式實際執行時規則是:如果環境變數為空則使用代

        碼中的值;如果環境變數不為空則優先使用環境變數對應的值。

        (2)譬如machid(機器碼)。uboot中在x210_sd.h中定義了一個機器碼2456,寫死在程式中的不能更改。如果要

        修改uboot中配置的機器碼,可以修改x210_sd.h中的機器碼,但是修改原始碼後需要重新編譯燒錄,很麻煩;比

        較簡單的方法就是使用環境變數machid。set machid 0x998類似這樣,有了machid環境變數後,系統啟動時會優

        先使用machid對應的環境變數,這就是優先順序問題。

    3、環境變數在uboot中工作方式

        (1)預設環境變數,在uboot/common/env_common.c中default_environment,這東西本質是一個字元陣列,

        大小為CFG_ENV_SIZE(16kb),裡面內容就是很多個環境變數連續分佈組成的,每個環境變數最末端以'\0'結束。

        (2)SD卡中環境變數分割槽,在uboot的raw分割槽中。SD卡中其實就是給了個分割槽,專門用來儲存而已。儲存時其實

        是把DDR中的環境變數整體的寫入SD卡中分割槽裡。所以當我們saveenv時其實整個所有的環境變數都被儲存了一

        遍,而不是隻儲存更改了的。

        (3)DDR中環境變數,在default_environment中,實質是字元陣列。在uboot中其實是一個全域性變數,連結時在數

        據段,重定位時default_environment就被重定位到DDR中一個記憶體地址處了。這個地址處這個全域性字元陣列就是

        我們uboot執行時的DDR中的環境變量了。

二、環境變數解析

    1、printenv

        (1)找到printenv命令所對應的函式。通過printenv的help可以看出,這個命令有2種使用方法。第一種直接使用

        不加引數則列印所有的環境變數;第二種是printenv name則只打印出name這個環境變數的值。

        (2)do_printenv函式首先區分argc=1還是不等於1的情況,若argc=1那麼就迴圈列印所有的環境變量出來;如果

        argc不等於1,則後面的引數就是要列印的環境變數,給哪個就列印哪個。

        (3)argc=1時用雙重for迴圈來依次處理所有的環境變數的列印。第一重for迴圈就是處理各個環境變數。所以有多少

        個環境變數則第一重就執行迴圈多少圈。

    2、setenv

        (1)命令定義和對應的函式在uboot/common/cmd_nvedit.c中,對應的函式為do_setenv。

        (2)setenv的思路就是:先去DDR中的環境變數處尋找原來有沒有這個環境變數,如果原來就有則需要覆蓋原來的

        環境變數,如果原來沒有則在最後新增一個環境變數即可。

            第1步:遍歷DDR中環境變數的陣列,找到原來就有的那個環境變數對應的地址。168-174行。

            第2步:擦除原來的環境變數,259-265行

            第3步:寫入新的環境變數,266-273行。

     3、saveenv

         (1)在uboot/common/cmd_nvedit.c中,對應函式為do_saveenv

         (2)從uboot實際執行saveenv命令的輸出,和x210_sd.h中的配置(#define CFG_ENV_IS_IN_AUTO)可以分析

        出:我們實際使用的是env_auto.c中相關的內容。沒有一種晶片叫auto的,env_auto.c中是使用巨集定義的方式去

        條件編譯了各種常見的flash晶片(如movinand、norflash、nand等)。然後在程式中讀取INF_REG(OMpin內

        部對應的暫存器)從而知道我們的啟動介質,然後呼叫這種啟動介質對應的操作函式來操作。    

        (3)do_saveenv內部呼叫env_auto.c中的saveenv函式來執行實際的環境變數儲存操作。

        (4)暫存器地址:E010F000+0C=E010_F00C,含義是使用者自定義資料。

        (5)真正執行儲存環境變數操作的是:cpu/s5pc11x/movi.c中的movi_write_env函式,這個函式肯定是寫sd卡,

        將DDR中的環境變數陣列(其實就是default_environment這個陣列,大小16kb,剛好32個扇區)寫入iNand中的

        ENV分割槽中。

        (6)raw_area_control是uboot中規劃iNnad/SD卡的原始分割槽表,這個裡面記錄了我們對iNand的分割槽,env分割槽

        也在這裡,下標是2.追到這一層就夠了,再裡面就是呼叫驅動部分的寫SD卡/iNand的底層函數了。

    4、getenv

        (1)應該是不可重入的。

        (2)實現方式就是去遍歷default_environment陣列,挨個拿出所有的環境變數比對name,找到相等的直接返回

        這個環境變數的首地址即可。

    5、getenv_r

        (1)可重入版本。(可自行搜尋補充可重入函式的概念)

        (2)getenv函式是直接返回這個找到的環境變數在DDR中環境變數處的地址,而getenv_r函式的做法是找到了DDR

        中環境變數地址後,將這個環境變數複製一份到提供的buf中,而不動原來DDR中環境變數。

        所以差別就是:getenv中返回的地址只能讀不能隨便亂寫,而getenv_r中返回的環境變數是在自己提供的buf中,

        是可以隨便改寫加工的。

歡迎各位指出不足之處