分享

uboot 环境变量备份

 guitarhua 2015-11-12

1、setenv 命令

该命令用于设置环境变量,用法介绍如下

  1. # setenv  
  2. setenv - set environment variables  
  3.   
  4. Usage:  
  5. setenv name value ...  
  6.     - set environment variable 'name' to 'value ...'  
  7. setenv name  
  8.     - delete environment variable 'name'  
如介绍所述,当要设置环境变量时,用法如: setenv name value,当要删除环境变量时,用法如:setenv name。函数的实现多数为字符串处理流程,在完成处理后会更新当前 env 的crc 校验值。这个命令的操作都是在内存中进行的,如果不写入emmc重启就会丢失,保存则需要用 saveenv 命令将内存中的所有env都写入emmc中。

2、mmc 命令

该命令用于初始化 SD 存储卡,用法介绍如下

  1. mmc - MMC sub-system  
  2.   
  3. Usage:  
  4. mmc init [dev] - init MMC sub system  
  5. mmc device [dev] - show or set current device  
如介绍所述,当要初始化 SD 存储卡时,用法如: mmc init [dev],其中 dev 可以指定设备编号,默认编号为 1。用法:mmc device [dev] 显示当前设备或者设置当前设备为 dev 编号的设备。
3、fatload 命令

该命令用于从 FAT 文件系统设备中读取指定文件放入指定内存中,用法介绍如下:

  1. usage: fatload <interface> <dev[:part]> <addr> <filename> [bytes]  
如介绍所述,当要读取文件时,需要设备已经完成初始化并注册到文件系统中,读取时用法如: fatload mmc 1 0x81000000 boot.img[size],其中 mmc 1 为文件 boot.img 保存的设备,0x81000000 为读取的内容存放的内存地址。

4、fatinfo 命令

该命令用于查看 FAT 格式设备的基本信息,用法介绍如下:

  1. usage: fatinfo <interface> <dev[:part]>  
在使用该命令的时候直接指定需要查看的设备和编号即可,如: fatinfo mmc 1,结果如下:

  1. Interface:  MMC  
  2.   Device 0: Vendor:  Rev:  Prod:   
  3.             Type: Hard Disk  
  4.             Capacity: 3789.0 MB = 3.7 GB (7759872 x 512)  
  5. Partition 1: Filesystem: FAT32 "NO NAME    "  
5、fatls 命令

该命令用于查看 FAT 格式设备的目录和文件信息,用法介绍如下:

  1. usage: fatls <interface> <dev[:part]> [directory]  
在使用该命令的时候需要指定设备及其编号,默认目录为根目录,如果想查看其它目录则可以通过 [directory] 参数指定,如:fatls mmc 1 customized,结果如下:

  1.           ./  
  2.           ../  
  3. 4106240   arm_tools.tar   
  4.    1713   readme_cn.txt   
  5.           gen_customer/  
  6.   
  7. file(s), 3 dir(s)  
6、fatname 命令
该命令用于从 FAT 格式设备的根目录读取指定文件,用法介绍如下:

  1. usage: fatname <interface> <dev[:part]> <filename>  

在使用该命令的时候同样需要指定设备和编号,如果该文件存在则会返回读回数据的长度,如果文件不存在则返回 -1 并在命令行打印相关消息,用法如:fatname mmc 1 fire


附:uboot 调试经验

1、烧录问题:以前经常遇到用串口烧录 xloader、uboot、boot 的时候串口传输出错,就会导致烧录失败并且开不了机,而且在双 uboot 的情况下仍然开不了机。只能用硬件的方式进入强制烧录模式才行。在查看相关源码后发现在烧录的时候不管传输的镜像文件是否完整,都会去做烧录的动作,而且只对传输过去的内容做crc校验,这也造成了crc校验失去了应有的意义。

解决方案:在烧录动作之前加入了镜像完整性检测,如果加载的镜像不完整就不会更新emmc中原有的镜像,这样就解决此问题了。


2、环境变量丢失的问题:有的时候会发现系统里面的一些重要参数(如:电池电量表、充电电流等)丢掉了,这些参数是通过 uboot 环境变量的形式保存在 emmc 中的,如果这些重要参数丢掉了会导致严重的问题,但遇到这种情况的概率比较小,就一直认为是 emmc 的随机问题,还做了环境变量备份的机制。后来通过客户那边的反馈信息才发现一种必现的情况,就是开机的时候一起按住Power 键 +音量加键 ,按照这种情况,系统应该进入烧录模式,也就是会从 SD 卡中读取镜像开始烧录了,如果 SD 卡没有系统镜像则会烧录失败,而测试到的情况表明烧录失败后,重启手机那些环境变量就已经丢掉了。

