本文主要以U-boot(1.1.6)为例进行说明。
1.相关文件
common/env_common.c
供u-boot调用的通用函数接口,它们隐藏了env的不同实现方式,比如dataflash, epprom, flash等
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/env_nvedit.c
实现u-boot对环境变量的操作命令
environment.c
环境变量以及一些宏定义
env如果存储在Flash中还需要Flash的支持。
2.数据结构
env 在 u-boot 中通常有两种存在方式,在永久性存储介质中( Flash NVRAM等 )在SDRAM,可以配置不使用 env 的永久存储方式,但这不常用。u-boot 在启动的时候会将存储在永久性存储介质中的 env 重新定位到 RAM 中,这样可以快速访问,同时可以通过saveenv将 RAM 中的 env 保存到永久性存储介质中。
在tools/env/fw_env.c中定义了表示env的数据结构
typedef struct environment_s {
ulong crc; /* CRC32 over data bytes */
uchar flags; /* active or obsolete */
uchar *data;
} env_t;
关于以上结构的说明:
crc是u-boot在保存env 的时候加上去的校验头,在第一次启动时一般 crc校验会出错,这很正常,因为这时 Flash中的数据无效。data字段保存实际的环境变量。u-boot的env按 name=value”\0”的方式存储,在所有env的最后以”\0\0”表示整个env的结束。新的name=value对总是被添加到env数据块的末尾,当删除一个name=value时,后面的环境变量将前移,对一个已经存在的环境变量的修改实际上先删除再插入。
env可以保存在 u-boot的TEXT段中,这样env就可以同u-boot一同加载入RAM中,这种方法没有测试过。
上文提到u-boot会将env从flash等存储设备重定位到RAM中,在env的不同实现版本( env_xxx.c )中定义了env_ptr, 它指向 env在RAM中的位置。u-boot在重定位env后对环境变量的操作都是针对 env_ptr。这个后面有说明。
env_t中除了数据之外还包含校验头,u-boot把env_t 的数据指针又保存在了另外一个地方,这就是 gd_t结构(不同平台有不同的 gd_t结构),这里以ARM为例仅列出和 env 相关的部分
这个结构体在U-Boot的include/asm-arm/global_data.h中定义如下:
typedef struct global_data {
bd_t *bd; //与板子相关的结构
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
unsigned long reloc_off; /* Relocation Offset */
unsigned long env_addr; /* Address of Environment struct */
........................
} gd_t;
gd_t.env_addr 即指向 env_ptr->data。
3.ENV的初始化
1):env_init函数
我们来看一下env_init函数,env 存储在不同的存储介质中,有不同的实现函数,这里以先以norflash,为例,它在common/env_flash.c中
在common/env_flash.c中对env_ptr定义如下:
char * env_name_spec = "Flash";
#ifdef ENV_IS_EMBEDDED
extern uchar environment[];
env_t *env_ptr = (env_t *)(&environment[0]); //env_ptr指向默认环境参数存放地址
#ifdef CMD_SAVEENV
/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#endif
#else /* ! ENV_IS_EMBEDDED */
env_t *env_ptr = (env_t *)CFG_ENV_ADDR; //env_ptr指向norflash环境参数存放地址
#ifdef CMD_SAVEENV
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#endif
#endif /* ENV_IS_EMBEDDED */
注:env_ptr在不同的存储介质中都有相应的定义
int env_init(void)
{
#ifdef CONFIG_OMAP2420H4
int flash_probe(void);
if(flash_probe() == 0)
goto bad_flash;
#endif
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { //使用norflash中环境参数
gd->env_addr = (ulong)&(env_ptr->data);
gd->env_valid = 1; 标识环境变量可用
return(0);
}
#ifdef CONFIG_OMAP2420H4
bad_flash:
#endif
gd->env_addr = (ulong)&default_environment[0];//否则使用默认的环境参数
gd->env_valid = 0; 使用默认环境变量参数,gd->env_valid设置为0,标识环境变量不可用
return (0);
}
实现 env的第一次初始化,对于nand env(非embedded方式)它在common/env_nand.c中:
char * env_name_spec = "NAND";
#ifdef ENV_IS_EMBEDDED
extern uchar environment[];
env_t *env_ptr = (env_t *)(&environment[0]); //env_ptr指向默认环境参数存放地址
#else /* ! ENV_IS_EMBEDDED */
env_t *env_ptr = 0; //env_ptr初始化为空指针
#endif /* ENV_IS_EMBEDDED */
/* local functions */
#if !defined(ENV_IS_EMBEDDED)
static void use_default(void);
#endif
int env_init(void)
{
#if defined(ENV_IS_EMBEDDED)
ulong total;
int crc1_ok = 0, crc2_ok = 0;
env_t *tmp_env1, *tmp_env2;
total = CFG_ENV_SIZE;
tmp_env1 = env_ptr;
tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);
crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
if (!crc1_ok && !crc2_ok)
gd->env_valid = 0;
else if(crc1_ok && !crc2_ok)
gd->env_valid = 1;
else if(!crc1_ok && crc2_ok)
gd->env_valid = 2;
else {
/* both ok - check serial */
if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
gd->env_valid = 2;
else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
gd->env_valid = 1;
else if(tmp_env1->flags > tmp_env2->flags)
gd->env_valid = 1;
else if(tmp_env2->flags > tmp_env1->flags)
gd->env_valid = 2;
else /* flags are equal - almost impossible */
gd->env_valid = 1;
}
if (gd->env_valid == 1)
env_ptr = tmp_env1;
else if (gd->env_valid == 2)
env_ptr = tmp_env2;
#else /* ENV_IS_EMBEDDED */
gd->env_addr = (ulong)&default_environment[0];//非embedded方式
gd->env_valid = 1; //env有效位置1,标识环境变量可用
#endif /* ENV_IS_EMBEDDED */
return (0);
}
2)环境变量的初始化env_relocate
common/env_common.c
void env_relocate (void)
{
DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
gd->reloc_off);
#ifdef CONFIG_AMIGAONEG3SE //未定义
enable_nvram();
#endif
#ifdef ENV_IS_EMBEDDED //未定义
/*
* The environment buffer is embedded with the text segment,
* just relocate the environment pointer
*/
env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else
/*
* We must allocate a buffer for the environment
*/
env_ptr = (env_t *)malloc (CFG_ENV_SIZE); //env_ptr重定位到内存空间
DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif
/*
* After relocation to RAM, we can always use the "memory" functions
*/
env_get_char = env_get_char_memory; //重新初始化函数指针,该函数指针原来在common/env_common.c文件中被初始化为env_get_char_init,现在改为env_get_char_memory。对于nand flash,这两个函数是一样的。
if (gd->env_valid == 0) { //在 env_annd.c和env_flash.c : env_init 中已经将 gd->env_valid 置1
#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 (-1);
#endif
if (sizeof(default_environment) > ENV_SIZE)
{
puts ("*** Error - default environment is too large\n\n");
return;
}
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; //标识环境变量可用
}
else {
env_relocate_spec ();//如果flash上有参数表可用,则从flash上加载,通过调用具体的env_relocate_spec函数来实现
}
gd->env_addr = (ulong)&(env_ptr->data); //最终完成将环境变量搬移到内存,即将环境变量的值赋值给全局变量gd->env_addr,这样只要通过这个全局变量就可以访问这些变量了。值得一提的是,字符串数组data里面的变量与变量之间是通过’\0’来分割的。
#ifdef CONFIG_AMIGAONEG3SE
disable_nvram();
#endif
}
这里涉及到两个和环境变量有关的宏,都在include/configs/smdk2410.h配置文件中定义
ENV_IS_EMBEDDED : env 是否存在于u-boot TEXT段中,未定义
CFG_ENV_SIZE : env 块的大小
实际上还需要几个宏来控制u-boot 对环境变量的处理
CFG_ENV_IS_IN_NAND : env 块是否存在于Nand Flash 中
CFG_ENV_OFFSET : env 块在 Flash 中偏移地址
#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */
#define CFG_FLASH_BASE PHYS_FLASH_1
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#if 0
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
#endif
#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */
#ifdef CONFIG_AMD_LV800
#define PHYS_FLASH_SIZE 0x00100000 /* 1MB */
#define CFG_MAX_FLASH_SECT (19) /* max number of sectors on one chip */
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */
#endif
#ifdef CONFIG_AMD_LV400
#define PHYS_FLASH_SIZE 0x00080000 /* 512KB */
#define CFG_MAX_FLASH_SECT (11) /* max number of sectors on one chip */
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x070000) /* addr of environment */
#endif
/* timeout values are in ticks */
#define CFG_FLASH_ERASE_TOUT (5*CFG_HZ) /* Timeout for Flash Erase */
#define CFG_FLASH_WRITE_TOUT (5*CFG_HZ) /* Timeout for Flash Write */
#define CFG_ENV_IS_IN_FLASH 1
#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */
3、env_relocate_spec
env_relocate_spec针对不同的存储介质有不同的实现
env_relocate_spec在common/env_flash.c中的实现
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
#ifdef CFG_ENV_ADDR_REDUND //未定义,boot的参数表还支持一种被称为CFG_ENV_OFFSET_REDUND的冗余模式,它会在flash上保存两个参数表副本,这样在一个副本出错的时候,还可以从另一个副本中去读取,通过这种方式,提高了数据的安全性。
if (gd->env_addr != (ulong)&(flash_addr->data)) {
env_t * etmp = flash_addr;
ulong ltmp = end_addr;
flash_addr = flash_addr_new;
flash_addr_new = etmp;
end_addr = end_addr_new;
end_addr_new = ltmp;
}
if (flash_addr_new->flags != OBSOLETE_FLAG &&
crc32(0, flash_addr_new->data, ENV_SIZE) ==
flash_addr_new->crc) {
char flag = OBSOLETE_FLAG;
gd->env_valid = 2;
flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new);
flash_write(&flag,
(ulong)&(flash_addr_new->flags),
sizeof(flash_addr_new->flags));
flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
}
if (flash_addr->flags != ACTIVE_FLAG &&
(flash_addr->flags & ACTIVE_FLAG) == ACTIVE_FLAG) {
char flag = ACTIVE_FLAG;
gd->env_valid = 2;
flash_sect_protect (0, (ulong)flash_addr, end_addr);
flash_write(&flag,
(ulong)&(flash_addr->flags),
sizeof(flash_addr->flags));
flash_sect_protect (1, (ulong)flash_addr, end_addr);
}
if (gd->env_valid == 2)
puts ("*** Warning - some problems detected "
"reading environment; recovered successfully\n\n");
#endif /* CFG_ENV_ADDR_REDUND */
memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE); //读出操作,将环境参数重定向到RAM中
#endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */
}
env_relocate_spec在common/env_nand.c中的实现
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 */
}
static void use_default()
{
puts ("*** Warning - bad CRC or NAND, using default environment\n\n");
if (default_environment_size > CFG_ENV_SIZE){
puts ("*** Error - default environment is too large\n\n");
return;
}
memset (env_ptr, 0, sizeof(env_t));
memcpy (env_ptr->data,
default_environment,
default_environment_size);
env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
gd->env_valid = 1; //设置环境参数有效
}
4、读取环境变量
Uboot中经常要读取环境变量,这是通过getenv来实现的:
它定义在common/cmd_nvedit.c文件中
char *getenv (char *name)
{
int i, nxt;
{
int i, nxt;
WATCHDOG_RESET();
for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
int val;
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);
if (nxt >= CFG_ENV_SIZE) {
return (NULL);
}
}
if ((val=envmatch((uchar *)name, i)) < 0)
continue;
return ((char *)env_get_addr(val));
}
}
这里重点理解env_get_char函数,它定义在common/env_common.c中:
static uchar env_get_char_init (int index);
uchar (*env_get_char)(int) = env_get_char_init;
uchar (*env_get_char)(int) = env_get_char_init;
/************************************************************************
* Default settings to be used when no valid environment is found
*/
#define XMK_STR(x) #x
#define MK_STR(x) XMK_STR(x)
* Default settings to be used when no valid environment is found
*/
#define XMK_STR(x) #x
#define MK_STR(x) XMK_STR(x)
uchar default_environment[] = {
#ifdef CONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
#ifdef CONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
.................
static uchar env_get_char_init (int index)
{
uchar c;
{
uchar c;
/* if crc was bad, use the default environment */
if (gd->env_valid)
{
c = env_get_char_spec(index);
} else {
c = default_environment[index];
}
if (gd->env_valid)
{
c = env_get_char_spec(index);
} else {
c = default_environment[index];
}
return (c);
}
注意:环境变量的初始化函数env_relocate中,将env_get_char函数指针由原来在common/env_common.c文件中被初始化为env_get_char_init,又重新初始化为env_get_char_memory了。对于nor和nand flash,这两个函数是一样的。
common/env_common.c
uchar env_get_char_memory (int index)
{
if (gd->env_valid) {
return ( *((uchar *)(gd->env_addr + index)) );
} else {
return ( default_environment[index] );
}
} 该函数获取环境变量数组中下标为index的字符。
这里 gd->env_valid参数在start_armboot函数中的初始化函数例表中的env_init函数中设置,如果配置参数保存在 flash中,gd->env_valid被设置为1,这里就通过env_get_char_spec函数从flash中取参数,否则 gd->env_valid设置为0,使用默认环境变量参数,默认环境变量参数定义在u-boot的common/env_common.c文件 uchar default_environment[] ,也就是include/configs/smdk2410.h配置文件中配置的参数。这里针对不同的flash存储芯片有不同的 env_get_char_spec定义
}
注意:环境变量的初始化函数env_relocate中,将env_get_char函数指针由原来在common/env_common.c文件中被初始化为env_get_char_init,又重新初始化为env_get_char_memory了。对于nor和nand flash,这两个函数是一样的。
common/env_common.c
uchar env_get_char_memory (int index)
{
if (gd->env_valid) {
return ( *((uchar *)(gd->env_addr + index)) );
} else {
return ( default_environment[index] );
}
} 该函数获取环境变量数组中下标为index的字符。
这里 gd->env_valid参数在start_armboot函数中的初始化函数例表中的env_init函数中设置,如果配置参数保存在 flash中,gd->env_valid被设置为1,这里就通过env_get_char_spec函数从flash中取参数,否则 gd->env_valid设置为0,使用默认环境变量参数,默认环境变量参数定义在u-boot的common/env_common.c文件 uchar default_environment[] ,也就是include/configs/smdk2410.h配置文件中配置的参数。这里针对不同的flash存储芯片有不同的 env_get_char_spec定义
common/env_flash.c
uchar env_get_char_spec (int index)
{
return ( *((uchar *)(gd->env_addr + index)) );
}
{
return ( *((uchar *)(gd->env_addr + index)) );
}
common/env_nand.c
DECLARE_GLOBAL_DATA_PTR;
uchar env_get_char_spec (int index)
{
return ( *((uchar *)(gd->env_addr + index)) );
}
{
return ( *((uchar *)(gd->env_addr + index)) );
}
common/env_nvram.c
#ifdef CONFIG_AMIGAONEG3SE
uchar env_get_char_spec (int index)
{
#ifdef CFG_NVRAM_ACCESS_ROUTINE
uchar c;
uchar env_get_char_spec (int index)
{
#ifdef CFG_NVRAM_ACCESS_ROUTINE
uchar c;
nvram_read(&c, CFG_ENV_ADDR+index, 1);
return c;
#else
uchar retval;
enable_nvram();
retval = *((uchar *)(gd->env_addr + index));
disable_nvram();
return retval;
#endif
}
#else
uchar env_get_char_spec (int index)
{
#ifdef CFG_NVRAM_ACCESS_ROUTINE
uchar c;
#else
uchar retval;
enable_nvram();
retval = *((uchar *)(gd->env_addr + index));
disable_nvram();
return retval;
#endif
}
#else
uchar env_get_char_spec (int index)
{
#ifdef CFG_NVRAM_ACCESS_ROUTINE
uchar c;
nvram_read(&c, CFG_ENV_ADDR+index, 1);
return c;
#else
return *((uchar *)(gd->env_addr + index));
#endif
}
#endif
env_get_char_init函数功能就是如果保存了参数到flsah中就调用env_get_char_spec从指定的flash地址中读取参数字符,否则就从默认环境变量参数中读取参数字符。
理解完env_get_char_init函数后,再来看envmatch函数,定义在common/cmd_nvedit.c
/************************************************************************
* 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.
*/
* 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)
{
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’符号隔开,即是当遇到该符号时,则表示一个变量结束而另一个变量开始。
if (*s1++ == '=')
return(i2);
if (*s1 == '\0' && env_get_char(i2-1) == '=')
return(i2);
return(-1);
}
这个函数功能是查找符号变量,如果找到则返回等号后面的字符串指针,即为变量的值,环境变量表是一个字符串数组,而其中的变量之间通过’\0’符号隔开,即是当遇到该符号时,则表示一个变量结束而另一个变量开始。
common/env_common.c
uchar *env_get_addr (int index)
{
if (gd->env_valid) {
return ( ((uchar *)(gd->env_addr + index)) );
} else {
return (&default_environment[index]);
}
}
这个函数功能是返回找到的环境变量字符串数组地址。
5、环境变量的设置过程
commom/cmd_nvedit.c
void setenv (char *varname, char *varvalue)
{
char *argv[4] = { "setenv", varname, varvalue, NULL };
_do_setenv (0, 3, argv);
}
{
char *argv[4] = { "setenv", varname, varvalue, NULL };
_do_setenv (0, 3, argv);
}
int do_setenv ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
if (argc < 2) {
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
}
return _do_setenv (flag, argc, argv);
{
if (argc < 2) {
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
}
}
int _do_setenv (int flag, int argc, char *argv[])
{
int i, len, oldval;
int console = -1;
uchar *env, *nxt = NULL;
char *name;
bd_t *bd = gd->bd;
uchar *env_data = env_get_addr(0);
if (!env_data) /* need copy in RAM */
return 1;
name = argv[1];
if (strchr(name, '=')) {
printf ("## Error: illegal character '=' in variable name \"%s\"\n", name);
return 1;
}
/*
* search if variable with this name already exists
*/
oldval = -1;
for (env=env_data; *env; env=nxt+1) {
for (nxt=env; *nxt; ++nxt)
;
if ((oldval = envmatch((uchar *)name, env-env_data)) >= 0)
break;
}
/*
* Delete any existing definition
*/
if (oldval >= 0) {
#ifndef CONFIG_ENV_OVERWRITE
/*
* Ethernet Address and serial# can be set only once,
* ver is readonly.
*/
if ( (strcmp (name, "serial#") == 0) ||
((strcmp (name, "ethaddr") == 0)
#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
&& (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
) ) {
printf ("Can't overwrite \"%s\"\n", name);
return 1;
}
#endif
/* Check for console redirection */
if (strcmp(name,"stdin") == 0) {
console = stdin;
} else if (strcmp(name,"stdout") == 0) {
console = stdout;
} else if (strcmp(name,"stderr") == 0) {
console = stderr;
}
if (console != -1) {
if (argc < 3) { /* Cannot delete it! */
printf("Can't delete \"%s\"\n", name);
return 1;
}
/* Try assigning specified device */
if (console_assign (console, argv[2]) < 0)
return 1;
#ifdef CONFIG_SERIAL_MULTI
if (serial_assign (argv[2]) < 0)
return 1;
#endif
}
/*
* Switch to new baudrate if new baudrate is supported
*/
if (strcmp(argv[1],"baudrate") == 0) {
int baudrate = simple_strtoul(argv[2], NULL, 10);
int i;
for (i=0; i<N_BAUDRATES; ++i) {
if (baudrate == baudrate_table[i])
break;
}
if (i == N_BAUDRATES) {
printf ("## Baudrate %d bps not supported\n",
baudrate);
return 1;
}
printf ("## Switch baudrate to %d bps and press ENTER ...\n",
baudrate);
udelay(50000);
gd->baudrate = baudrate;
#ifdef CONFIG_PPC
gd->bd->bi_baudrate = baudrate;
#endif
serial_setbrg ();
udelay(50000);
for (;;) {
if (getc() == '\r')
break;
}
}
if (*++nxt == '\0') {
if (env > env_data) {
env--;
} else {
*env = '\0';
}
} else {
for (;;) {
*env = *nxt++;
if ((*env == '\0') && (*nxt == '\0'))
break;
++env;
}
}
*++env = '\0';
}
#ifdef CONFIG_NET_MULTI
if (strncmp(name, "eth", 3) == 0) {
char *end;
int num = simple_strtoul(name+3, &end, 10);
if (strcmp(end, "addr") == 0) {
eth_set_enetaddr(num, argv[2]);
}
}
#endif
/* Delete only ? */
if ((argc < 3) || argv[2] == NULL) {
env_crc_update ();
return 0;
}
/*
* Append new definition at the end
*/
for (env=env_data; *env || *(env+1); ++env)
;
if (env > env_data)
++env;
/*
* Overflow when:
* "name" + "=" + "val" +"\0\0" > ENV_SIZE - (env-env_data)
*/
len = strlen(name) + 2;
/* add '=' for first arg, ' ' for all others */
for (i=2; i<argc; ++i) {
len += strlen(argv[i]) + 1;
}
if (len > (&env_data[ENV_SIZE]-env)) {
printf ("## Error: environment overflow, \"%s\" deleted\n", name);
return 1;
}
while ((*env = *name++) != '\0')
env++;
for (i=2; i<argc; ++i) {
char *val = argv[i];
*env = (i==2) ? '=' : ' ';
while ((*++env = *val++) != '\0')
;
}
/* end is marked with double '\0' */
*++env = '\0';
/* Update CRC */
env_crc_update ();
/*
* Some variables should be updated when the corresponding
* entry in the enviornment is changed
*/
if (strcmp(argv[1],"ethaddr") == 0) {
char *s = argv[2]; /* always use only one arg */
char *e;
for (i=0; i<6; ++i) {
bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
if (s) s = (*e) ? e+1 : e;
}
#ifdef CONFIG_NET_MULTI
eth_set_enetaddr(0, argv[2]);
#endif
return 0;
}
if (strcmp(argv[1],"ipaddr") == 0) {
char *s = argv[2]; /* always use only one arg */
char *e;
unsigned long addr;
bd->bi_ip_addr = 0;
for (addr=0, i=0; i<4; ++i) {
ulong val = s ? simple_strtoul(s, &e, 10) : 0;
addr <<= 8;
addr |= (val & 0xFF);
if (s) s = (*e) ? e+1 : e;
}
bd->bi_ip_addr = htonl(addr);
return 0;
}
if (strcmp(argv[1],"loadaddr") == 0) {
load_addr = simple_strtoul(argv[2], NULL, 16);
return 0;
}
#if (CONFIG_COMMANDS & CFG_CMD_NET)
if (strcmp(argv[1],"bootfile") == 0) {
copy_filename (BootFile, argv[2], sizeof(BootFile));
return 0;
}
#endif /* CFG_CMD_NET */
#ifdef CONFIG_AMIGAONEG3SE
if (strcmp(argv[1], "vga_fg_color") == 0 ||
strcmp(argv[1], "vga_bg_color") == 0 ) {
extern void video_set_color(unsigned char attr);
extern unsigned char video_get_attr(void);
video_set_color(video_get_attr());
return 0;
}
#endif /* CONFIG_AMIGAONEG3SE */
return 0;
}
6、环境变量的保存,保存是读取的反过程,所以跟上面的过程相似,如下:
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))
return 1;
puts ("Writing to Nand... "); //后写入
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;
}
common/env_flash.c
int saveenv(void)
{
char *saved_data = NULL;
int rc = 1;
char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
#if CFG_ENV_SECT_SIZE > CFG_ENV_SIZE
ulong up_data = 0;
#endif
debug ("Protect off %08lX ... %08lX\n",
(ulong)flash_addr, end_addr);
if (flash_sect_protect (0, (ulong)flash_addr, end_addr)) {
goto Done;
}
debug ("Protect off %08lX ... %08lX\n",
(ulong)flash_addr_new, end_addr_new);
if (flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new)) {
goto Done;
}
#if CFG_ENV_SECT_SIZE > CFG_ENV_SIZE
up_data = (end_addr_new + 1 - ((long)flash_addr_new + CFG_ENV_SIZE));
debug ("Data to save 0x%x\n", up_data);
if (up_data) {
if ((saved_data = malloc(up_data)) == NULL) {
printf("Unable to save the rest of sector (%ld)\n",
up_data);
goto Done;
}
memcpy(saved_data,
(void *)((long)flash_addr_new + CFG_ENV_SIZE), up_data);
debug ("Data (start 0x%x, len 0x%x) saved at 0x%x\n",
(long)flash_addr_new + CFG_ENV_SIZE,
up_data, saved_data);
}
#endif
puts ("Erasing Flash...");
debug (" %08lX ... %08lX ...",
(ulong)flash_addr_new, end_addr_new);
if (flash_sect_erase ((ulong)flash_addr_new, end_addr_new)) {
goto Done;
}
puts ("Writing to Flash... ");
debug (" %08lX ... %08lX ...",
(ulong)&(flash_addr_new->data),
sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
if ((rc = flash_write((char *)env_ptr->data,
(ulong)&(flash_addr_new->data),
sizeof(env_ptr->data))) ||
(rc = flash_write((char *)&(env_ptr->crc),
(ulong)&(flash_addr_new->crc),
sizeof(env_ptr->crc))) ||
(rc = flash_write(&flag,
(ulong)&(flash_addr->flags),
sizeof(flash_addr->flags))) ||
(rc = flash_write(&new_flag,
(ulong)&(flash_addr_new->flags),
sizeof(flash_addr_new->flags))))
{
flash_perror (rc);
goto Done;
}
puts ("done\n");
#if CFG_ENV_SECT_SIZE > CFG_ENV_SIZE
if (up_data) { /* restore the rest of sector */
debug ("Restoring the rest of data to 0x%x len 0x%x\n",
(long)flash_addr_new + CFG_ENV_SIZE, up_data);
if (flash_write(saved_data,
(long)flash_addr_new + CFG_ENV_SIZE,
up_data)) {
flash_perror(rc);
goto Done;
}
}
#endif
{
env_t * etmp = flash_addr;
ulong ltmp = end_addr;
flash_addr = flash_addr_new;
flash_addr_new = etmp;
end_addr = end_addr_new;
end_addr_new = ltmp;
}
rc = 0;
Done:
if (saved_data)
free (saved_data);
/* try to re-protect */
(void) flash_sect_protect (1, (ulong)flash_addr, end_addr);
(void) flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
return rc;
}