u-boot环境变量

u-boot-1.1.6

在u-boot命令行模式的时候,输入printenv的时候出现很多很多环境变量,这是怎么实现的?使用setenv修改一个环境变量后在printenv显示修改成功,但是关机重启后显示没有改变,这是怎么回事?我看了几天源码和参考网上一个仁兄的文章,今天就在这里好好八一八它的老底!

一、环境变量概述

1.1 调用的次序


1.2 相关源码文件

common/env_common.c        供u-boot调用的通用函数接口,它们隐藏了env的不同实现方式:默认的环境变量定义,环境变量底层操作env_get_char_memory
common/env_dataflash.c       env 存储在dataflash中的实现
common/env_epprom.c          env 存储在epprom中的实现
common/env_flash.c               env 存储在flash中的实现
common/env_nand.c               env 存储在nand中的实现
common/cmd_nvedit.c             实现u-boot对环境变量的操作命令:getenv函数和printenv,setenv,saveenv命令
environment.c                           环境变量以及一些宏定义

1.3 相关结构体

/include/environment.h中定义了表示env的数据结构
 typedef struct environment_s
{
       unsigned long crc;
#ifdef CFG_REDUNDAND_ENVIRONMENT
       unsigned char flags; 
#endif
       unsigned char data[ENV_SIZE];
} env_t;

关于以上结构的说明:

crc是u-boot在保存env 的时候加上去的校验头,在第一次启动时一般 crc校验会出错,这很正常,因为这时 Flash中的数据无效。data字段保存实际的环境变量。u-boot 的 env 按 name=value”\0”的方式存储,在所有env的最后以”\0\0”表示整个 env 的结束。新的name=value对总是被添加到 env 数据块的末尾,当删除一个name=value对时,后面的环境变量将前移,对一个已经存在的环境变量的修改实际上先删除再插入。

u-boot会将 env 从  nand flash等存储设备重定位到 RAM 中,在 env 的不同实现版本(如env_nand.c)中定义了 env_ptr, 它指向 env 在RAM中的位置。u-boot在重定位 env后对环境变量的操作都是针对 env_ptr。u-boot 把env_t 的数据指针有保存在了另外一个地方,这就是 gd_t 结构,这里以ARM为例仅列出和 env 相关的部分。

<include/asm-arm/Global_data.h>

typedef struct global_data

{
       …
       unsigned long env_off;        
       unsigned long env_addr;       
       unsigned long env_valid       
       …
} gd_t

gd_t->env_addr = env_ptr->data;

二、环境变量实现

2.1  默认环境变量定义

 /common/env_common.c    default_environment部分内容如下:
uchar default_environment[] = 
#ifdef	CONFIG_BOOTARGS
	"bootargs="CONFIG_BOOTARGS"\0"
#endif
#ifdef	CONFIG_BOOTCOMMAND
	"bootcmd="CONFIG_BOOTCOMMAND"\0"
#endif
#ifdef	CONFIG_RAMBOOTCOMMAND
	"ramboot="CONFIG_RAMBOOTCOMMAND"\0"
#endif
#ifdef	CONFIG_NFSBOOTCOMMAND
	"nfsboot="	CONFIG_NFSBOOTCOMMAND"\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	"bootdelay="MK_STR(CONFIG_BOOTDELAY)"\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
	"baudrate="MK_STR(CONFIG_BAUDRATE)"\0"
#endif
可以从上面得到,
default_environment的初始化就是根据include/configs/smdk2410.h中的宏决定的
2.2  env_init

/common.c/env_nand.c    当ENV_IS_EMBEDDED为假时env_init为:
env_init
          gd->env_addr  = (ulong)&default_environment[0];//gd中env_addr指向默认的环境变量
          gd->env_valid = 1;                             //说明env_addr指向的数据有效

2.3  env_relocate

common/env_common.c
void env_relocate (void)                                                                                                                
    env_ptr = (env_t *)malloc (CFG_ENV_SIZE); //环境变量重定位:先给它给配空间大小
    env_get_char = env_get_char_memory;       //环境变量底层操作函数指针初始化
    env_relocate_spec();                      //环境变量重定位,env_nand.c中定义的env_ptr指针指向重定位后的环境变量
    gd->env_addr = (ulong)&(env_ptr->data);   //gd中的env_addr指向重定位后的环境变量
2.4  env_relocate_spec 
 /common/env_nand.c
