一、环境变量概述

1、环境变量的概念

可以理解为用户对软件的全局配置信息,这部分信息应该可以从永久性存储器上读取,能被查询,能被修改。

  启动过程中,应该首先把环境变量读取到合适的内存区域,然后利用环境变量初始化硬件、启动操作系统等等。

2、启动过程中环境变量初始化过程涉及的问题

这里涉及到两个问题:

   环境变量在哪个地方存着(从哪个地方取)

   将环境变量存储到哪里(放到哪)

(1)环境变量位于存储器(norflash、nandflash )

“CFG_ENV_IS_IN_XXX”(CFG_ENV_IS_IN_FLASH、CFG_ENV_IS_IN_NAND等等)定义了则这种情况有效,以在flash上为例。

ENV_IS_EMBEDDED定义了

详细工作原理,见”ENV_IS_EMBEDDED“解惑以及相关的移植实验。这种情况的环境变量在flash上存着(但是占了flash一个扇区),并且随着代码段(因为环境变量区嵌在代码段内)在start.s重定位时一同载入内存。在环境变量初始化时候,如果这部分能通过校验,就不需要先在堆区开辟空间然后搬移的工作,而是直接使用这部分环境变量(省了搬移工作)。倘若不能通过校验,则使用默认环境变量放到重定位时环境变量所占的空间中。

ENV_IS_EMBEDDED没有定义

这种情况会在堆区为环境变量区开辟空间,如果flash上存储的是有效的(能通过校验)环境变量,则需要把flash上的数据搬运到堆区指定的位置;如果flash上的存储是错误的环境变量,那么使用默认的环境变量(default_environment)放到堆区。

(2)没有存储器上存储有环境变量 

“CFG_ENV_IS_NOWHERE”定义了则选择这种模式,使用common/env_nowhere.c文件而不是用env_flash.c、env_nvram.c等等文件。

  这种情况下,使用默认的环境变量(default_environment)。先在堆区为环境变量开辟空间,然后启动搬运工作。

二、环境变量初始化流程

  以环境变量位于NorFlash上,并且没有使能“ENV_IS_EMBEDDED”功能为例,进行以下内容的分析。其他情况本文不讨论。

1、校验

 直接在NorFlash上校验环境变量,实际上这一步是确定环境变量的源。如果NorFlash上存储的是有效的环境变量的话,那么就从NorFlash上读取数据。倘若NorFlash上存储的是无效的环境变量,那么使用默认的环境变量作为源。

2、重定位

  将从存储环境变量的存储区加载到系统指定的位置。

3、涉及到的函数

(1)env_init

  完成校验,并决定环境变量的源

  此函数在start_armboot函数的开始阶段,会依次执行“init_sequence”中的每一个函数,其中一个就是env_init。

(2)env_relocate

  首先,在堆区为环境变量开辟存储缓冲区。另外,当NorFlash上的环境变量区是无效的时候,选择默认的环境变量区进行定位。当NorFlash上的环境变量区是有效的时候,调用env_relocate_spec进行重定位。

  此函数是在start_armboot函数的中途阶段,在NorFlash和NandFlash都初始化后,会调用这个函数。

(3)env_relocate_spec

  此函数是被env_relocate所调用。

三、代码分析

1、相关全局变量

1> env_ptr(common/env_flash.c)

env_t *env_ptr = (env_t *)CFG_ENV_ADDR; // 定义flash中环境变量的地址
#ifdef CMD_SAVEENV
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;

2> default_environment(common/env_common.c)

uchar default_environment[] = {
#ifdef CONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
somestrings

 #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
  "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
  #endif

#ifdef  CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
"\0"
};

2、env_init(common/env_flash.c)

    if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { //如果校验成功 
gd->env_addr = (ulong)&(env_ptr->data);
gd->env_valid = 1; //1代表flash中存在环境变量
return(0);
}
gd->env_addr = (ulong)&default_environment[0];
//不成功,则使用系统默认的环境变量
//default_environment仅仅是环境变量的data区,不包含头部crc 、flags
gd->env_valid = 0; //0代表使用默认的环境变量
return (0);

