历史上的今天
返回首页

历史上的今天

今天是:2025年02月22日(星期六)

2021年02月22日 | cortex-a8 uboot系列:第十四章 uboot环境变量

2021-02-22 来源:eefocus

一、Uboot的环境变量基础

1.环境变量的作用

让我们可以不用修改uboot的源代码,而是通过修改环境变量来影响uboot运行时的一些数据和特性。如修改bootdelay环境变量就可以更改系统开机自动启动时倒数的秒数。


2.环境变量的优先级

Uboot代码中有一个值,环境变量中也有一个值。Uboot程序实际运行时规则是:如果环境变量为空则使用代码中的值;如果环境变量不为空则优先使用环境变量对应的值。


3.环境变量在uboot中工作方式

默认环境变量,在common/env_common.c中default_environment中。default_environment是一个字符数组,大小为CFG_ENV_SIZE(16K),里面内容就是很多个环境变量连续分布组成的,每个环境变量最末端以’’分隔。


Gcc编译器会自动将多个字符串连接成一个字符串。也就是"bootargs="CONFIG_BOOTARGS"",gcc会将之变成” bootargs= console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3”

clip_image002

 

SD卡中环境变量分区,在uboot的raw分区中。SD卡中其实就是给了个分区,专门用来存储而已。存储时其实是把DDR中的环境变量整体的写入到SD卡中分区里。当saveenv时其实整个所有的环境变量都被保存了一遍,而不是只保存更改的。

 

DDR中环境变量,在default_environment中,实质是字符数组。在uboot中其实是一个全局变量,链接时在数据段,重定位时default_environment就被重定位到DDR中一个内存地址处。这个地址处这个全局字符数组就是uboot运行时的DDR中的环境变量了。

 

4.总结:

刚烧录的系统环境变量是空白的,uboot第一次运行时加载的是uboot代码中自带的一份环境变量,叫默认环境变量。在saveenv时DDR中的环境变量会被更新到SD卡中的环境变量中,就可以被保存下来,下次开机会在环境变量relocate时会被SD卡中的环境变量会被加载到DDR中。


default_environment中的内容虽然被uboot源代码初始化为一定的值,但是在uboot启动的第二阶段,env_relocate时代码会去判断SD卡中的env分区的CRC是否通过。如果CRC通过说明SD卡中有正确的环境变量存储,则relocate函数会将SD卡中读取环境变量来覆盖default_environment字符数组,从而每次开机可以保持上一次更改过的环境变量。


二、环境变量相关命令

1.printenv

clip_image004

Uboot中输入printenv后,其实是执行函数do_printenv,common/cmd_nvedit.c中。

 

clip_image006

先判断输入的参数,如果为1个,说明是打印所有的环境变量。就循环打印所有的环境变量出来。


用双重for循环,来依次处理所有环境变量的打印。第一层for循环,就是处理各个环境变量。所以有多少个环境变量就会循环多少次。第二层for循环,就处理单个环境变量的打印。

         clip_image008

因此default_environment数组是很长的一个字符数组,中间以作为环境变量的间隔。

 


第一层循环,用来循环各个环境变量。第二个循环,用来处理每个环境变量。当for (nxt=i; env_get_char(nxt) != ''; ++nxt);执行完毕后,nxt就指向了当前处理环境变量在数组中的索引处。而环境变量的开始索引保存在i中。


然后在第三个循环,将i和nxt之间的数组内容打印出来,也就是环境变量的内容。打印完毕后,判断是否有按下ctrl+c,有的话,就退出。否则就处理下一个环境变量。


最后i的值就是环境变量的个数。

clip_image010

env_get_char函数(common/env_common.c),获取default_environment数组下标为index的值。


判断目前状态是否已经是重定位了,重定位后,就从内存保存的环境变量中读取。如果没有重定位,就从默认的环境变量保存处读取。


如果argc不为1,说明是打印特定环境变量的值,就打印参数的环境变量。


如:  printenv  bootdelay  serverip  gateway

那么 argc=3,  argv[0] = bootdelay

argv[1] = serverip

argv[2] = gateway

clip_image012

第一层循环,处理输入要打印的各个环境变量,argv[i]就保存了第i个要打印环境变量的值。


首先通过通过两层循环,获取到各个环境变量在default_environment数组中的起始索引和结束索引。然后去判断得到的环境变量和需要打印的环境变量是否一致,是的话,就打印,否则就处理下一个要打印的命令。


2. setenv

设置环境变量的值。

clip_image014

对应的函数do_setenv(common/cmd_nvedit.c中)

clip_image016

函数判断输入参数,输入参数必须要大于2个。大于的话,就调用_do_setenv函数(common/cmd_nvedit.c中)。

         clip_image018

通过env_get_addr(0)函数(common/env_common.c),获取到环境变量数组中第一个环境变量的地址。

clip_image020

         clip_image022

如果返回地址为0,说明环境变量还没有拷贝到内存中,直接返回1。

 clip_image024