void env_relocate_spec (void)
        ulong total = CFG_ENV_SIZE;
	int ret;
	ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);//将nand中环境变量读到内存的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(); 
三、环境变量操作

3.1 env_get_xxx

 /common/env_common.c
uchar env_get_char_memory (int index)                       //获得环境变量字符串中偏移值为index的那个字符
{
     if (gd->env_valid)                                     
            return ( *((uchar *)(gd->env_addr + index)) );
     else                                                                
            return ( default_environment[index] );
}

uchar *env_get_addr (int index)                             //获得环境变量字符串中偏移值为index的那个字符的地址
{
     if (gd->env_valid) 
           return ( ((uchar *)(gd->env_addr + index)) );
     else 
          return (&default_environment[index]);
}
3.2 printenv打印环境变量
 /common/cmd_nvedit.c                                                                                               
int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])//将内存中的环境变量打印出来
{
	int i, j, k, nxt;
	int rcode = 0;
	if (argc == 1) {	                                 //不带任何参数则打印出所有的变量
	for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
	       for (nxt=i; env_get_char(nxt) != '\0'; ++nxt)   ; //先获得某一个环境变量长度
	       for (k=i; k<nxt; ++k)
	             putc(env_get_char(k));                      //打印出这个环境变量
	       putc  ('\n');//换行
	       if (ctrlc()) {
		         puts ("\n ** Abort\n");
	                 return 1;
		      }
	 }//end for
           printf("\nEnvironment size: %d/%d bytes\n", i, ENV_SIZE);
           return 0;
	}//end if
	for (i=1; i<argc; ++i) {//循环打印命令后出现的单个环境变量
	char *name = argv[i];   //获得某个环境变量名字
	k = -1;
	for (j=0; env_get_char(j) != '\0'; j=nxt+1) {
	        for (nxt=j; env_get_char(nxt) != '\0'; ++nxt)  ;//获得该个环境变量的长度
                     k = envmatch((uchar *)name, j);            //根据名字找到它在环境变量中的偏移量
	        if (k < 0) {continue;}                          //没找到就跳过剩下的部分继续循环
	        puts (name);                                    //找到就打印名字             
	        putc ('=');                                     //打印等号
	        while (k < nxt)
	           putc(env_get_char(k++));                     //打印内容
	        putc ('\n');                                    //换行
	        break;                                          //结束循环
	     }//end for2
	if (k < 0) {
	   printf ("## Error: \"%s\" not defined\n", name);
	   rcode ++; }
	}//end for1
	return rcode;}
3.3 saveenv保存环境变量
 /common/cmd_nvedit.c
int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])//将环境变量保存在永久性储存设备中
{
	extern char * env_name_spec;
	printf ("Saving Environment to %s...\n", env_name_spec);
	return (saveenv() ? 1 : 0);
}
//common/env_nand.c
int saveenv(void)
{
	ulong total;
	int ret = 0;
	puts ("Erasing Nand...");
	if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))//擦除nand中所有的环境变量
	     return 1;
	puts ("Writing to Nand... ");
	total = CFG_ENV_SIZE;
	ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);//将env_ptr指向的环境变量烧写到nand中
	if (ret || total != CFG_ENV_SIZE)
	    return 1;
	puts ("done\n");
	return ret;
}
3.4 setenv(太复杂,略)

3.5  getenv获得环境变量

/common/cmd_nvedit.c   
char *getenv (char *name)//根据名字获得某个环境变量的起始地址
{
     int i, nxt;
     WATCHDOG_RESET();
     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);}
四、配置环境变量

要支持环境变量保存在nand中必须在/include/configs/smdk2410.h设置下某些宏开关,并且要设置些宏为默认环境变量来赋值。

#define CFG_ENV_IS_IN_NAND		1
#define CFG_ENV_OFFSET			0x40000
#define CFG_ENV_SIZE			0x20000         //支持环境变量保存在nand中需要设置的宏定义
/***************************************************************************************/
#define MTDIDS_DEFAULT	 "nand0=nandflash0"             //常用的环境变量
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bios)," \
                         "128k(params)," \
                         "128k(toc)," \
                         "512k(eboot)," \
                         "1024k(logo)," \
                         "3m(kernel)," \
                         "-(root)"

#define CONFIG_COMMANDS \
			(CONFIG_CMD_DFL | \
			CFG_CMD_CACHE	 | \
			CFG_CMD_PING     | \
			CFG_CMD_JFFS2    | \
			CFG_CMD_NAND	 | \
			CFG_CMD_REGINFO  | \
		    	CFG_CMD_ELF	 | \
			CFG_CMD_DATE)
