日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

uboot环境变量实现分析

發(fā)布時間:2025/4/16 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uboot环境变量实现分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

u-boot的環(huán)境變量用來存儲一些經(jīng)常使用的參數(shù)變量,uboot希望將環(huán)境變量存儲在靜態(tài)存儲器中(如nand?nor?eeprom?mmc)。

其中有一些也是大家經(jīng)常使用,有一些是使用人員自己定義的,更改這些名字會出現(xiàn)錯誤,下面的表中我們列出了一些常用的環(huán)境變量:

?????bootdelay????執(zhí)行自動啟動的等候秒數(shù)
?????baudrate?????串口控制臺的波特率
?????netmask?????以太網(wǎng)接口的掩碼
?????ethaddr???????以太網(wǎng)卡的網(wǎng)卡物理地址
?????bootfile????????缺省的下載文件
?????bootargs?????傳遞給內(nèi)核的啟動參數(shù)
?????bootcmd?????自動啟動時執(zhí)行的命令
?????serverip???????服務器端的ip地址
?????ipaddr?????????本地ip?地址
?????stdin???????????標準輸入設備
?????stdout????????標準輸出設備
?????stderr?????????標準出錯設備

上面這些是uboot默認存在的環(huán)境變量,uboot本身會使用這些環(huán)境變量來進行配置。我們可以自己定義一些環(huán)境變量來供我們自己uboot驅(qū)動來使用。

Uboot環(huán)境變量的設計邏輯是在啟動過程中將env從靜態(tài)存儲器中讀出放到RAM中,之后在uboot下對env的操作(如printenv?editenv?setenv)都是對RAMenv的操作,只有在執(zhí)行saveenv時才會將RAM中的env重新寫入靜態(tài)存儲器中。

這種設計邏輯可以加快對env的讀寫速度。

基于這種設計邏輯,2014.4版本uboot實現(xiàn)了saveenv這個保存env到靜態(tài)存儲器的命令,而沒有實現(xiàn)讀取envRAM的命令。

那我們就來看一下ubootenv的數(shù)據(jù)結(jié)構(gòu)?初始化?操作如何實現(xiàn)的。

一?env數(shù)據(jù)結(jié)構(gòu)

include/environment.h中定義了env_t,如下:

