1、uboot启动中环境变量的加载
1.1、uboot加载环境变量流程分析
(1)首先使用默认的环境变量default_environment[];
(2)然后加载SD卡中env分区的环境变量,校验读出来的环境变量分区是否正确;
(3)如果CRC校验通过则使用SD中读出来的环境变量,校验不通过则使用默认的环境变量;
补充:对环境变量不熟悉的建议阅读博客:《uboot中环境变量的实现》;
1.2、函数调用关系
start_armboot()
env_init()--init_sequence[]
env_relocate()
env_relocate_spec ()
env_relocate_spec_movinand()
movi_read_env()
use_default()
mmc_bread()
1.3、源码分析
//uboot中存放环境变量的结构体
typedef struct environment_s {
ulong crc; /* CRC校验和 */
unsigned char flags; /* active or obsolete */
char *data; /* 环境变量的值 */
} env_t;
//先使用默认环境变量
int env_init(void)
{
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
return (0);
}
//加载外存中的环境变量
void env_relocate (void)
{
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
if (gd->env_valid == 0)
{
puts ("*** Warning - bad CRC, using default environment\n\n");
show_boot_progress (-60);
set_default_env();
}
else {
env_relocate_spec (); //从SD卡中加载环境变量
}
//最终gd->env_addr都是指向的env_ptr->data
gd->env_addr = (ulong)&(env_ptr->data);
}
//路径:./common/env_auto.c
void env_relocate_spec(void)
{
//判断开发板的启动介质,去相应的启动介质读取环境变量
if (INF_REG3_REG == 1)
env_relocate_spec_onenand();
else if (INF_REG3_REG == 2)
env_relocate_spec_nand();
else if (INF_REG3_REG == 3)
env_relocate_spec_movinand();
else if (INF_REG3_REG == 4)
env_relocate_spec_nor();
else
use_default();
}
//从iNand/SD卡读取环境变量
void env_relocate_spec_movinand(void)
{
uint *magic = (uint*)(PHYS_SDRAM_1);
//magic[0]和magic[1]是存放的魔术,在其他地方会设置这个值
if ((0x24564236 != magic[0]) || (0x20764316 != magic[1])) {
movi_read_env(virt_to_phys((ulong)env_ptr));
}
//校验读出来的环境变量,如果不成功就用默认的环境变量
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();
}
//根据分区表读取env分区,存放到env_ptr变量中
void movi_read_env(ulong addr)
{
movi_read(raw_area_control.image[2].start_blk,
raw_area_control.image[2].used_blk, addr);
}
//从SD卡通道0读取环境变量,就是内接的iNand,这里代码写死了环境变量是放在iNand中的
ulong movi_read(ulong start, lbaint_t blkcnt, void *dst)
{
return mmc_bread(0, start, blkcnt, dst);
}
//当从env分区读出来的环境变量CRC校验失败时,就是用默认的环境变量default_environment[]
static void use_default()
{
puts("*** Warning - using default environment\n\n");
if (default_environment_size > CFG_ENV_SIZE) {
puts("*** Error - default environment is too large\n\n");
return;
}
memset (env_ptr, 0, sizeof(env_t));
memcpy (env_ptr->data,
default_environment,
default_environment_size);
env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
gd->env_valid = 1;
}
(1)环境变量的地址存放在变量gd->env_addr中,gd全局变量参见博客:《uboot中重要的全局变量——gd》;
(2)实际上gd->env_addr == (ulong)&(env_ptr->data),但是env_ptr->data可以指向默认环境变量default_environment[]或者从SD卡读取的环境变量;
(3)raw_area_control.image[2]里保存的是环境变量分区的信息,具体参见博客:《X210开发板(S5PV210芯片)uboot中SD卡分区分析(init_raw_area_table函数)》;
(4)将[INF_REG_BASE+INF_REG3_OFFSET]地址处的值取出来放在INF_REG3_REG变量中,然后判断当前的启动方式,这个地址的值是在_star汇编函数中根据启动方式写入的。参加博客:《嵌入式开发(S5PV210)——u-boot中如何确定启动方式》;
2、saveenv命令的代码调用关系
do_saveenv
saveenv
saveenv_movinand
movi_write_env
movi_write
mmc_bwrite
2.1、源码分析
#define __REG(x) (*(vu_long *)(x))
#define INF_REG3_REG __REG(INF_REG_BASE+INF_REG3_OFFSET)
//路径:./common/env_auto.c
int saveenv(void)
{
if (INF_REG3_REG == 2)
saveenv_nand();
else if (INF_REG3_REG == 3) //开发板接的iNand/SD卡,所以INF_REG3_REG == 3
saveenv_movinand();
else if (INF_REG3_REG == 1)
saveenv_onenand();
else if (INF_REG3_REG == 4)
saveenv_nor();
else
printf("Unknown boot device\n");
return 0;
}
//从外存中读取环境变量保存到env_ptr变量中
int saveenv_movinand(void)
{
movi_write_env(virt_to_phys((ulong)env_ptr));
puts("done\n");
return 1;
}
void movi_write_env(ulong addr)
{
movi_write(raw_area_control.image[2].start_blk,
raw_area_control.image[2].used_blk, addr);
}
ulong movi_write(ulong start, lbaint_t blkcnt, void *src)
{
//第一个参数是0,说明从SD卡通道0去读环境变量,这在代码里写死了
//start:开始读取的扇区数
//blkcnt:要写入的扇区个数
//src:将从SD卡读取到的数据加载到该地址处
return mmc_bwrite(0, start, blkcnt, src);
}
(1)saveenv命令的实现参见博客:嵌入式开发——uboot中命令体系详解;
(2)raw_area_control.image[2]里保存的是环境变量分区的信息,具体参见博客:《X210开发板(S5PV210芯片)uboot中SD卡分区分析(init_raw_area_table函数)》;
(3)将[INF_REG_BASE+INF_REG3_OFFSET]地址处的值取出来放在INF_REG3_REG变量中,然后判断当前的启动方式,这个地址的值是在_star汇编函数中根据启动方式写入的。参加博客:《嵌入式开发(S5PV210)——u-boot中如何确定启动方式》;