学习目标:
1、分析u-boot-1.1.6环境变量,了解环境变量初始化、设置以及过程
2、为后面能够掌握u-boot-1.1.6如何启动内核过程打下基础
1、环境变量的概念
在分析uboot环境变量的源码实现之前,先介绍一下环境变量的概念。u-boot通过环境变量为用户提供一定程度的可配置性,在不改变源码、不重新编译的情况下,可以通过设置环境变量的值来改变uboot的一些设置,如bootdelay时间,内核启动命令参数等。可配置性意味着环境变量是可以添加、删除和修改的,也就是说环境变量的内容可能会频繁变化,为了不让这种变化对u-boot的代码和数据造成破坏,通常的选择是在FLASH中预留一个专门用来存储环境变量的块。开发者在串口终端输入setenv命令可以设置环境量值,设置完成后使用saveenv命令将setenv命令设置好的环境变量保存在非易失存储器中。如下图所示,使用uboot时, 在串口终端输入printenv命令便能够打印uboot中的环境变量值。
2、环境变量的数据结构
#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE) typedef struct environment_s { unsigned long crc; /* CRC32 over data bytes */ #ifdef CFG_REDUNDAND_ENVIRONMENT unsigned char flags; /* active/obsolete flags */ #endif unsigned char data[ENV_SIZE]; /* Environment data */ } env_t;
crc变量保存上一次环境变量数据写入flash时做crc运算的结果,当重新从flash中读取环境变量值时,代码会对读取数据进行crc校验,并将新的校验的值与上次保存的值进行比较,如果两次crc校验值相同,表示存放在flash中的环境变量正常,否则,表示存放环境变量数据损坏。
数组data[ENV_SIZE]保存环境变量的值,环境变量名已经环境变量值以字符形式存放在内存中
3、环境变量的初始化
int env_init(void) { /* 未定义CONFIG_OMAP2420H4,此处代码不被编译 */ #ifdef CONFIG_OMAP2420H4 int flash_probe(void); if(flash_probe() == 0) goto bad_flash; #endif /* env_t *env_ptr = (env_t *)CFG_ENV_ADDR, 此处执行吗?,如果此处执行 */ /* 先进入nor flash读取环境变量,通过CRC检测读取环境变量是否正确 */ if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { gd->env_addr = (ulong)&(env_ptr->data); gd->env_valid = 1; return(0); } /* 未定义CONFIG_OMAP2420H4,此处代码不被编译 */ #ifdef CONFIG_OMAP2420H4 bad_flash: #endif /* CRC校验后读取环境变量不正确,此处执行,使用默认环境变量 */ gd->env_addr = (ulong)&default_environment[0]; gd->env_valid = 0; return (0); }
int env_inti(void)函数在uboot代码第二阶段入口函数start_armboot开始处被调用。首先,env_init函数从存放环境变量的flash内存地址中读取环境变量的值,并且对读出的环境变量数据进行crc校验,将新校验的crc值与写入环境变量时的crc校验值进行比较。如果两个值相等,将读取数据的地址赋值给gd指针执行的全局数据结构中的env_addr成员,并将env_valid标志位置位。如果读取环境变量校验值和写入时的校验值不同,存储在flash中的环境变量值损坏,将默认环境变量值赋给gd指针执行的全局数据结构中的env_addr成员。
env_ptr指针指向环境变量存放初始地址,env_t *env_ptr = (env_t *)CFG_ENV_ADDR。CFG_ENV_ADDR是一个宏,代表环境变量在flash中存放的地址,由于我配置uboot时目标板是smdk2410,所以该宏存放在include/configs/smdk2410.h头文件中。默认环境变量值如下所示:
uchar default_environment[] = { #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "