uboot參數(shù)表的結(jié)構(gòu)和操作(R.wen)
1、參數(shù)表的結(jié)構(gòu)定義在environment.c中,如下:
#ifdef CFG_REDUNDAND_ENVIRONMENT
# define ENV_HEADER_SIZE (sizeof(unsigned long) + 1)
#else
# define ENV_HEADER_SIZE (sizeof(unsigned long))
#endif
//除去參數(shù)表頭后參數(shù)的長度最值
#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;
結(jié) 構(gòu)env_t參數(shù)表的結(jié)構(gòu)非常簡單,第一個成員就是crc,用于crc32校驗,第二個參數(shù)是冗余的標(biāo)志,最后一個就是參數(shù)數(shù)組了。所以參數(shù)頭的長度 ENV_HEADER_SIZE就是crc與flags之和,即為sizeof(long)+sizeof(char)。這個結(jié)構(gòu)就是在內(nèi)存和flash 上表示參數(shù)表的結(jié)構(gòu)。
參數(shù)表的最后一個成員data數(shù)組中存放所有的環(huán)境變量值,每個變量和值用‘=’號連接,而兩個變量之間則通過’\分開,如下:
uchar default_environment[] = {
#ifdef CONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
#ifdef CONFIG_BOOTCOMMAND
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
#endif
……
"\0"
};
2、環(huán)境變量的初始化env_relocate()
Uboot在完成匯編部分的初始化之后,將跳到start_armboot()去執(zhí)行,其中便會執(zhí)行env_relocate()初始化環(huán)境變量。
去除了一些不執(zhí)行的代碼后,這個函數(shù)如下:
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;
第二步,重新初始化函數(shù)指針,
static uchar env_get_char_init (int index);
uchar (*env_get_char)(int) = env_get_char_init;
該函數(shù)指針原來被初始化為env_get_char_init,現(xiàn)在改為env_get_char_memory。對于nand flash,這兩個函數(shù)是一樣的。
第三步,如果flash沒有參數(shù)表,則使用默認(rèn)參數(shù),這里是通過default_env()來加載。
void default_env(void)
{
memset (env_ptr, 0, sizeof(env_t));
memcpy (env_ptr->data,
default_environment,
sizeof(default_environment)); //拷貝環(huán)境變量
#ifdef CFG_REDUNDAND_ENVIRONMENT
env_ptr->flags = 0xFF;
#endif
env_crc_update (); //更新crc32校驗
gd->env_valid = 1; //標(biāo)識環(huán)境變量可用
}
第四步,如果flash上有參數(shù)表可用,則從flash上加載,通過env_relocate_spec()來實現(xiàn):
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED) //如果不是使用嵌入?yún)?shù)的形式,即為參數(shù)表的形式
ulong total;
int ret;
total = CFG_ENV_SIZE; //參數(shù)表大小,包括參數(shù)表頭部
//讀出操作,flash設(shè)備為nand_info,偏移為CFG_ENV_OFFSET,讀出的大小為total,目標(biāo)地址由env_ptr所指。
ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
//如果讀出的長度不對或出錯,則使用默認(rèn)值
if (ret || total != CFG_ENV_SIZE)
return use_default();
//如果校驗出錯,使用默認(rèn)值
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}
此外,uboot的參數(shù)表還支持一種被稱為CFG_ENV_OFFSET_REDUND的冗余模式,它會在flash上保存兩個參數(shù)表副本,這樣在一個副本出錯的時候,還可以從另一個副本中去讀取,通過這種方式,提高了數(shù)據(jù)的安全性。
第五步,gd->env_addr = (ulong)&(env_ptr->data)
即將環(huán)境變量的值賦值給全局變量gd->env_addr,這樣只要通過這個全局變量就可以訪問這些變量了。
值得一提的是,字符串?dāng)?shù)組data里面的變量與變量之間是通過’\來分割的。
3、環(huán)境變量的保存,保存是讀取的反過程,所以跟上面的過程相似,如下:
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、讀取環(huán)境變量
Uboot中經(jīng)常要讀取環(huán)境變量,這是通過getenv來實現(xiàn)的:
/ * 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;
//通過所得的下標(biāo)返回變量值的指針,由于是字符串指針,所以它在碰到’\符合時結(jié)束,即為該變量的值。
return ((char *)env_get_addr(val));
}
return (NULL);
}
通過輸入變量的名字,返回變量的值。
前面已經(jīng)提到,函數(shù)指針env_get_char已經(jīng)被初始化為env_get_char_memory:
該函數(shù)獲取環(huán)境變量數(shù)組中下標(biāo)為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);
}
如前所述,環(huán)境變量表是一個字符串?dāng)?shù)組,而其中的變量之間通過’\符號隔開,即是當(dāng)遇到該符號時,則表示一個變量結(jié)束而另一個變量開始。




