uboot nand flash dump 环境变量 + 制作环境变量分区 + 代码结构详解
第一部分,首先从外部感性的认识下env分区
1.1首先我们在uboot console里面执行saveenv,打印如下
UBOOT=>saveenv
Saving Environment to NAND... Erasing NAND...
Erasing at 0x400000 -- 100% complete.
Writing to NAND... OK
OK
1.2观察上述打印,我们可以知道uboot env分区是在nand flash 0x400000处
1.3使用命令dump出来看看内容是什么

1.4解析dump出来的内容
env在uboot中的结构体如下,下面根据结构体来解析dump出来的内容
dump出来的内容解析如下:
随便找了一个hex-》ascii的在线网站:https://www.rapidtables.com/convert/number/hex-to-ascii.html

第二部分,下面根据代码讲解下如何制作env分区
2.1首先准备好一个env.txt,其内容如下

2.2使用如下命令
uboot/u-boot-2020.04/tools/mkenvimage -s 0x20000 -r -p 0x00 -o env.bin env.txt
本小节参考如下两个链接,建议先看完这两个链接,再往下继续:
https://bootlin.com/blog/mkenvimage-uboot-binary-env-generator/
https://source.denx.de/u-boot/u-boot/-/commit/a6337e6ffdea211e70dd8d6c638f6a5ec2295400
2.2.1 我们使用的工具是mkenvimage,其源代码已经被包含中uboot的源代码当中,编译uboot的同时就会编译出这个工具mkenvimage。如果没有被编译,生成这个tool,检查下如下路径的makefile。

2.2.2 -s 后面的0x20000表示env分区的大小,由代码的defconfig文件的如下宏决定
这里再赘述下上述的结构体,一看便知什么意思
CONFIG_ENV_SIZE=0x20000 128kB CONFIG_ENV_OFFSET=0x400000 CONFIG_ENV_OFFSET_REDUND=0x480000 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT # define ENV_HEADER_SIZE (sizeof(uint32_t) + 1) #else # define ENV_HEADER_SIZE (sizeof(uint32_t)) #endif #define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)
data[ENV_SIZE]中ENV_SIZE的值是(CONFIG_ENV_SIZE - ENV_HEADER_SIZE),说明这个结构就是128kB。
对于本项目,env_a和env_b的分区的大小是512kB, 即如下两个offset相减。
CONFIG_ENV_OFFSET=0x400000
CONFIG_ENV_OFFSET_REDUND=0x480000
2.2.3 -r表示我使用的redundant env,即目前我有两个env,有两个env的话,生成的头是 crc32 + flags多了一个flags。
2.2.4 -p 0x00表示 data数组的后面用什么填充,因为这个结构体非常大,我们大概率是填不满的,此时用0x00填充而非0xff
在最后一个stdout环境变量之后我们开始用0x00来填充。

2.3.使用hexdump查看下header的crc值是否正确,是否有flag,以及内容是否正确。
crc32值为 79 6c 88 58,和从nand flash的值是一样的
flag为01,具体值不用管,只要有这个byte就行
再看看altbootcmd和bautrate的值,也是对的,

2.4.下面只需要根据CONFIG_ENV_OFFSET和CONFIG_ENV_OFFSET_REDUND的值将这一个生成的env.bin写到两个env_a,env_b的开始处,就行了。自此大功告成。
CONFIG_ENV_OFFSET=0x400000
CONFIG_ENV_OFFSET_REDUND=0x480000
第三部分,下面讲解uboot启动过程中如何与env分区打交道
首先入口的函数调用顺序是initr_env -》 env_relocate -》env_load
注意下面开始最关键的代码分析
3.1 首先打印Loading Environment from,
3.2 调用函数指针drv->load(),这个值被填充的地方是在下图绿框里面结构定义,值为圆圈3,env_nand_load
3.3 进入env_nand_load以后,首先会从两个env_a, env_b的offset处开始读取
3.4 读取成功后进入env_import_redund(圆圈6),在这个函数里面会进行crc32值的计算(圆圈7)
3.5 如果失败,打印*** Warning - %s, " "using default environment (圆圈8和圆圈9)
3.6 如果成功,在返回后,会打印OK(圆圈10)
3.7 两种情况下crc错误 和 crc正确的串口打印log如下图




浙公网安备 33010602011771号