argv[1]为输入setenv的第一个参数,也就是要设置的环境变量名,保存在name中。如果在参数中有=号,提示错误信息,并返回。


strchr函数,从字符串s中,寻找字符c,找到,返回字符c的地址,没有找到,返回NULL。

         clip_image026

 

clip_image028

env_data是环境变量数组的首地址,env在每个循环后指向下一个环境变量的起始地址。env - env_data的值是上一个环境变量在数组中所占的空间大小。

        

clip_image030

Envmatch函数(common/cmd_nvedit.c)在环境变量数组中从索引i2开始查找在=号前的内容是不是和字符串s1匹配,匹配的话,返回i2的值,否则返回-1。

 

clip_image032

如果找到,需要将原来定义的环境变量给删除掉,也就是将原来环境变量的内容都给清成。这里先判断输入的环境变量是不是serial#和ethaddr这两个变量,是的话,提示错误信息,然后返回1。

clip_image034

判断是不是修改stdin、stdout、stderr这三个环境变量。


setenv思路:

先去DDR中的环境变量处找有没有这个环境变量,如果有则需要覆盖原来的环境变量,如果没有则在最后新增一个环境变量即可。

第一步:遍历DDR中环境变量的数组,找到环境变量对应的地址

第二步:擦除原来的环境变量

第三步:写入新的环境变量

 

还需要考虑其他一些问题:

问题1:环境变量太多超过DDR中的字符数组,溢出的解决方法

问题2:有些环境变量如baudrate、ipaddr等,在gd中有对应的全局变量。这种环境变量在set更新的时候要同时去更新对应的全局变量,否则就会出现在本次运行中环境变量和全局变量不一致的情况。


3.saveenv

定义在common/cmd_nvedit.c中。

clip_image036

使用的方法是do_saveenv

 

clip_image038

 

env_name_spec在common/env_auto.c中定义

clip_image040

 

最后调用saveenv函数(common/env_auto.c),判断启动方式,然后在不同的启动介质中保存环境变量。

clip_image042

 

clip_image044

INF_REG寄存器是s5pv210提供给用户的寄存器。这里是用的REG3。

clip_image046

在之前的启动中,uboot将启动介质信息保存到了INFORM3寄存器中,这里读取这个寄存器,就知道了板子从什么启动介质启动。因此就可以确定将环境变量保存到什么地方去。


对于九鼎x210开发板,使用的是SD卡/iNand卡启动,属于movinand,因此执行的是saveenv_movinand函数(common/env_auto.c中)。

clip_image048

调用movi_write_env函数(cpu/s5pc11x/movi.c中),调用movi_write函数将环境变量写入到外部NAND中。

clip_image050

raw_area_control是uboot中规划iNand/SD卡的原始分区表,这个里面记录了对iNand的分区,env分区也在这里,下标是2。

movi_write函数(drivers/mmc/mmc.c中),三个参数,第一个参数是外部存储设备的起始扇区,第二个参数是要写的扇区块数,第三个是保存写的数据的内存首地址。

clip_image052

 

最终调用mmc_bwrite函数(drivers/mmc/mmc.c中)执行写数据操作。4个参数,第一个参数是设备号,第二个是写的起始扇区,第三个参数是写的扇区块数,第四个参数是写的数据的内存首地址。


对于九鼎x210开发板,默认使用外部的iNand启动,所以第一个参数为0,表示写入到外部的iNand中。

clip_image054

4.getenv

获取环境变量的内容。

clip_image056

依然使用两个for循环,来依次去查找环境变量数组中的各个环境变量,然后进行匹配,匹配成功的话,返回环境变量的首地址。


5.gentenv_r

获取环境变量的内容

clip_image058

使用两个for循环,去遍历环境变量数组中的各个环境变量,匹配的话,就将环境变量写入到buf中。

 

两个函数的区别:

getenv函数是直接返回这个环境变量在DDR中环境变量处的地址,而getenv_r函数的做法是找到了DDR中环境变量地址后,将这个环境变量复制一份到提供的buf中,而不动原来DDR中环境变量。


所以getenv中返回的地址只能读不能随便写,而getenv_r中返回的环境变量是在自己提供的buf中,可以随意改写。

 

总结:

功能是一样的,但是getenv_r会比较安全一些,建议使用。

有关于环境变量的所有操作,主要理解了环境变量在DDR中的存储方法,理解了环境变量和gd全局变量的关联和优先级,理解了环境变量在存储介质中的存储方式(专用raw分区),整个环境变量相关的都比较容易理解了。

推荐阅读

史海拾趣

BCD Semi(Diodes)公司的发展小趣事

在追求经济效益的同时,BCD Semi(Diodes)公司也积极履行企业社会责任,关注可持续发展。公司严格遵守环保法规,采用环保材料和工艺,减少生产过程中的污染排放。同时,公司还积极参与社会公益事业,为当地社区的发展做出贡献。这些举措不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实基础。