[cpp] view plaincopyprint?
  • #ifdef?CONFIG_SYS_REDUNDAND_ENVIRONMENT??
  • #?define?ENV_HEADER_SIZE????(sizeof(uint32_t)?+?1)??
  • #?define?ACTIVE_FLAG???1??
  • #?define?OBSOLETE_FLAG?0??
  • #else??
  • #?define?ENV_HEADER_SIZE????(sizeof(uint32_t))??
  • #endif??
  • #define?ENV_SIZE?(CONFIG_ENV_SIZE?-?ENV_HEADER_SIZE)??
  • typedef?struct?environment_s?{??
  • ????uint32_t????crc;????????/*?CRC32?over?data?bytes????*/??
  • #ifdef?CONFIG_SYS_REDUNDAND_ENVIRONMENT??
  • ????unsigned?char???flags;??????/*?active/obsolete?flags????*/??
  • #endif??
  • ????unsigned?char???data[ENV_SIZE];?/*?Environment?data?????*/??
  • }?env_t;??
  • #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT # define ENV_HEADER_SIZE (sizeof(uint32_t) + 1) # define ACTIVE_FLAG 1 # define OBSOLETE_FLAG 0 #else # define ENV_HEADER_SIZE (sizeof(uint32_t)) #endif #define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE) typedef struct environment_s {uint32_t crc; /* CRC32 over data bytes */ #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENTunsigned char flags; /* active/obsolete flags */ #endifunsigned char data[ENV_SIZE]; /* Environment data */ } env_t;

    CONFIG_ENV_SIZE是我們需要在配置文件中配置的環(huán)境變量的總長度。

    這里我們使用的nand作為靜態(tài)存儲器,nand的一個block128K,因此選用一個block來存儲envCONFIG_ENV_SIZE128K

    Env_t結(jié)構(gòu)體頭4bytes是對datacrc校驗碼,沒有定義CONFIG_SYS_REDUNDAND_ENVIRONMENT,所以后面緊跟data數(shù)組,數(shù)組大小是ENV_SIZE.

    ENV_SIZECONFIG_ENV_SIZE減掉ENV_HEADER_SIZE,也就是4bytes

    所以env_t這個結(jié)構(gòu)體就包含了整個我們規(guī)定的長度為CONFIG_ENV_SIZE的存儲區(qū)域。

    4bytescrc校驗碼,后面剩余的空間全部用來存儲環(huán)境變量。

    需要說明的一點,crc校驗碼是uboot中在saveenv時計算出來,然后寫入nand,所以在第一次啟動ubootcrc校驗會出錯,

    因為ubootnand上讀入的一個block數(shù)據(jù)是隨機的,沒有意義的,執(zhí)行saveenv后重啟ubootcrc校驗就正確了。

    data?字段保存實際的環(huán)境變量。u-boot??的?env??按?name=value”\0”的方式存儲,在所有env?的最后以”\0\0”表示整個?env??的結(jié)束。

    新的name=value?對總是被添加到?env??數(shù)據(jù)塊的末尾,當刪除一個?name=value?對時,后面的環(huán)境變量將前移,對一個已經(jīng)存在的環(huán)境變量的修改實際上先刪除再插入。?
    u-boot?env_t??的數(shù)據(jù)指針保存在了另外一個地方,這就?
    是?gd_t??結(jié)構(gòu)(不同平臺有不同的?gd_t??結(jié)構(gòu)?),這里以ARM?為例僅列出和?env??相關的部分?

    [cpp] view plaincopyprint?
  • typedef?struct?global_data???
  • {???
  • ?????…???
  • ?????unsigned?long?env_off;????????/*?Relocation?Offset?*/???
  • ?????unsigned?long?env_addr;???????/*?Address?of?Environment?struct?????*/???
  • ?????unsigned?long?env_valid???????/*?Checksum?of?Environment?valid?*/???
  • ?????…???
  • }?gd_t;???
  • typedef struct global_data? {?…?unsigned long env_off; ? ? ? ?/* Relocation Offset */?unsigned long env_addr; ? ? ? /* Address of Environment struct ??? */?unsigned long env_valid ? ? ? /* Checksum of Environment valid */?…? } gd_t;?


    二?env的初始化

    ubootenv的整個架構(gòu)可以分為3層:

    (1)?命令層,如saveenvsetenv?editenv這些命令的實現(xiàn),還有如啟動時調(diào)用的env_relocate函數(shù)。

    (2)?中間封裝層,利用不同靜態(tài)存儲器特性封裝出命令層需要使用的一些通用函數(shù),如env_init,env_relocate_spec,saveenv這些函數(shù)。實現(xiàn)文件在common/env_xxx.c

    (3)?驅(qū)動層,實現(xiàn)不同靜態(tài)存儲器的讀寫擦等操作,這些是uboot下不同子系統(tǒng)都必須的。

    按照執(zhí)行流順序,首先分析一下uboot啟動的env初始化過程。

    首先在board_init_f中調(diào)用init_sequenceenv_init,這個函數(shù)是不同存儲器實現(xiàn)的函數(shù),nand中的實現(xiàn)如下:

    [cpp] view plaincopyprint?
  • <span?style="font-size:14px;">/*?
  • ?*?This?is?called?before?nand_init()?so?we?can't?read?NAND?to?
  • ?*?validate?env?data.?
  • ?*?
  • ?*?Mark?it?OK?for?now.?env_relocate()?in?env_common.c?will?call?our?
  • ?*?relocate?function?which?does?the?real?validation.?
  • ?*?
  • ?*?When?using?a?NAND?boot?image?(like?sequoia_nand),?the?environment?
  • ?*?can?be?embedded?or?attached?to?the?U-Boot?image?in?NAND?flash.?
  • ?*?This?way?the?SPL?loads?not?only?the?U-Boot?image?from?NAND?but?
  • ?*?also?the?environment.?
  • ?*/??
  • int?env_init(void)??
  • {??
  • ????gd->env_addr????=?(ulong)&default_environment[0];??
  • ????gd->env_valid???=?1;??
  • ????return?0;??
  • }</span>??
  • <span style="font-size:14px;">/** This is called before nand_init() so we can't read NAND to* validate env data.** Mark it OK for now. env_relocate() in env_common.c will call our* relocate function which does the real validation.** When using a NAND boot image (like sequoia_nand), the environment* can be embedded or attached to the U-Boot image in NAND flash.* This way the SPL loads not only the U-Boot image from NAND but* also the environment.*/ int env_init(void) {gd->env_addr = (ulong)&default_environment[0];gd->env_valid = 1;return 0; }</span>

    從注釋就基本可以看出這個函數(shù)的作用,因為env_init要早于靜態(tài)存儲器的初始化,所以無法進行env的讀寫,這里將gd中的env相關變量進行配置,

    默認設置envvalid。方便后面env_relocate函數(shù)進行真正的envnandramrelocate

    繼續(xù)執(zhí)行,在board_init_r中,如下:

    [cpp] view plaincopyprint?
  • /*?initialize?environment?*/??
  • ????if?(should_load_env())??
  • ????????env_relocate();??
  • ????else??
  • ????????set_default_env(NULL);??
  • /* initialize environment */if (should_load_env())env_relocate();elseset_default_env(NULL);

    這是在所有存儲器初始化完成后執(zhí)行的。

    首先調(diào)用should_load_env,如下:

    [cpp] view plaincopyprint?
  • /*?
  • ?*?Tell?if?it's?OK?to?load?the?environment?early?in?boot.?
  • ?*?
  • ?*?If?CONFIG_OF_CONFIG?is?defined,?we'll?check?with?the?FDT?to?see?
  • ?*?if?this?is?OK?(defaulting?to?saying?it's?not?OK).?
  • ?*?
  • ?*?NOTE:?Loading?the?environment?early?can?be?a?bad?idea?if?security?is?
  • ?*???????important,?since?no?verification?is?done?on?the?environment.?
  • ?*?
  • ?*?@return?0?if?environment?should?not?be?loaded,?!=0?if?it?is?ok?to?load?
  • ?*/??
  • static?int?should_load_env(void)??
  • {??
  • #ifdef?CONFIG_OF_CONTROL??
  • ????return?fdtdec_get_config_int(gd->fdt_blob,?"load-environment",?1);??
  • #elif?defined?CONFIG_DELAY_ENVIRONMENT??
  • ????return?0;??
  • #else??
  • ????return?1;??
  • #endif??
  • }??
  • /** Tell if it's OK to load the environment early in boot.** If CONFIG_OF_CONFIG is defined, we'll check with the FDT to see* if this is OK (defaulting to saying it's not OK).** NOTE: Loading the environment early can be a bad idea if security is* important, since no verification is done on the environment.** @return 0 if environment should not be loaded, !=0 if it is ok to load*/ static int should_load_env(void) { #ifdef CONFIG_OF_CONTROLreturn fdtdec_get_config_int(gd->fdt_blob, "load-environment", 1); #elif defined CONFIG_DELAY_ENVIRONMENTreturn 0; #elsereturn 1; #endif }

    從注釋可以看出,CONFIG_OF_CONTROL沒有定義,鑒于考慮安全性問題,如果我們想要推遲envload,可以定義CONFIG_DELAY_ENVIRONMENT,這里返回0,就調(diào)用set_default_env使用默認的env,默認env是在配置文件中CONFIG_EXTRA_ENV_SETTINGS設置的。

    我們可以在之后的某個地方在調(diào)用env_relocateload?env。這里我們選擇在這里直接load?env。所以沒有定義CONFIG_DELAY_ENVIRONMENT,返回1。調(diào)用env_relocate

    common/env_common.c中:

    [cpp] view plaincopyprint?
  • void?env_relocate(void)??
  • {??
  • #if?defined(CONFIG_NEEDS_MANUAL_RELOC)??
  • ????env_reloc();??
  • ????env_htab.change_ok?+=?gd->reloc_off;??
  • #endif??
  • ????if?(gd->env_valid?==?0)?{??
  • #if?defined(CONFIG_ENV_IS_NOWHERE)?||?defined(CONFIG_SPL_BUILD)??
  • ????????/*?Environment?not?changable?*/??
  • ????????set_default_env(NULL);??
  • #else??
  • ????????bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);??
  • ????????set_default_env("!bad?CRC");??
  • #endif??
  • ????}?else?{??
  • ????????env_relocate_spec();??
  • ????}??
  • }??
  • void env_relocate(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC)env_reloc();env_htab.change_ok += gd->reloc_off; #endifif (gd->env_valid == 0) { #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)/* Environment not changable */set_default_env(NULL); #elsebootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);set_default_env("!bad CRC"); #endif} else {env_relocate_spec();} } [cpp] view plaincopyprint?
  • ??
  • </pre><p style="font-size: 14px;">Gd->env_valid<span style="font-family: 宋體;">在之前的</span><span style="font-family: Verdana;">env_init</span><span style="font-family: 宋體;">中設置為</span><span style="font-family: Verdana;">1</span><span style="font-family: 宋體;">,所以這里調(diào)用</span><span style="font-family: Verdana;">env_relocate_spec</span><span style="font-family: 宋體;">,</span></p><p style="font-size: 14px;"><span style="font-family: 宋體;">這個函數(shù)也是不同存儲器的中間封裝層提供的函數(shù),對于</span><span style="font-family: Verdana;">nand</span><span style="font-family: 宋體;">在</span><span style="font-family: Verdana;">common/env_nand.c</span><span style="font-family: 宋體;">中,如下:</span></p><div class="dp-highlighter bg_cpp"><div class="bar"><div class="tools"><strong>[cpp]</strong> <a target=_blank title="view plain" class="ViewSource" href="http://blog.csdn.net/skyflying2012/article/details/39005705#">view plain</a><a target=_blank title="copy" class="CopyToClipboard" href="http://blog.csdn.net/skyflying2012/article/details/39005705#">copy</a><a target=_blank title="print" class="PrintSource" href="http://blog.csdn.net/skyflying2012/article/details/39005705#">print</a><a target=_blank title="?" class="About" href="http://blog.csdn.net/skyflying2012/article/details/39005705#">?</a><a target=_blank title="在CODE上查看代碼片" style="text-indent: 0px;" href="https://code.csdn.net/snippets/462607" target="_blank"><img width="12" height="12" style="left: 2px; top: 1px; position: relative;" alt="在CODE上查看代碼片" src="https://code.csdn.net/assets/CODE_ico.png" /></a><a target=_blank title="派生到我的代碼片" style="text-indent: 0px;" href="https://code.csdn.net/snippets/462607/fork" target="_blank"><img width="12" height="12" style="left: 2px; top: 2px; position: relative;" alt="派生到我的代碼片" src="https://code.csdn.net/assets/ico_fork.svg" /></a></div></div><ol class="dp-cpp"><li class="alt"><span><span class="keyword">void</span><span>?env_relocate_spec(</span><span class="keyword">void</span><span>)??</span></span></li><li><span>{??</span></li><li class="alt"><span>???<span class="datatypes">int</span><span>?ret;??</span></span></li><li><span>????ALLOC_CACHE_ALIGN_BUFFER(<span class="datatypes">char</span><span>,?buf,?CONFIG_ENV_SIZE);??</span></span></li><li class="alt"><span>????ret?=?readenv(CONFIG_ENV_OFFSET,?(u_char?*)buf);??</span></li><li><span>????<span class="keyword">if</span><span>?(ret)?{??</span></span></li><li class="alt"><span>????????set_default_env(<span class="string">"!readenv()?failed"</span><span>);??</span></span></li><li><span>????????<span class="keyword">return</span><span>;??</span></span></li><li class="alt"><span>????}??</span></li><li><span>????env_import(buf,?1);??</span></li><li class="alt"><span>}???</span></li></ol></div><pre class="cpp" style="font-size: 14px; display: none;" name="code" code_snippet_id="462607" snippet_file_name="blog_20140902_8_4316261">void env_relocate_spec(void) {int ret;ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);if (ret) {set_default_env("!readenv() failed");return;}env_import(buf, 1); }

    首先定義一個長度為CONFIG_ENV_SIZEbuf,然后調(diào)用readenv

    CONFIG_ENV_OFFSET是在配置文件中定義的envnand中偏移位置。我們這里定義的是在4M的位置。

    Readenv也在env_nand.c中,如下:

    [cpp] view plaincopyprint?
  • int?readenv(size_t?offset,?u_char?*buf)??
  • {??
  • ????size_t?end?=?offset?+?CONFIG_ENV_RANGE;??
  • ????size_t?amount_loaded?=?0;??
  • ????size_t?blocksize,?len;??
  • ????u_char?*char_ptr;??
  • ????blocksize?=?nand_info[0].erasesize;??
  • ????if?(!blocksize)??
  • ????????return?1;??
  • ????len?=?min(blocksize,?CONFIG_ENV_SIZE);??
  • ????while?(amount_loaded?<?CONFIG_ENV_SIZE?&&?offset?<?end)?{??
  • ????????if?(nand_block_isbad(&nand_info[0],?offset))?{??
  • ????????????offset?+=?blocksize;??
  • ????????}?else?{??
  • ????????????char_ptr?=?&buf[amount_loaded];??
  • ????????????if?(nand_read_skip_bad(&nand_info[0],?offset,??
  • ???????????????????????????&len,?NULL,??
  • ???????????????????????????nand_info[0].size,?char_ptr))??
  • ????????????????return?1;??
  • ????????????offset?+=?blocksize;??
  • ????????????amount_loaded?+=?len;??
  • ????????}??
  • ????}??
  • ??
  • ????if?(amount_loaded?!=?CONFIG_ENV_SIZE)??
  • ????????return?1;??
  • ??
  • ????return?0;??
  • }??
  • int readenv(size_t offset, u_char *buf) {size_t end = offset + CONFIG_ENV_RANGE;size_t amount_loaded = 0;size_t blocksize, len;u_char *char_ptr;blocksize = nand_info[0].erasesize;if (!blocksize)return 1;len = min(blocksize, CONFIG_ENV_SIZE);while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {if (nand_block_isbad(&nand_info[0], offset)) {offset += blocksize;} else {char_ptr = &buf[amount_loaded];if (nand_read_skip_bad(&nand_info[0], offset,&len, NULL,nand_info[0].size, char_ptr))return 1;offset += blocksize;amount_loaded += len;}}if (amount_loaded != CONFIG_ENV_SIZE)return 1;return 0; }

    Readenv函數(shù)利用nand_info[0]nand進行讀操作,讀出指定位置,指定長度的數(shù)據(jù)到buf中。Nand_info[0]是一個全局變量,來表征第一個nand?device,這里在nand_init時會初始化這個變量。Nand_init必須在env_relocate之前。

    回到env_relocate_spec中,buf讀回后調(diào)用env_import,如下:

    [cpp] view plaincopyprint?
  • /*?
  • ?*?Check?if?CRC?is?valid?and?(if?yes)?import?the?environment.?
  • ?*?Note?that?"buf"?may?or?may?not?be?aligned.?
  • ?*/??
  • int?env_import(const?char?*buf,?int?check)??
  • {??
  • ????env_t?*ep?=?(env_t?*)buf;??
  • ??
  • ????if?(check)?{??
  • ????????uint32_t?crc;??
  • ??
  • ????????memcpy(&crc,?&ep->crc,?sizeof(crc));??
  • ??
  • ????????if?(crc32(0,?ep->data,?ENV_SIZE)?!=?crc)?{??
  • ????????????set_default_env("!bad?CRC");??
  • ????????????return?0;??
  • ????????}??
  • ????}??
  • ??
  • ????if?(himport_r(&env_htab,?(char?*)ep->data,?ENV_SIZE,?'\0',?0,??
  • ????????????0,?NULL))?{??
  • ????????gd->flags?|=?GD_FLG_ENV_READY;??
  • ????????return?1;??
  • ????}??
  • ??
  • ????error("Cannot?import?environment:?errno?=?%d\n",?errno);??
  • ??
  • ????set_default_env("!import?failed");??
  • ??
  • ????return?0;??
  • }??
  • /** Check if CRC is valid and (if yes) import the environment.* Note that "buf" may or may not be aligned.*/ int env_import(const char *buf, int check) {env_t *ep = (env_t *)buf;if (check) {uint32_t crc;memcpy(&crc, &ep->crc, sizeof(crc));if (crc32(0, ep->data, ENV_SIZE) != crc) {set_default_env("!bad CRC");return 0;}}if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0,0, NULL)) {gd->flags |= GD_FLG_ENV_READY;return 1;}error("Cannot import environment: errno = %d\n", errno);set_default_env("!import failed");return 0; }

    首先將buf強制轉(zhuǎn)換為env_t類型,然后對data進行crc校驗,跟buf中原有的crc對比,不一致則使用默認env

    最后調(diào)用himport_r,該函數(shù)將給出的data按照‘\0’分割填入env_htab的哈希表中。

    之后對于env的操作,如printenv?setenv?editenv,都是對該哈希表的操作。

    Env_relocate執(zhí)行完成,env的初始化就完成了。


    三?env的操作實現(xiàn)

    Ubootenv的操作命令實現(xiàn)在common/cmd_nvedit.c中。

    對于setenv?printenv?editenv3個命令,看其實現(xiàn)代碼,都是對relocateRAM中的env_htab的操作,這里就不再詳細分析了,重點來看一下savenv實現(xiàn)。

    [cpp] view plaincopyprint?
  • static?int?do_env_save(cmd_tbl_t?*cmdtp,?int?flag,?int?argc,??
  • ???????????????char?*?const?argv[])??
  • {??
  • ????printf("Saving?Environment?to?%s...\n",?env_name_spec);??
  • ??
  • ????return?saveenv()???1?:?0;??
  • }??
  • ??
  • U_BOOT_CMD(??
  • ????saveenv,?1,?0,??do_env_save,??
  • ????"save?environment?variables?to?persistent?storage",??
  • ????""??
  • );??
  • static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,char * const argv[]) {printf("Saving Environment to %s...\n", env_name_spec);return saveenv() ? 1 : 0; }U_BOOT_CMD(saveenv, 1, 0, do_env_save,"save environment variables to persistent storage","" );

    do_env_save調(diào)用saveenv,這個函數(shù)是不同存儲器實現(xiàn)的封裝層函數(shù)。對于nand,在common/env_nand.c中,如下:

    [cpp] view plaincopyprint?
  • int?saveenv(void)??
  • {??
  • ????int?ret?=?0;??
  • ????ALLOC_CACHE_ALIGN_BUFFER(env_t,?env_new,?1);??
  • ????ssize_t?len;??
  • ????char????*res;??
  • ????int?env_idx?=?0;??
  • ????static?const?struct?env_location?location[]?=?{??
  • ????????{??
  • ????????????.name?=?"NAND",??
  • ????????????.erase_opts?=?{??
  • ????????????????.length?=?CONFIG_ENV_RANGE,??
  • ????????????????.offset?=?CONFIG_ENV_OFFSET,??
  • ????????????},??
  • ????????},??
  • #ifdef?CONFIG_ENV_OFFSET_REDUND??
  • ????????{??
  • ????????????.name?=?"redundant?NAND",??
  • ????????????.erase_opts?=?{??
  • ????????????????.length?=?CONFIG_ENV_RANGE,??
  • ????????????????.offset?=?CONFIG_ENV_OFFSET_REDUND,??
  • ????????????},??
  • ????????},??
  • #endif??
  • ????};??
  • ??
  • ????if?(CONFIG_ENV_RANGE?<?CONFIG_ENV_SIZE)??
  • ????????return?1;??
  • ??
  • ????res?=?(char?*)&env_new->data;??
  • ????len?=?hexport_r(&env_htab,?'\0',?0,?&res,?ENV_SIZE,?0,?NULL);??
  • ????if?(len?<?0)?{??
  • ????????error("Cannot?export?environment:?errno?=?%d\n",?errno);??
  • ????????return?1;??
  • ????}??
  • ????env_new->crc???=?crc32(0,?env_new->data,?ENV_SIZE);??
  • #ifdef?CONFIG_ENV_OFFSET_REDUND??
  • ????env_new->flags?=?++env_flags;?/*?increase?the?serial?*/??
  • ????env_idx?=?(gd->env_valid?==?1);??
  • #endif??
  • ??
  • ????ret?=?erase_and_write_env(&location[env_idx],?(u_char?*)env_new);??
  • #ifdef?CONFIG_ENV_OFFSET_REDUND??
  • ????if?(!ret)?{??
  • ????????/*?preset?other?copy?for?next?write?*/??
  • ????????gd->env_valid?=?gd->env_valid?==?2???1?:?2;??
  • ????????return?ret;??
  • ????}??
  • ??
  • ????env_idx?=?(env_idx?+?1)?&?1;??
  • ????ret?=?erase_and_write_env(&location[env_idx],?(u_char?*)env_new);??
  • ????if?(!ret)??
  • ????????printf("Warning:?primary?env?write?failed,"??
  • ????????????????"?redundancy?is?lost!\n");??
  • #endif??
  • ??
  • ????return?ret;??
  • }??
  • int saveenv(void) {int ret = 0;ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);ssize_t len;char *res;int env_idx = 0;static const struct env_location location[] = {{.name = "NAND",.erase_opts = {.length = CONFIG_ENV_RANGE,.offset = CONFIG_ENV_OFFSET,},}, #ifdef CONFIG_ENV_OFFSET_REDUND{.name = "redundant NAND",.erase_opts = {.length = CONFIG_ENV_RANGE,.offset = CONFIG_ENV_OFFSET_REDUND,},}, #endif};if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)return 1;res = (char *)&env_new->data;len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);if (len < 0) {error("Cannot export environment: errno = %d\n", errno);return 1;}env_new->crc = crc32(0, env_new->data, ENV_SIZE); #ifdef CONFIG_ENV_OFFSET_REDUNDenv_new->flags = ++env_flags; /* increase the serial */env_idx = (gd->env_valid == 1); #endifret = erase_and_write_env(&location[env_idx], (u_char *)env_new); #ifdef CONFIG_ENV_OFFSET_REDUNDif (!ret) {/* preset other copy for next write */gd->env_valid = gd->env_valid == 2 ? 1 : 2;return ret;}env_idx = (env_idx + 1) & 1;ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);if (!ret)printf("Warning: primary env write failed,"" redundancy is lost!\n"); #endifreturn ret; }

    定義env_t類型的變量env_new,準備來存儲env

    利用函數(shù)hexport_renv_htab操作,讀取env內(nèi)容到env_new->data

    校驗data,獲取校驗碼env_new->crc

    最后調(diào)用erase_and_write_envenv_new先擦后寫入由location定義的偏移量和長度的nand區(qū)域中。

    這樣就完成了env寫入nand的操作。

    在savenv readenv函數(shù)以及printenv setenv的實現(xiàn)函數(shù)中涉及到的函數(shù)himport_r hexport_r hdelete_r hmatch_r都是對env_htab哈希表的一些基本操作函數(shù)。

    這些函數(shù)都封裝在uboot的lib/hashtable.c中,這里就不仔細分析這些函數(shù)了。

    總結(jié)

    以上是生活随笔為你收集整理的uboot环境变量实现分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。