#include <cmd_confdefs.h>

#define CONFIG_BOOTDELAY		10
#define CONFIG_BOOTARGS			"noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0"
#define CONFIG_ETHADDR			0a:1b:2c:3d:4e:5f
#define CONFIG_NETMASK			255.255.255.0
#define CONFIG_IPADDR			192.168.1.6
#define CONFIG_SERVERIP			192.168.1.8
#define CONFIG_BOOTCOMMAND		"boot_zImage"

参考文献: U-BOOT环境变量实现 


                
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
U-BOOT的移植 U-BOOT 的移植 说先在把U-BOOT- 1.1.6复制到SMB共享文件里面,然后到虚拟机里面解压他,执行命令:tar xjvf U-BOOT-1.1.6 课程咨询:联系人:何老师 15333833127 QQ:1187729241 编译U-BOOT需要采用arm-linux-gcc-3.3.2的交叉编译器 将编译器的压缩文件复制到smb的共享文件夹里面,然后采用tar xjvf 进行解压,解压后的文件需要移动到usr/local/arm里面,然后要修改编译器的环境变量: 执行vi /etc/profile,然后在里面的修改成 export PATH =/usr/local/arm/3.3.2/bin:$PATH 修改好了以后,需要执行 source /etc/profile,可以查看编译器的版本 a 执行arm-linux-gcc –v 接下来可以进入U-BOOT-1.1.6里面进行编译,但是还需要修改一个地方, 执行:vi cpu/arm920t/config.mk然后再该目录下,把-msoft-float用#号注释掉(意思是不用软浮点进行编译) U-BOOT没有像VIVI那样的图形配置界面,我们只能修改其中的文件进行配置, 解压U-BOOT-1.1.6,进入U-BOOT目录,修改Makefile: 每个文件都有这样的语句,意思是代表每个开发板,具体就是 开发板的名称_config 各项的意思如下: arm: CPU的架构(ARCH) arm920t: CPU的类型(CPU),其对应于cpu/arm920t子目录。 TX2440: 开发板的型号(BOARD),对应于board/TX2440目录。 NULL: 开发者/或经销商(vender)。 s3c24x0: 片上系统(SOC)。 在smdk2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0 加上 TQ2440_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t TQ2440 NULL s3c24x0 修改好了以后需要保存,但是这时候,是没法保存的,因为没权限,这时候,需要在虚拟机里面修改权限: 在u-boot-1.1.6目录里面 执行chmod 666 Makefile 把文件的权限修改成可以读写 指定交叉编译器的工具 在Makefile第128行里面的CROSS_COMPILE=arm-linux- 意思就是指定arm-linux-为交叉编译器 在虚拟机里面U-Boot-1.1.6的board里面新建一个自己开发板的目录TQ2440: 在U-Boot-1.1.6中进入Board目录中,把里面的一个文件,smdk2410改名成TQ2440. 进入到TQ2440中,把里面的文件 ,smdk2410.c改名成TQ2440.c 返回到Board目录。只保留TQ2440文件,其余的可以删除掉,删除方法可以这样: 把TQ2440移动上一层目录:mv TQ2440 ../ 然后执行 rm – rf*,把所以得文件删除掉(注意这个命令的格式,多几个空格) 最后把上一层目录上的TQ2440移回来:mv ../ TQ2440 ./ 在这个board目录中修改Makefile文件。我们可以再smb共享的文件进入到board文件中 打开Makefile。在第28行的smdk2410.o改为TX2410.o。 在修改中,会遇到没有权限修改文件,我们回到虚拟机中,修改权限: 打开TQ2440,执行:chomd 666 Makefile. 在返回去保存! 在include/configs目录下创建板子的配置头文件,把smdk2410.h改名为TQ2440.h: 首先进入到include/configs目录中,执行mv smdk2410.h TQ2440.h 然后把该目录下除了TQ2440.h,其余的都删除了。 看看配置是否成功: 回到U-Boot-1.1.6目录 执行 make TQ2440_config 当出现Configuring for TX2440 board.....表示配置以已经成功 出现make: execvp: …………/mkconfig: 权限不够 查看mkconfig的权限,发现没有可执行权限,用chmod 764 mkconfig加上权限 然后再make,成功后可出现 Configuring for TX2440 board.....

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值