解决方案:分析代码才发现原来只要进入烧录模式的第一个动作就是擦除原有的环境变量,而不管用户是否有插入 SD 卡或者 SD 卡中是否有镜像,于是将擦除环境变量的动作移动到了 uboot 烧录完成之后,这样就能保证用户误操作开机不会导致环境变量异常丢失了。


3、环境变量备份:为了防止 emmc 或者 nand 异常出错导致环境变量错误,需要对环境变量做一个备份。

解决方案:系统的环境变量(env1)保存在 emmc 偏移为 0x400000 的地址处,长度只有 8192,在设计时为环境变量预留的保存空间为 2M,所以有很大的空间可以用来做备份(env2),现在选定偏移地址为 0x480000 为备份起始地址,长度同样为 8192。在开机的时候,会分别对两处环境变量分别做 crc 检验,然后与其保存的 crc 校验值比较,如果相同则表示环境变量没有错误,如果不同则说明当前环境变量出错,如果出错了则将正确的那处环境变量读到内存中使用,并将出错的那处环境变量重写,如果两处都出错,则应该维修了。为了简化处理流程,在写新的环境变量的时候,同时会写到两处,写的过程则是先完成 env1 的擦除和重写再做 env2 的擦除和重写同时更新 crc 校验值。在 uboot 中把不必要的环境变量都去掉了,这样一般只有在烧录系统的时候才会对环境变量有改写,这样也减少了出错的概率。以下是开机时判断环境变量是否出错的代码:

  1. void env_relocate_spec (void)  
  2. {  
  3.     int crc1_ok = 0, crc2_ok = 0, b_save_env = 0;  
  4.     env_t *tmp_env1, *tmp_env2;  
  5.   
  6.     /* 申请两块内存用来保存从 emmc 读取出来的环境变量 */  
  7.     tmp_env1 = (env_t *) malloc(CONFIG_ENV_SIZE);  
  8.     tmp_env2 = (env_t *) malloc(CONFIG_ENV_SIZE);  
  9.   
  10.     /* 读取环境变量 */  
  11.     if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))  
  12.         printf("No Valid First Environment Area Found\n");  
  13.     if (readenv(CONFIG_ENV_BK_OFFSET, (u_char *) tmp_env2))  
  14.         printf("No Valid Secondary Environment Area Found\n");  
  15.   
  16.     /* 对环境变量做 crc 校验并与保存值比较 */  
  17.     crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);  
  18.     crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);  
  19.   
  20.     /* 判断环境变量是否出错 */  
  21.     if(!crc1_ok && !crc2_ok) {  
  22.         free(tmp_env1);  
  23.         free(tmp_env2);  
  24.         printf("Env crc1 and crc2 is not OK\n");  
  25.         return use_default();  
  26.     } else if(crc1_ok && !crc2_ok) {  
  27.         gd->env_valid = 1;  
  28.         b_save_env = 1;  
  29.     } else if (!crc1_ok && crc2_ok) {  
  30.         gd->env_valid = 2;  
  31.     } else {  
  32.         /* both ok - check serial */  
  33.         if(tmp_env1->crc == 0 && tmp_env2->crc != 0) {  
  34.             gd->env_valid = 2;  
  35.         } else if(tmp_env2->crc == 0 && tmp_env1->crc != 0){  
  36.             gd->env_valid = 1;  
  37.             b_save_env = 1;  
  38.         } else if(tmp_env2->crc == 0 &&  tmp_env1->crc == 0) {  
  39.             printf("No Vaild Env, return to default Env.\n");  
  40.             return use_default();  
  41.         } else { /* crc are equal - almost impossible */  
  42.             gd->env_valid = 1;  
  43.         }  
  44.         printf("The Same Environment.\n");  
  45.     }  
  46.   
  47.     /* 包含部分异常处理 */  
  48.     free(env_ptr);  
  49.     if(gd->env_valid == 1) {  
  50.         env_ptr = tmp_env1;  
  51.         if(b_save_env) run_command("saveenv", 0);  
  52.   
  53.         printf ("Env1 is OK\n\n");  
  54.         free(tmp_env2);  
  55.     } else {  
  56.         env_ptr = tmp_env2;  
  57.   
  58.         printf ("Save env2 to env1 \n\n");  
  59.         run_command("saveenv", 0);  
  60.   
  61.         free(tmp_env1);  
  62.     }  
  63.   
  64.     gd->env_addr = env_ptr->data;  
  65.   
  66.     if(getenv("second_env") == NULL)  
  67.         return;  
  68.   
  69.     setenv("second_env", 0);  
  70.   
  71.     /* 将代码中的环境变量保存到 emmc 中,仅在烧录系统时作用 */  
  72.     add_sencond_env();  
  73. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多