• uboot环境变量初始化


    一、环境变量概述

    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            ""
    #endif
    somestrings

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

    #ifdef  CONFIG_EXTRA_ENV_SETTINGS
        CONFIG_EXTRA_ENV_SETTINGS
    #endif
        ""
    };

    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
    ", __FUNCTION__,__LINE__,env_ptr);
        if (gd->env_valid == 0) {  //env_init中决定了env_valid的值,倘若flash中存在的环境变量校验错误
    #if defined(CONFIG_GTH)    || defined(CFG_ENV_IS_NOWHERE)    /* Environment not changable */
            puts ("Using default environment
    
    ");
    #else
            puts ("*** Warning - bad CRC, using default environment
    
    "); //打印校验错误信息
            SHOW_BOOT_PROGRESS (-1);
    #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
    
    ");
                return;
            }
    
            memset (env_ptr, 0, sizeof(env_t)); //为环境变量存储区清零空间
            memcpy (env_ptr->data,
                default_environment,
                sizeof(default_environment)); //将环境默认变量拷贝到RAM中的指定区域
             env_crc_update (); //更新crc
            gd->env_valid = 1; //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
    ", __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)。

  • 相关阅读:
    【HNOI 2002】 营业额统计
    【BZOJ 3224】 普通平衡树
    【NOIP2014】 联合权值
    【NOIP2016】 组合数问题
    BZOJ2212 POI2011Tree Rotations(线段树合并)
    LOJ114 k大(xiao)异或和(线性基)
    LOJ121 动态图连通性(LCT)
    BZOJ3569 DZY Loves Chinese II(随机化+树上差分+线性基)
    BZOJ3237 AHOI2013连通图(线段树分治+并查集)
    BZOJ2208 JSOI2010连通数(floyd+bitset)
  • 原文地址:https://www.cnblogs.com/amanlikethis/p/3449705.html
Copyright © 2020-2023  润新知