分享

uboot参数表的结构和操作

 WUCANADA 2012-08-25

uboot参数表的结构和操作

uboot参数表的结构和操作(R.wen)

1、参数表的结构定义在environment.c中,如下:

#ifdef CFG_REDUNDAND_ENVIRONMENT

# define ENV_HEADER_SIZE       (sizeof(unsigned long) + 1)

#else

# define ENV_HEADER_SIZE       (sizeof(unsigned long))

#endif

//除去参数表头后参数的长度最值

#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE)

typedef     struct environment_s {

unsigned long crc;        /* CRC32 over data bytes      */

#ifdef CFG_REDUNDAND_ENVIRONMENT

unsigned char flags;             /* active/obsolete flags   */

#endif

unsigned char data[ENV_SIZE]; /* Environment data         */

} env_t;

结 构env_t参数表的结构非常简单,第一个成员就是crc,用于crc32校验,第二个参数是冗余的标志,最后一个就是参数数组了。所以参数头的长度 ENV_HEADER_SIZE就是crc与flags之和,即为sizeof(long)+sizeof(char)。这个结构就是在内存和flash 上表示参数表的结构。

参数表的最后一个成员data数组中存放所有的环境变量值,每个变量和值用‘=’号连接,而两个变量之间则通过’\分开,如下:

uchar default_environment[] = {

#ifdef CONFIG_BOOTARGS

"bootargs="    CONFIG_BOOTARGS                "\0"

#endif

#ifdef CONFIG_BOOTCOMMAND

"bootcmd="    CONFIG_BOOTCOMMAND              "\0"

#endif

……

"\0"

};

2、环境变量的初始化env_relocate()

       Uboot在完成汇编部分的初始化之后,将跳到start_armboot()去执行,其中便会执行env_relocate()初始化环境变量。

去除了一些不执行的代码后,这个函数如下:

void env_relocate (void)

{

      /*

      * We must allocate a buffer for the environment

      */

      env_ptr = (env_t *)malloc (CFG_ENV_SIZE); // 1

      /*

      * After relocation to RAM, we can always use the "memory" functions

      */

      env_get_char = env_get_char_memory; // 2

      if (gd->env_valid==0)

             default_env();           // 3

      else {

             env_relocate_spec ();   // 4

      }

      gd->env_addr = (ulong)&(env_ptr->data); // 5

}

第一步,初始化一个全局指针,它被定义为:

env_t *env_ptr = 0;

第二步,重新初始化函数指针,

static uchar env_get_char_init (int index);

uchar (*env_get_char)(int) = env_get_char_init;

该函数指针原来被初始化为env_get_char_init,现在改为env_get_char_memory。对于nand flash,这两个函数是一样的。

第三步,如果flash没有参数表,则使用默认参数,这里是通过default_env()来加载。

void default_env(void)

{

       memset (env_ptr, 0, sizeof(env_t));

       memcpy (env_ptr->data,

              default_environment,

              sizeof(default_environment)); //拷贝环境变量

#ifdef CFG_REDUNDAND_ENVIRONMENT

       env_ptr->flags = 0xFF;

#endif

       env_crc_update ();   //更新crc32校验

       gd->env_valid = 1; //标识环境变量可用

}

第四步,如果flash上有参数表可用,则从flash上加载,通过env_relocate_spec()来实现:

void env_relocate_spec (void)

{

#if !defined(ENV_IS_EMBEDDED) //如果不是使用嵌入参数的形式,即为参数表的形式

       ulong total;

       int ret;

       total = CFG_ENV_SIZE; //参数表大小,包括参数表头部

       //读出操作,flash设备为nand_info,偏移为CFG_ENV_OFFSET,读出的大小为total,目标地址由env_ptr所指。

       ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);

       //如果读出的长度不对或出错,则使用默认值

    if (ret || total != CFG_ENV_SIZE)

              return use_default();

       //如果校验出错,使用默认值

       if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)

              return use_default();

#endif /* ! ENV_IS_EMBEDDED */

}

此外,uboot的参数表还支持一种被称为CFG_ENV_OFFSET_REDUND的冗余模式,它会在flash上保存两个参数表副本,这样在一个副本出错的时候,还可以从另一个副本中去读取,通过这种方式,提高了数据的安全性。

第五步,gd->env_addr = (ulong)&(env_ptr->data)

即将环境变量的值赋值给全局变量gd->env_addr,这样只要通过这个全局变量就可以访问这些变量了。

       值得一提的是,字符串数组data里面的变量与变量之间是通过’\来分割的。

3、环境变量的保存,保存是读取的反过程,所以跟上面的过程相似,如下:

int saveenv(void)

{

      ulong total;

      int ret = 0;

      //先擦除

      if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))

      //写入

total = CFG_ENV_SIZE;

      ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);

      if (ret || total != CFG_ENV_SIZE)

             return 1;

      puts ("done\n");

      return ret;

}

4、读取环境变量

Uboot中经常要读取环境变量,这是通过getenv来实现的:

/ * Look up variable from environment,

* return address of storage for that variable,

* or NULL if not found

*/

char *getenv (char *name)

{

       int i, nxt;

       for (i=0; env_get_char(i) != '\0'; i=nxt+1) {

              int val;

              for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {

                     if (nxt >= CFG_ENV_SIZE) {

                            return (NULL);

                     }

              }

              if ((val=envmatch((uchar *)name, i)) < 0)

                     continue;

              //通过所得的下标返回变量值的指针,由于是字符串指针,所以它在碰到’\符合时结束,即为该变量的值。

              return ((char *)env_get_addr(val));

       }

       return (NULL);

}

通过输入变量的名字,返回变量的值。

前面已经提到,函数指针env_get_char已经被初始化为env_get_char_memory:

       该函数获取环境变量数组中下标为index的字符。

uchar env_get_char_memory (int index)

{

if (gd->env_valid) {

         return ( *((uchar *)(gd->env_addr + index)) );

} else {

         return ( default_environment[index] );

}

}

/************************************************************************

* Match a name / name=value pair

*

* s1 is either a simple 'name', or a 'name=value' pair.

* i2 is the environment index for a 'name2=value2' pair.

* If the names match, return the index for the value2, else NULL.

*/

查找符号变量,如果找到则返回等号后面的字符串指针,即为变量的值。

static int

envmatch (uchar *s1, int i2)

{

       while (*s1 == env_get_char(i2++))

              if (*s1++ == '=')

                     return(i2);

       if (*s1 == '\0' && env_get_char(i2-1) == '=')

              return(i2);

       return(-1);

}

如前所述,环境变量表是一个字符串数组,而其中的变量之间通过’\符号隔开,即是当遇到该符号时,则表示一个变量结束而另一个变量开始。

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

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多