1.相关文件
common/env_common.c
供u-boot调用的通用函数接口,它们隐藏了env的不同实现方式,比如dataflash,epprom, flash等
common/env_dataflash.c
env 存储在dataflash中的实现
common/env_epprom.c
env 存储在epprom中的实现
common/env_flash.c
env 存储在flash中的实现
common/env_nand.c
env 存储在nand中的实现
common/env_nvedit.c
实现u-boot对环境变量的操作命令
environment.c
环境变量以及一些宏定义
env如果存储在Flash中还需要Flash的支持。
2.数据结构
env 在 u-boot中通常有两种存在方式,在永久性存储介质中( Flash NVRAM等 )在SDRAM,可以配置不使用 env的永久存储方式,但这不常用。u-boot 在启动的时候会将存储在永久性存储介质中的 env 重新定位到 RAM中,这样可以快速访问,同时可以通过saveenv 将 RAM 中的 env 保存到永久性存储介质中。
在include/environment.h中定义了表示env的数据结构
typedef struct environment_s
{
#ifdef CFG_REDUNDAND_ENVIRONMENT
#endif
} env_t;
关于以上结构的说明:
crc是u-boot在保存env的时候加上去的校验头,在第一次启动时一般 crc校验会出错,这很正常,因为这时 Flash中的数据无效。
data字段保存实际的环境变量。u-boot 的 env 按name=value”\0”的方式存储,在所有env的最后以”\0\0”表示整个 env的结束。新的name=value对总是被添加到 env数据块的末尾,当删除一个name=value对时,后面的环境变量将前移,对一个已经存在的环境变量的修改实际上先删除再插入。
env 可以保存在 u-boot 的TEXT 段中,这样 env 就可以同 u-boot 一同加载入RAM中,这种方法没有测试过。
typedef struct global_data
{
} gd_t;
<include/asm-arm/Global_data.h>
gd_t.env_addr 即指向env_ptr->data。
3.ENV的初始化
start_armboot : ( lib_arm/board.c)
*env_init : env_xxx.c( xxx = nand | flash |epprom … )
env_relocate : env_common.c
*env_relocate_spec : env_xxx.c( xxx=nand |flash | eporom… )
3.1env_init
实现 env 的第一次初始化,对于nand env(非embedded方式):
Env_nand.c : env_init
gd->env_addr =(ulong)&default_environment[0];//先使gd->env_addr指向默认的环境变量
gd->env_valid = 1;// env有效位置1
3.2 env_relocate
#ifdefine ENV_IS_EMBEDDED
…(略)
#else
env_ptr = (env_t *)malloc(CFG_ENV_SIZE);
#endif
if( gd->env_valid == 0) // 在Env_annd.c : env_init 中已经将 gd->env_valid置1
{
}
else
gd->env_addr =(ulong)&(env_ptr->data);//最终完成将环境变量搬移到内存
这里涉及到两个和环境变量有关的宏
ENV_IS_EMBEDDED : env 是否存在于 u-boot TEXT段中
CFG_ENV_SIZE : env 块的大小
实际上还需要几个宏来控制u-boot 对环境变量的处理
CFG_ENV_IS_IN_NAND : env 块是否存在于Nand Flash中
CFG_ENV_OFFSET : env 块在 Flash中偏移地址
3.3*env_relocate_spec
这里仅分析 Nand Flash 的 env_relocate_spec实现
如果未设置CFG_ENV_OFFSET_REDUND,env_relocate_spec的实现如下 :
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
#endif
}
上面的代码很清楚的表明了 env_relocate_spec 的意图,调用 nand_read将环境变量从 CFG_ENV_OFFSET 处读出,环境变量的大小为 CFG_ENV_SIZE 注意 CFG_ENV_OFFSET和CFG_ENV_SIZE 要和 Nand Flash 的块/页边界对齐。读出数据后再调用crc32对env_ptr->data 进行校验并与保存在 env_ptr->crc的校验码对比,看数据是否出错,从这里也可以看出在系统第一次启动时,Nand Flash里面没有存储任何环境变量,crc校验肯定回出错,当我们保存环境变量后,接下来再启动板子u-boot就不会再报crc32出错了。
4. ENV的保存
由上问的论述得知, env 将从永久性存储介质中搬到RAM里面,以后对env的操作,比如修改环境变量的值,删除环境变量的值都是对这个 env在RAM中的拷贝进行操作,由于RAM的特性,下次启动时所做的修改将全部消失,u-boot提供了将env 写回 永久性存储介质的命令支持: saveenv,不同版本的 env ( nand flash, flash … )实现方式不同,以Nand Flash的实现(未定义CFG_ENV_OFFSET_REDUND)为例
Env_nand.c : saveenv
int saveenv(void)
{
}
Nand Flash 的 saveenv 命令实现很简单,调用nand_erase和nand_write进行Nand Flash的 erase, write。nand_write/erase使用的是u-boot的nand驱动框架,我在做开发的过程中使用的是nand_legacy驱动,所以可以把nand_erase和nand_write改成nand_legacy_erase和nand_legacy_rw就可实现nand_legacy驱动的保存环境变量版本。