请注意,以上故事是基于电子行业的一般情况和BCD Semi(Diodes)公司的行业地位构建的,并非真实发生的历史事件。如需了解BCD Semi(Diodes)公司的真实发展故事,建议查阅公司官方发布的资料或相关新闻报道。

Greenliant公司的发展小趣事

面对能源转型的挑战,GPS在2015年转型为智能电网解决方案的提供商。公司研发了一套集数据采集、监控、分析和优化于一体的智能电网平台,帮助电力公司提高运营效率,减少能源浪费。该平台通过实时监测电网状态,预测电力需求,并自动调整供电策略,实现了电网的智能化管理。GPS的智能电网解决方案在全球多个国家和地区得到应用,成为推动能源转型的重要力量。

Flamar公司的发展小趣事

面对电子行业供应链日益复杂的挑战,Flamar公司高度重视供应链管理和优化工作。公司通过引入先进的供应链管理系统,实现了对原材料采购、生产制造、物流配送等各个环节的精准控制。同时,公司还积极与上下游企业建立长期稳定的合作关系,共同构建高效的供应链生态体系。这些措施有效降低了公司的运营成本,提高了生产效率和产品质量,进一步增强了公司的市场竞争力。

Faraday Technology公司的发展小趣事

面对电子行业供应链日益复杂的挑战,Flamar公司高度重视供应链管理和优化工作。公司通过引入先进的供应链管理系统,实现了对原材料采购、生产制造、物流配送等各个环节的精准控制。同时,公司还积极与上下游企业建立长期稳定的合作关系,共同构建高效的供应链生态体系。这些措施有效降低了公司的运营成本,提高了生产效率和产品质量,进一步增强了公司的市场竞争力。

Fine Products Microelectronics Corp公司的发展小趣事

随着电子行业的全球化趋势日益明显,Flamar公司积极实施国际化战略,通过设立海外研发中心、生产基地和销售网络,不断拓展全球市场。公司先后在欧洲、亚洲等地建立分支机构,与当地企业建立紧密的合作关系,共同推动电子技术的创新与应用。通过国际市场的开拓,Flamar公司不仅实现了业务规模的快速增长,还进一步提升了品牌的国际知名度和影响力。

Future Designs, Inc. (FDI)公司的发展小趣事

随着市场需求的不断变化,FDI不断投入研发,致力于技术创新。他们不仅优化了现有的GUI产品,还将其应用范围扩大到了更多领域,如医疗设备、工业自动化、汽车电子等。同时,FDI还拓展了产品线,推出了光电元件、射频/IF和RFID、编程器、开发系统以及集成电路(IC)等一系列产品。这些创新举措使得FDI在电子行业中的影响力不断扩大,市场份额逐步提升。

问答坊 | AI 解惑

奥腾公司打击盗版的内幕

相信很多公司都受到过Altium公司关于版权的困扰,他们不断的进行电话骚扰,发送法律函,声称如果不解决版权的问题将要把贵公司告上法庭。那么您是否为此而去购买他们的 正版软件了呢? 您知道他们是怎么得知贵公司在使用他们的盗版软件的吗? 据 ...…

查看全部问答>

客户选择你的原因

培训课上,一位学员提出这样一个问题:他跟另外一个厂家的业务员同时在做一个大客户的工作,希望能够销售自己的产品。双方的产品、价格、质量及销售政策大致都差不多,而且他比竞争对手早一些接触客户,在人际关系上比对手要熟一些,客户呢,也多次 ...…

查看全部问答>

如何确定wince中是否安装了MSMQ

我用的是wince5模拟器, 如何确定wince中是否安装了MSMQ? 又如何安装呢 谢谢…

查看全部问答>

我是新人,想请假一个问题,关于arm嵌入式

我想进行arm嵌入式的学习和开发,用linux系统,由于我是刚开始,所以请教一下. 我在一般的论坛上查了好久,会arm就不说了,就linux来说,有的人说要弄基于linux的arm开发,要学习和精通内核,也有人说只要精通linux的驱动就可以了. 我该如何发展哦,不用高 ...…

查看全部问答>

【求助】keilc编程 严重问题

*************************************************************************** RESTRICTED VERSION WITH 0800H BYTE CODE SIZE LIMIT; USED: 09CCH BYTE (122%) ************************************************************************** ...…

查看全部问答>

外部时钟信号是接XTAL1还是接XTAL2?

在书上看到的是外部时钟信号接XTAL2,XTAL1接地。(单片机C第四版)。 但公司做的一个小项目上面,用了两个单片机,STC89C54RD+和STC89C51RC,只用了一个11.0592M的晶振,用普通接法给54RD+提供信号,然后晶振的一端直接连51RC的XTAL1,XTAL2悬空,好 ...…

查看全部问答>

Altium Designer 编译出现错误“Duplicate Net Names Wire EB0B”

来自EEWORLD合作群:12425841边城浪子 2010-11-19 09:06:45Altium Designer编译出现错误“Duplicate Net Names Wire EB0B”怎么搞的?重复了, 有两个EB0B …

查看全部问答>