9、1、uboot的环境变量
1、环境变量的作用
(1)在我们不改变uboot源代码的情况下,只需要改变环境变量的值就可以改变uboot运行时的数据和一些特性。比如说,通过修改bootdelay环境变量,就可以更改开机倒数的秒数。
2、环境变量的优先级
(1)uboot代码当中有一个值,环境变量(DDR 环境变量的分区中)中也有一个值,uboot程序实际运行时,规则是,如果环境变量(DDR中环境变量的分区)为空,则使用代码中的环境变量的值,如果环境变量不为空,优先使用环境变对应的值。
(2)比如说我们的machid(机器码),我们uboot中,在x210_sd.h中,定义了一个机器码2456,这个是写死在程序中的,所以我们在开机的时候是可以看到这个环境变量的,用bdinfo来看。如果要修改uboot中配置的机器码,可以修改x210_sd.h中的机器码,但是修改源代码后需要重新编译烧录,很麻烦,比较简便的方法就是使用环境变量machid即可。把环境变量machid设置成别的 set machid xxx 设置好后,系统在启动时,会优先使用machid环境变量中的值。
3、环境变量在uboot中的工作方式
(1)当一个uboot镜像刚开始烧录到一个SD卡上的时候,第一次烧录的时候,SD卡上的环境变量分区是空的。所以将来重定位到了DDR中去运行的时候,DDR中的环境变量分区也是空的,所以这个时候会使用uboot代码中默认的环境变量,当我们将改变环境变量后,在saveenv保存环境变量的时候,这个时候会将环境变量保存到了SD卡的环境变量的分区上去。当我们在此启动的时候,在将sd卡的环境变量分区重定位到DDR中的时候,环境变量在内存就有了,所以就会使用内存中的这一份环境变量。
(2)默认环境变量在uboot/common/env_comon.c中的default_environment,这个东西就是一个字符数组,里面的内容就是很多个环境变量连续分布组成的,每个环境变量的末端用'\0'作为结束符。
(3)DDR中的环境变量,在default_environment中,实质是字符数组,在uboot中其实是一个全局变量,链接时在数据段的,重定位的时候就重定位到了DDR中的一个内存地址中去了。这个地址处放的就是我们uboot在运行的时候的环境变量了。
在重定位的时候,程序会去检查SD卡的env分区中是否有环境变量,会进行CRC校验,如果检验通过了,SD卡的env'分区有环境变量,那么就会将SD卡中的这一份环境变量会覆盖default_environment中的环境变量,
9、2、环境变量相关命令的源码分析1
1、printenv
(1)分析do_printenv函数
(2)在do_printenv函数中可以看出来,如果argc=1的话,就会打印出来所有的环境变量,如果argc不等于1就会只打印出来我们我要打印出来的环境变量。
(3)argc=1时,就会执行那个三重for循环,第一重for循环就是处理所有的环境变量,你有多少了个环境变量,那么第一重的for循环就会循环多少次。
(4)这个函数要看明白,首先要明白环境变量在内存中是怎么存储的问题,根据代码和上节课将到的default_enironment字符数组,知道,环境变量在内存中是以一个字符数组的形式存储的,每个环境变量的名到他的值都是连续的字符,一个环境变量的名字和值结束后就会有一个'\0'来标志这第一个环境变量的字符结束了,接着要在内存中接着放第二个环境变量的字符一次挨着放的,每个环境变量的结束分割是'\0',所以代码中,可以用'\0'这个标志,来区分我们在内存中读取字符时,读取到哪个位置表示一个环境变量读取完了,可以接着读取下一个了。
9、3、环境变量相关命令的源码分析2
1、setenv
(1)_do_setenv (flag, argc, argv);//没有下划线的表示可以自己用的,一个下划线表示系统自己用的,两个下划线的表示系统内部自己用的,三个下划线开头表示我们就不要碰了
}
(2)setenv的思路,先去DDR中去寻找有没有这个环境变量,如果有,则覆盖这个环境变量,如果没有则在最后新增一个环境变量,
第一步:遍历DDR中环境变量的字符数组,找到原来就有的那个环境变量对应的地址 168-174行
第二部:去擦除原来的环境变量在_do_setenv 259-265行
第三步:写入新的环境变量 266-273行
本来setenv做完上面的就完事了,但是还要考虑一些附加的问题,
问题1、就是环境变量太多,超出了DDR中环境变量的分区,这时就溢出了,
问题2,有些环境变量,如bundrate,在gd中有对应的全局变量,这种环境变量在set的时候,还要对应的更新对应的全局变量,否则就会出现在本次运行中,环境变量和全局变量不一致的情况。
9、4、环境变量相关命令的源码分析3
1、saveenv
(1)我们的uboot执行saveenv的函数是在env_aotu.c中那个do_saveenv函数,为什么是这个文件中的这个函数呢,是由在x210_sd.h中那个#define CFG_ENV_IS_IN_AUTO宏来配置的,aotu的意思就是自动适配的,在do_saveenv函数中开始的部分,有一个寄存器(这个寄存器是用户自定的寄存器,是在start.S中往里面写值的)来判断我们是从哪个介质中启动的,从哪个介质中启动,就执行哪个对应的函数,我们的SD卡启动的,所以对应的实际上应该是movinand(因为movinand就是inand,而inand的操作和SD卡的操作很像inand就是小版的sd卡可以这么理解,因为板子上的inand是是接在SD卡通道0的,SD通道2和3是接SD卡的,可以看出来其实两者很像)。
(2)用户自定义信息的寄存器E010_F00C,这个寄存器中实现在start.S中,开始时由一个寄存器判断出了是从哪个启动介质启动,完了之后,我们相应的在这个用户自定义信息的寄存器中存储了我们从哪种介质启动的信息标志,由于我们是SD卡启动,我们无法从那个寄存器中知道我们是哪种启动方式,我们只能通过实际来知道,因为那个寄存器三星给的数据手册中没有。由这个用户自定寄存器中的值在我们的env_aotu.c中的do_saveenv函数中开始的部分去进行判断执行哪个保存环境变量的函数,最后我们确定是调用的saveenv_movinand这个函数去保存我们的环境变量的。
(3)真正执行保存环境变量的函数是这个movi_write_env,将环境变量从DDR中写入到,保存到SD/iNand中,实际上就是将内存中的那个default_enironment字符数组保存到了SD/iNand中,大小是16KB,刚好就是32个扇区(一个扇区512B)。
(4)raw_area_control是uboot中规划inand/sd卡的原始分区表,env分区就记录在这里,
9、5、uboot内部获取环境变量
1、getenv
(1)getenv,应该是不可重入函数
(2)实现方式就是去遍历default_enironment这个字符数组,也就是遍历DDR中内存中放env的那部分内存里面的字符。
去和name相比较,如果找到了,就返回这个环境变量的首地址
2、getenv_r
(1)可重入函数。(你用的时候,没有破坏原来的内存中那一份,别人用的时候,内存中的那一份还是好的)
(2)这个函数,是在DDR中找到那一个环境变量后,将他的值放到了一个buf中,而getenv函数是将那个环境变量的值在DDR中对应的内存地址返回回来,改的话,就直接改了DDR中环境变量的那一份,而getenv_r改的值的话,改的是buf中的那一份,为的是当发送中断,或者在多线程的情况下,你getenv的话执行,在别人想用这个值的是,可是已经被你改掉了,有可能会无意的改动了内存中值,而放在了buf中的话,当发生这种情况的话,内存中的那一份的值还是好好的,当别人想用的时候还可以得到内存中完好的那一份的值。
总结:
功能是一样的,但是可重入版本是安全一些的,建议应该使用这个、
有关于环境变量的所有操作,只要理解了环境变量在DDR中的存储方法,理解了环境变量和我们gd全局变量的关联,和优先级,理解了环境变量在存储介质中的存储方式(就是我们专用的分区),那么整个环境变量相关的就都清楚了。