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

Posted 正在起飞的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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中如何确定启动方式》

以上是关于uboot中环境变量的加载写入过程详解的主要内容,如果未能解决你的问题,请参考以下文章

uboot配置和编译过程详解

ubuntu学习前传—uboot常见环境变量

2.4uboot配置和编译过程详解

uboot 放在哪里?

uboot启动过程详解

uboot————第二阶段start_armboot 函数详解