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中,
是可以隨便改寫加工的。
歡迎各位指出不足之處