亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1983 | 回復(fù): 0
打印 上一主題 下一主題

U-BOOT環(huán)境變量實現(xiàn) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2010-02-22 16:58 |只看該作者 |倒序瀏覽
1.相關(guān)文件common/env_common.c
供u-boot調(diào)用的通用函數(shù)接口,它們隱藏了env的不同實現(xiàn)方式,比如dataflash, epprom, flash等

common/env_dataflash.c
env 存儲在dataflash中的實現(xiàn)

common/env_epprom.c
env 存儲在epprom中的實現(xiàn)

common/env_flash.c
env 存儲在flash中的實現(xiàn)

common/env_nand.c
env 存儲在nand中的實現(xiàn)

common/env_nvedit.c
實現(xiàn)u-boot對環(huán)境變量的操作命令

environment.c
環(huán)境變量以及一些宏定義

env如果存儲在Flash中還需要Flash的支持。
2.數(shù)據(jù)結(jié)構(gòu)env 在 u-boot 中通常有兩種存在方式,在永久性存儲介質(zhì)中( Flash NVRAM等 )在SDRAM,可以配置不使用 env 的永久存儲方式,但這不常用。u-boot 在啟動的時候會將存儲在永久性存儲介質(zhì)中的 env 重新定位到 RAM 中,這樣可以快速訪問,同時可以通過saveenv將 RAM 中的 env 保存到永久性存儲介質(zhì)中。

在include/environment.h中定義了表示env的數(shù)據(jù)結(jié)構(gòu)

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;
關(guān)于以上結(jié)構(gòu)的說明:
crc是u-boot在保存env 的時候加上去的校驗頭,在第一次啟動時一般 crc校驗會出錯,這很正常,因為這時 Flash中的數(shù)據(jù)無效。
data字段保存實際的環(huán)境變量。u-boot 的 env 按 name=value”\0”的方式存儲,在所有env的最后以”\0\0”表示整個 env 的結(jié)束。新的name=value對總是被添加到 env 數(shù)據(jù)塊的末尾,當(dāng)刪除一個name=value對時,后面的環(huán)境變量將前移,對一個已經(jīng)存在的環(huán)境變量的修改實際上先刪除再插入。
env 可以保存在 u-boot 的 TEXT 段中,這樣 env 就可以同 u-boot 一同加載入RAM中,這種方法沒有測試過。
       上文提到u-boot會將 env 從 flash 等存儲設(shè)備重定位到 RAM 中,在 env 的不同實現(xiàn)版本( env_xxx.c )中定義了 env_ptr, 它指向 env在RAM中的位置。u-boot在重定位 env后對環(huán)境變量的操作都是針對 env_ptr。
       env_t 中除了數(shù)據(jù)之外還包含校驗頭,u-boot 把env_t 的數(shù)據(jù)指針有保存在了另外一個地方,這就是 gd_t 結(jié)構(gòu)( 不同平臺有不同的 gd_t結(jié)構(gòu) ),這里以ARM為例僅列出和 env 相關(guān)的部分
typedef struct global_data
{
       …
       unsigned long env_off;         /* Relocation Offset */
       unsigned long env_addr;        /* Address of Environment struct ??? */
       unsigned long env_valid        /* Checksum of Environment valid */
       …
} gd_t;
ta.h>
gd_t.env_addr 即指向 env_ptr->data。





3.ENV 的初始化

500)this.width=500;" border=0>
start_armboot : ( lib_arm/board.c )
*env_init : env_xxx.c( xxx = nand | flash | epprom … )
env_relocate : env_common.c
*env_relocate_spec : env_xxx.c( xxx=nand | flash | eporom… )
3.1env_init實現(xiàn) env 的第一次初始化,對于nand env (非embedded方式):
Env_nand.c : env_init
gd->env_addr = (ulong)&default_environment[0]; //先使gd->env_addr指向默認(rèn)的環(huán)境變量
gd->env_valid = 1;// env 有效位置1
3.2 env_relocate#ifdefine ENV_IS_EMBEDDED
…(略)
#else
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
#endif
if( gd->env_valid == 0) // 在 Env_annd.c : env_init 中已經(jīng)將 gd->env_valid 置1
{
       …
}
else
       env_relocate_spec ();// 調(diào)用具體的 env_relocate_spec 函數(shù)
