uboot中环境变量的加载、写入过程详解

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中如何确定启动方式》

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值