本文主要以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; 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); } 这里重点理解env_get_char函数,它定义在common/env_common.c中:static uchar env_get_char_init (int index); 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) uchar default_environment[] = { #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "\0" #endif ................. static uchar env_get_char_init (int index) { 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]; } 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定义 common/env_flash.c uchar env_get_char_spec (int 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)) ); } common/env_nvram.c #ifdef CONFIG_AMIGAONEG3SE 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; 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. */ 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’符号隔开,即是当遇到该符号时,则表示一个变量结束而另一个变量开始。 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); } 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); } 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) 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) + 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; *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 = 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; } |
uboot环境变量的实现和读取设置
最新推荐文章于 2024-08-12 16:30:07 发布