gd->env_addr = (ulong)&(env_ptr->data);// 最終完成將環(huán)境變量搬移到內(nèi)存
這里涉及到兩個和環(huán)境變量有關(guān)的宏
ENV_IS_EMBEDDED : env 是否存在于 u-boot TEXT 段中
CFG_ENV_SIZE : env 塊的大小
實際上還需要幾個宏來控制u-boot 對環(huán)境變量的處理
CFG_ENV_IS_IN_NAND : env 塊是否存在于Nand Flash 中
CFG_ENV_OFFSET : env 塊在 Flash 中偏移地址

3.3*env_relocate_spec這里僅分析 Nand Flash 的 env_relocate_spec 實現(xiàn)
如果未設(shè)置 CFG_ENV_OFFSET_REDUND,env_relocate_spec的實現(xiàn)如下 :
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
       ulong total;
       int ret;

       total = CFG_ENV_SIZE;
       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 */
}
上面的代碼很清楚的表明了 env_relocate_spec 的意圖,調(diào)用 nand_read 將環(huán)境變量從 CFG_ENV_OFFSET 處讀出,環(huán)境變量的大小為CFG_ENV_SIZE 注意 CFG_ENV_OFFSET和 CFG_ENV_SIZE 要和 Nand Flash 的塊/頁邊界對齊。讀出數(shù)據(jù)后再調(diào)用crc32 對env_ptr->data進行校驗并與保存在 env_ptr->crc 的校驗碼對比,看數(shù)據(jù)是否出錯,從這里也可以看出在系統(tǒng)第一次啟動時,Nand Flash 里面沒有存儲任何環(huán)境變量,crc校驗肯定回出錯,當(dāng)我們保存環(huán)境變量后,接下來再啟動板子u-boot就不會再報crc32出錯了。
4. ENV 的保存由上問的論述得知, env 將從永久性存儲介質(zhì)中搬到RAM里面,以后對env 的操作,比如修改環(huán)境變量的值,刪除環(huán)境變量的值都是對這個 env 在RAM中的拷貝進行操作,由于RAM的特性,下次啟動時所做的修改將全部消失,u-boot提供了將env 寫回 永久性存儲介質(zhì)的命令支持 : saveenv,不同版本的 env ( nand flash, flash … )實現(xiàn)方式不同,以Nand Flash 的實現(xiàn)(未定義CFG_ENV_OFFSET_REDUND)為例
Env_nand.c : saveenv
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;
}
Nand Flash 的 saveenv 命令實現(xiàn)很簡單,調(diào)用nand_erase 和nand_write進行Nand Flash的 erase, write。nand_write/erase使用的是u-boot 的nand驅(qū)動框架,我在做開發(fā)的過程中使用的是nand_legacy驅(qū)動,所以可以把nand_erase和nand_write改成nand_legacy_erase和nand_legacy_rw就可實現(xiàn)nand_legacy驅(qū)動的保存環(huán)境變量版本。
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)境變量值,每個變量和值用‘=’號連接,而兩個變量之間則通過’\0’分開,如下:
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里面的變量與變量之間是通過’\0’來分割的。
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))
                     continue;
              //通過所得的下標(biāo)返回變量值的指針,由于是字符串指針,所以它在碰到’\0’符合時結(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 / pair
*
* s1 is either a simple 'name', or a ' 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ù)組,而其中的變量之間通過’\0’符號隔開,即是當(dāng)遇到該符號時,則表示一個變量結(jié)束而另一個變量開始。
               
               
               
               

本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u3/91445/showart_2184050.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP