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出来的内容

typedef struct environment_s {
    uint32_t    crc;        /* CRC32 over data bytes    */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
    unsigned char   flags;      /* active/obsolete flags ENVF_REDUND_ */
#endif
    unsigned char   data[ENV_SIZE]; /* Environment data     */
} env_t;

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,表示env的大小是0x20000,即128 kB,这里要注意的是 
128kB大小指的是 上述结构体的大小,并非mtd中env分区的大小

 这里再赘述下上述的结构体,一看便知什么意思

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)
typedef struct environment_s {
    uint32_t    crc;        /* CRC32 over data bytes    */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
    unsigned char   flags;      /* active/obsolete flags ENVF_REDUND_ */
#endif
    unsigned char   data[ENV_SIZE]; /* Environment data     */
} env_t;
 

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如下图

 

 

posted @ 2025-04-30 16:33  midhillzhou  阅读(162)  评论(0)    收藏  举报