uboot中环境变量的实现

1、环境变量介绍

uboot中环境变量的作用类似于全局变量,需要某个环境变量的值时调用getenv函数就可以得到。环境变量会指导程序的运行,不必修改代码重新编译,通过修改环境变量就可以改变uboot的的数据和特性。在uboot启动时bootdelay时间内按下按键就可以打断uboot的启动进入控制台,输入printenv命令就可以查看当前的环境变量,setenv可以改变环境变量的值,如果没有saveenv则修改只有本次启动有效,因为修改的是DDR里的那一份环境变量。

2、环境变量在内存中的保存形式

	bootdelay=3`\0`bootcmd=movi read kernel 30008000; movi read rootfs 30B00000 300000; bootm 30008000 30B00000`\0`.........

环境变量是类似于数组,一个接着一个加载在某段内存中,其中该段内存的起始地址保存在全局变量gd->env_addr中。每个环境变量之间以反斜杠零(\0)作为分隔符(也就是字符串的末尾符),在遍历环境变量时去找反斜杠零(\0)就可以将每个环境变量分隔开,而每个环境变量的格式也是固定的,
格式:env=value,再根据等号作为分隔符区分环境变量的名字和数值。只要拿到保存环境变量的内存起始地址,就可以解析出所有的环境变量。

3、默认环境变量和SD卡中的环境变量

环境变量在代码里有一份默认的环境变量,是用数组来实现的;在SD卡/flash等外存也存在一份,uboot会加载到内存中。首先是调用env_init函数,暂时使用默认的环境变量;后续再调用env_relocate函数将SD卡中的那一份环境变量加载到内存中,如果CRC校验通过则将gd->env_addr指向内存中从SD卡处加载的环境变量。由此可见,SD卡中的环境变量优先级高于默认的环境变量。

//初始化默认环境变量,保存在default_environment数组中
int env_init(void)
{
	gd->env_addr  = (ulong)&default_environment[0];
	gd->env_valid = 1;

	return (0);
}

char * env_ptr;

//从SD卡中重定位环境变量
void env_relocate (void)
{
	/*
	 * We must allocate a buffer for the environment
	 */
	env_ptr = (env_t *)malloc (CFG_ENV_SIZE); //申请CFG_ENV_SIZE大小的内存,此时已经初始化了堆管理器,所以可以用malloc
	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 (); //把外存里的环境变量加载到内存,并将内存起始地址保存在env_ptr->data
	}
	gd->env_addr = (ulong)&(env_ptr->data);
}

void env_relocate_spec (void)
{
	uint *magic = (uint*)(PHYS_SDRAM_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) //crc校验不通过则用默认的环境变量
		return use_default();
}

4、关键函数的实现思路

前提:从gd->env_addr得到环境变量在内存中的地址,并且uboot中有变量记录当前所有环境变量所占内存大小
(1)printenv思路分析:
以反斜杠零为分隔符解析处各个环境变量,然后通过控制台输出;
(2)setenv思路分析
首先通过以反斜杠零和等号为分隔符,解析处各个环境变量的名字和数值,然后去匹配是否存在要查找的环境变量,如果存在则覆盖掉原来的值;
(3)saveenv思路分析
将内存中的那份环境变量写到SD卡中特定的分区里;
(4)getenv思路分析
首先通过以反斜杠零和等号为分隔符,解析处各个环境变量的名字和数值,然后去匹配是否存在要查找的环境变量,如果存在则返回该环境变量的值;

5、可重入版本和不可重入版本的函数

可重入版本函数的名字就是在不可重入版本函数的名字后面加"_r",因为可重入版本是在不可重入版本后面出现的。不可重入函数,简单理解就是函数不能同时多个地方调用或者同时调用不安全。
(1)char *getenv (char *name);
传入环境变量的名字返回环境变量字符串所在的内存地址;如果修改返回来的环境变量字符串内容,则内存中的环境变量也会被修改,这样不安全。
(2)int getenv_r (char *name, char *buf, unsigned len);
传入环境变量的名字name,缓冲区buf,buf的长度len,返回读取到的环境变量字符串的长度。环境变量的值是保存在buf中,无论你怎么修改buf中保存的环境变量字符串也不会影响内存中的环境变量。

6、补充

在SD卡中会预留出分区来保存环境变量,在uboot的配置文件里会用宏定义来指定环境变量保存在SD卡里起始块和块数量的信息。参见博客:《uboot中环境变量的加载、写入过程详解》

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

正在起飞的蜗牛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值