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 )都是對 RAM 中 env 的操作,只有在執(zhí)行 saveenv 時才會將 RAM 中的 env 重新寫入靜態(tài)存儲器中。
這種設計邏輯可以加快對env 的讀寫速度。
基于這種設計邏輯,2014.4 版本 uboot 實現(xiàn)了 saveenv 這個保存 env 到靜態(tài)存儲器的命令,而沒有實現(xiàn)讀取 env 到 RAM 的命令。
那我們就來看一下uboot 中 env 的數(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;?????????? #ifdef?CONFIG_SYS_REDUNDAND_ENVIRONMENT ??????unsigned?char ???flags;???????? #endif ??????unsigned?char ???data[ENV_SIZE];??? }?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 的一個 block 是 128K ,因此選用一個 block 來存儲 env , CONFIG_ENV_SIZE 為 128K 。
Env_t結(jié)構(gòu)體頭 4 個 bytes 是對 data 的 crc 校驗碼,沒有定義 CONFIG_SYS_REDUNDAND_ENVIRONMENT,所以后面緊跟data 數(shù)組,數(shù)組大小是 ENV_SIZE.
ENV_SIZE是 CONFIG_ENV_SIZE 減掉 ENV_HEADER_SIZE ,也就是 4bytes ,
所以env_t 這個結(jié)構(gòu)體就包含了整個我們規(guī)定的長度為 CONFIG_ENV_SIZE 的存儲區(qū)域。
頭4bytes 是 crc 校驗碼,后面剩余的空間全部用來存儲環(huán)境變量。
需要說明的一點,crc 校驗碼是 uboot 中在 saveenv 時計算出來,然后寫入 nand ,所以在第一次啟動 uboot 時 crc 校驗會出錯,
因為 uboot 從 nand 上讀入的一個 block 數(shù)據(jù)是隨機的,沒有意義的,執(zhí)行 saveenv 后重啟 uboot , crc 校驗就正確了。
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;??????????? ?????unsigned?long ?env_addr;?????????? ?????unsigned?long ?env_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 的初始化
uboot中 env 的整個架構(gòu)可以分為 3 層:
(1)?命令層,如saveenv , setenv?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_sequence 的 env_init ,這個函數(shù)是不同存儲器實現(xiàn)的函數(shù), nand 中的實現(xiàn)如下:
[cpp] view plaincopyprint?
<span?style="font-size:14px;" >? ? ? ? ? ? ? ? ? ? ? ?? 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 相關變量進行配置,
默認設置 env 為 valid 。方便后面 env_relocate 函數(shù)進行真正的 env 從 nand 到 ram 的 relocate 。
繼續(xù)執(zhí)行,在board_init_r 中,如下:
[cpp] view plaincopyprint?
?? ????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?
? ? ? ? ? ? ? ? ? ? ?? 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 沒有定義,鑒于考慮安全性問題,如果我們想要推遲 env 的 load ,可以定義 CONFIG_DELAY_ENVIRONMENT, 這里返回 0 ,就調(diào)用 set_default_env 使用默認的 env ,默認 env 是在配置文件中 CONFIG_EXTRA_ENV_SETTINGS設置的。
我們可以在之后的某個地方在調(diào)用env_relocate 來 load?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) ???????????? ????????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_SIZE 的 buf ,然后調(diào)用 readenv ,
CONFIG_ENV_OFFSET 是在配置文件中定義的 env 在 nand 中偏移位置。我們這里定義的是在 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?
? ? ? ?? 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)
Uboot對 env 的操作命令實現(xiàn)在 common/cmd_nvedit.c 中。
對于setenv?printenv?editenv 這 3 個命令,看其實現(xiàn)代碼,都是對 relocate 到 RAM 中的 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;??? ????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)?{?? ?????????? ????????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_r 對 env_htab 操作,讀取 env 內(nèi)容到 env_new->data ,
校驗data ,獲取校驗碼 env_new->crc 。
最后調(diào)用erase_and_write_env 將 env_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)容還不錯,歡迎將生活随笔 推薦給好友。