u-boot环境变量
来源:互联网 发布:java语言爱心代码表白 编辑:程序博客网 时间:2024/06/01 10:21
u-boot通过环境变量为用户提供一定程度的可配置性,如波特率,启动参数等。环境变量固化在非易失性存储介质中,通过saveenv来保存。可配置性意味着环境变量是可以添加、删除和修改的,也就是说环境变量的内容可能会频繁变化,为了不让这种变化对u-boot的代码和数据造成破坏,通常的选择是在FLASH中预留一个专门用来存储环境变量的块。
U-boot环境变量大致分为四个部分:环境变量的结构,初始化,环境变量的保存,环境变量的读取。根据这个思路,依次学习各个部分。
本例中环境变量存储在NAND FLASH上,且环境变量没有嵌入到u-boot中,即ENV_IS_EMBEDDED宏状态是undefined。NAND FLASH擦除以块为单位,一块的大小时128K,下图是本例u-boot和环境变量在NAND FLASH上的存储, 单独为环境变量分配了一个块的存储空间。
一、环境变量的结构
环境变量是一个结构体
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;
其中元素crc保存的是整个环境变量值做CRC运算的结果,用于校验环境变量是否合法。
元素data[ENV_SIZE] 保存了环境变量的值,下面是默认的环境变量的值,可以看出环境变量其实是一个字符串,由”\0”将每个变量分开,环境变量的末尾是”\0\0”。
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#ifdef CONFIG_LOADS_ECHO "loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"#endif#ifdef CONFIG_ETHADDR "ethaddr=" MK_STR(CONFIG_ETHADDR) "\0"#endif#ifdef CONFIG_ETH1ADDR "eth1addr=" MK_STR(CONFIG_ETH1ADDR) "\0"#endif#ifdef CONFIG_ETH2ADDR "eth2addr=" MK_STR(CONFIG_ETH2ADDR) "\0"#endif#ifdef CONFIG_ETH3ADDR "eth3addr=" MK_STR(CONFIG_ETH3ADDR) "\0"#endif#ifdef CONFIG_IPADDR "ipaddr=" MK_STR(CONFIG_IPADDR) "\0"#endif#ifdef CONFIG_SERVERIP "serverip=" MK_STR(CONFIG_SERVERIP) "\0"#endif#ifdef CFG_AUTOLOAD "autoload=" CFG_AUTOLOAD "\0"#endif#ifdef CONFIG_PREBOOT "preboot=" CONFIG_PREBOOT "\0"#endif#ifdef CONFIG_ROOTPATH "rootpath=" MK_STR(CONFIG_ROOTPATH) "\0"#endif#ifdef CONFIG_GATEWAYIP "gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"#endif#ifdef CONFIG_NETMASK "netmask=" MK_STR(CONFIG_NETMASK) "\0"#endif#ifdef CONFIG_HOSTNAME "hostname=" MK_STR(CONFIG_HOSTNAME) "\0"#endif#ifdef CONFIG_BOOTFILE "bootfile=" MK_STR(CONFIG_BOOTFILE) "\0"#endif#ifdef CONFIG_LOADADDR "loadaddr=" MK_STR(CONFIG_LOADADDR) "\0"#endif#ifdef CONFIG_CLOCKS_IN_MHZ "clocks_in_mhz=1\0"#endif#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0) "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"#endif#ifdef CONFIG_EXTRA_ENV_SETTINGS CONFIG_EXTRA_ENV_SETTINGS#endif "\0"};
二、环境变量的初始化
u-boot首先调用common/env_nand.c下的int env_init(void)函数。由于ENV_IS_EMBEDDED是未定义的,故初始化函数执行了两条语句,这里暂时认为CRC是正确的,在环境变量拷贝到SDRAM上之后再做校验。
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]; gd->env_valid = 1;#endif /* ENV_IS_EMBEDDED */ return (0);}
环境变量原本是存放在NAND FLASH上的,由于环境变量经常被用到,且NAND FLASH的擦写速度太慢,需要将环境变量从FLASH上拷贝到SDRAM上,u-boot通过调用env_relocate()完成这部分的操作。
void env_relocate (void){ DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__, gd->reloc_off);#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 */ //在malloc区分配大小为CFG_ENV_SIZE的空间,并将env_ptr指向该空间的起始地址。 env_ptr = (env_t *)malloc (CFG_ENV_SIZE); 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; // gd->env_valid的值为1 if (gd->env_valid == 0) {#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 (); gd->env_valid = 1; } else { // 从FLASH中读取环境变量的内容到SDRAM上。 env_relocate_spec (); } // gd->env_addr指向环境变量的第一个参数。 gd->env_addr = (ulong)&(env_ptr->data);}
通过env_relocate_spec ()读取环境变量到SDRAM上。请注意,刚烧写的板子上仅仅给环境变量预留了一定大小的空间,并没有环境变量的内容。根据重定位函数,我们知道板子第一次开机时,读出来的环境变量进行CRC校验时肯定是失败的,会使用预存的默认环境变量。
void env_relocate_spec (void){#if !defined(ENV_IS_EMBEDDED) ulong total = CFG_ENV_SIZE; int ret; // 读取FLASH上环境变量到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(); // 校验CRC,若失败,则使用默认的环境变量。 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); // 计算CRC,并赋给SDRAM上的env_ptr->crc env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE); gd->env_valid = 1;}
至此,环境变量的初始化就结束了,环境变量的值被拷贝到SDRAM,全局变量
gd->env_addr = (ulong)&(env_ptr->data); 指向了环境变量的第一个参数。
gd->env_valid = 1;
三、环境变量的保存
int saveenv(void)用来保存环境变量的。由于NAND FLASH的每个位只能从1->0,而不能相反,所以我们需要先对其擦除,然后再进行写操作。
int saveenv(void){ ulong total; int ret = 0; puts ("Erasing Nand..."); // 擦除FLASH,&nand_info[0]是NAND的起始地址,擦除操作从CFG_ENV_OFFSET开始,大小为CFG_ENV_SIZE。 if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE)) return 1; puts ("Writing to Nand... "); total = CFG_ENV_SIZE; // 写FLASH,&nand_info[0]是NAND的起始地址,将env_ptr所指向的内容写到CFG_ENV_OFFSET开始的位置,大小为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;}
关于环境变量的存储偏移量和大小相关的宏定义是下面这样。由于板子上用的NAND FLASH的块擦除的大小为128K (0x20000),下面的宏定义保证了环境变量保存在单独的一个NAND 块上。
#define CFG_ENV_OFFSET 0x40000#define CFG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
四、环境变量的读取
在u-boot运行时,我们可以使用U-boot命令配置环境变量而不是修改代码来控制U-boot的行为,如我们可以修改环境变量来配置开发板的IP地址。u-boot配置环境变量就是配置存储器上的某个地址的内容,读取这个地址的内容再进行接下来的操作。u-boot中读取环境变量的函数是common/cmd_nvedit.c下的
int getenv_r (char *name, char *buf, unsigned len)。
@para1: 需要读取的环境变量名
@para2: 若找到了该环境变量,将值存放到buf。
@para3: buf的长度
@return value: 若有该环境变量,返回值为环境变量参数的长度。否则返回-1
int getenv_r (char *name, char *buf, unsigned len){ int i, nxt; for (i=0; env_get_char(i) != '\0'; i=nxt+1) { int val, n; for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) { if (nxt >= CFG_ENV_SIZE) { return (-1); } } if ((val=envmatch((uchar *)name, i)) < 0) continue; /* found; copy out */ n = 0; while ((len > n++) && (*buf++ = env_get_char(val++)) != '\0') ; if (len == n) *buf = '\0'; return (n); } return (-1);}
其中 env_get_char指向函数env_get_char_memory。
功能是获取环境变量中,索引为index处的字符。
uchar env_get_char_memory (int index){ if (gd->env_valid) { // gd->env_addr是环境变量的首地址。 return ( *((uchar *)(gd->env_addr + index)) ); } else { return ( default_environment[index] ); }}
- U-BOOT环境变量实现
- U-BOOT环境变量实现
- U-BOOT环境变量实现
- U-BOOT环境变量实现
- U-BOOT环境变量实现
- U-BOOT环境变量实现
- U-Boot的环境变量
- U-Boot环境变量
- U-BOOT环境变量实现
- u-boot环境变量解释
- U-BOOT环境变量实现
- u-boot环境变量
- u-boot环境变量
- u-boot环境变量设置
- U-BOOT环境变量实现
- u-boot的环境变量
- U-BOOT环境变量实现
- U-BOOT环境变量实现
- 如何生成HLS协议的M3U8文件
- bzoj 4878: [Lydsy2017年5月月赛]挑战NP-Hard dfs
- Scala学习五:异常
- Unity5的AssetBundle打包方式简析
- 我与python约个会:17. 字符串详解及序列类型
- u-boot环境变量
- Handler机制原理
- js实现复制粘贴
- JVM调优总结(五)-分代垃圾回收详述1
- mysql干掉占用的链接
- 复制网页上的代码后去除前面的序号的简便方法
- 语音合成vocoder(三) spectral envelope参数
- Fragment相关
- for循环用于延时例子