3、env_relocate(common/env_common.c)

void env_relocate (void)
{
/*
* We must allocate a buffer for the environment
*/
env_ptr = (env_t *)malloc (CFG_ENV_SIZE); //为环境变量区分配空间
DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
if (gd->env_valid == ) { //env_init中决定了env_valid的值,倘若flash中存在的环境变量校验错误
#if defined(CONFIG_GTH) || defined(CFG_ENV_IS_NOWHERE) /* Environment not changable */
puts ("Using default environment\n\n");
#else
puts ("*** Warning - bad CRC, using default environment\n\n"); //打印校验错误信息
SHOW_BOOT_PROGRESS (-);
#endif
//#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE) ENV_SIZE在include/environment.h中定义
if (sizeof(default_environment) > ENV_SIZE)
{
puts ("*** Error - default environment is too large\n\n");
return;
} memset (env_ptr, , sizeof(env_t)); //为环境变量存储区清零空间
memcpy (env_ptr->data,
default_environment,
sizeof(default_environment)); //将环境默认变量拷贝到RAM中的指定区域
env_crc_update (); //更新crc
gd->env_valid = ; //env_valid确认有效了
}
else { //倘若flash中存在的环境变量校验成功
env_relocate_spec ();
/*该函数实现真正的重定位功能,先从NAND flash中读取环境变量,如果读取成*/
}
gd->env_addr = (ulong)&(env_ptr->data); //将环境变量的首地址(不含crc头部)赋给全局变量gd->env_addr
}

修改env_common.c中第47行“#undef DEBUG_ENV”变为“#define DEBUG_ENV”,并在函数一开始处加上语句

  DEBUGF ("%s[%d] env_valid = 0x%8x\n", __FUNCTION__,__LINE__,
gd->env_valid);

重新编译后下载,调试结果如下。

可见执行完env_init()函数中env_valid被置为0,这是由于一开始NorFlash上并没有存储环境变量,当然会校验错误。并且,可以看到环境变量缓冲区被开在堆区。

4、 env_relocate_spec(common/env_flash.c)

void env_relocate_spec (void) //此函数被env_relocate()函数调用
{
memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE); //在env_relocate已经将env_ptr指向环境变量存储区
}

 四、环境变量的源位置和加载位置

  回过头来,再看一下环境变量的源在哪儿,加载位置又在哪儿?看一下重定位的关键函数调用:

memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE); 

  flash_addr是源位置,在0x70000

static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */
#define CFG_FLASH_BASE PHYS_FLASH_1
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x070000) /* addr of environment */
#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */

  env_ptr是加载位置,位于堆区

 env_ptr = (env_t *)malloc (CFG_ENV_SIZE);  

总结

env_init()函数读取flash中环境变量区然后校验,“gd->env_valid ”记录了校验成功与否。进入env_relocate函数,先将环境变量区设定在堆区,然后根据校验标志位决定是从flash中拷贝,还是从默认环境变量区拷贝(这种情况还需要更新校验crc)。

uboot环境变量初始化的更多相关文章

  1. uboot环境变量实现分析

    u-boot的环境变量用来存储一些经常使用的参数变量,uboot希望将环境变量存储在静态存储器中(如nand nor eeprom mmc). 其中有一些也是大家经常使用,有一些是使用人员自己定义的, ...

  2. 在Linux里读取UBOOT环境变量

    转载:http://falloutmx.blog.163.com/blog/static/39236020201211145010154/ 可以通过mtd方式读取,也可以用ioremap方式.不过这些 ...

  3. u-boot 环境变量参数设置

    今天本来是烧写内核,结果一不小心把uboot也整不能用了,无奈之下只好重新烧个uboot,等都弄好以后,发现系统还是启动不了,原来是启动参数设置不对,于是找到了这篇文章,//是我添加的内容. 原文地址 ...

  4. OK335xS U-boot 环境变量解析

    /************************************************************************************************** ...

  5. MPC8313ERDB在Linux从NAND FLASH读取UBoot环境变量的代码分析

    MPC8313ERDB在Linux从NAND FLASH读取UBoot环境变量的代码分析 Yao.GUET@2014-05-19 一.故事起因 由于文件系统的增大,已经大大的超出了8MB的NOR FL ...

  6. I.MX6 Linux U-boot 环境变量解析

    /********************************************************************************** * I.MX6 Linux U- ...

  7. Linux系统——访问U-BOOT环境变量

    Linux系统下访问U-BOOT环境变量 移植过U-BOOT的人,都知道:在U-BOOT中存有ENV.但U-BOOT在引导内核启动之后,U-BOOT的生命周期就结束了.那么启动LINUX内核之后,U- ...

  8. uboot环境变量

    一. uboot运行时环境变量分布 1.1. 环境变量有2份,一份在Flash中,另一份在DDR中.uboot开机时一次性从Flash中读取全部环境变量到DDR中作为环境变量的初始化值,然后使用过程中 ...

  9. uboot 环境变量

    从bootm 命令讲起 1 找到linux的内核入口 Bootm命令通过读取uImage的头部0×40字节的信息,将uImage定位到正确的地址,同时找到linux的内核入口地址. 这个地方就涉及到u ...

随机推荐

  1. Flume 入门--几种不同的Sources

    1.flume概念 flume是分布式的,可靠的,高可用的,用于对不同来源的大量的日志数据进行有效收集.聚集和移动,并以集中式的数据存储的系统. flume目前是apache的一个顶级项目. flum ...

  2. Activiti5.13数据库表结构设计

    1.结构设计 1.1.    逻辑结构设计 Activiti使用到的表都是ACT_开头的. ACT_RE_*: ’RE’表示repository(存储),RepositoryService接口所操作的 ...

  3. NSURLSessionDownloadTask 断点下载

    #import "ViewController.h" #import "ASIHTTPRequest.h" #import <AFNetworking/A ...

  4. android79 Fragment生命周期

    切换成01时依次调用onCreate,onStart,onResume方法,切换到03的时候01依次onPause,onStop,onDestroy,03依次onCreate,onStart,onRe ...

  5. BaseAdapter优化深入分析

    BaseAdapter是一个数据适配器,将我们提供的数据格式化为ListView可以显示的数据,BaseAdapter的优化直接影响到ListView的显示效率. 我们都知道,ListView自带有回 ...

  6. Android - Binder驱动

      以下资料摘录整理自老罗的Android之旅博客,是对老罗的博客关于Android底层原理的一个抽象的知识概括总结(如有错误欢迎指出)(侵删): http://blog.csdn.net/luosh ...

  7. Linux重复执行上一条命令

    执行刚刚执行的一条命令: !! 执行最近一个以指定字符串开头的命令(比如man) !man !m 引用上一个命令的最后一个参数 !$ <ESC>, .

  8. 安装指南:Win10下安装CentOs7

    系统安装 安装准备 系统:CentOS 7.Win 10 硬件:U盘一枚.PC一台 软件:UltraISO 安装步骤 使用UltraISO将镜像写入U盘 window10使用磁盘管理,空出一个未分配的 ...

  9. 新建oracle数据库表空间

    1.新建表空间,注意是数据表空间,不是临时表空间 create tablespace CARD logging  datafile 'C:\app\tablespace\CARD.DBF'   //注 ...

  10. SQL Server 中WITH (NOLOCK)

    with(nolock)的功能: 1: 指定允许脏读.不发布共享锁来阻止其他事务修改当前事务读取的数据,其他事务设置的排他锁不会阻碍当前事务读取锁定数据.允许脏读可能产生较多的并发操作,但其代价是读取 ...