uboot環境變量初始化


一、環境變量概述

1、環境變量的概念

     可以理解為用戶對軟件的全局配置信息,這部分信息應該可以從永久性存儲器上讀取,能被查詢,能被修改。

  啟動過程中,應該首先把環境變量讀取到合適的內存區域,然后利用環境變量初始化硬件、啟動操作系統等等。

2、啟動過程中環境變量初始化過程涉及的問題

       這里涉及到兩個問題:

   環境變量在哪個地方存着(從哪個地方取)

   將環境變量存儲到哪里(放到哪)

(1)環境變量位於存儲器(norflash、nandflash )

    “CFG_ENV_IS_IN_XXX”(CFG_ENV_IS_IN_FLASH、CFG_ENV_IS_IN_NAND等等)定義了則這種情況有效,以在flash上為例。

ENV_IS_EMBEDDED定義了

      詳細工作原理,見”ENV_IS_EMBEDDED“解惑以及相關的移植實驗。這種情況的環境變量在flash上存着(但是占了flash一個扇區),並且隨着代碼段(因為環境變量區嵌在代碼段內)在start.s重定位時一同載入內存。在環境變量初始化時候,如果這部分能通過校驗,就不需要先在堆區開辟空間然后搬移的工作,而是直接使用這部分環境變量(省了搬移工作)。倘若不能通過校驗,則使用默認環境變量放到重定位時環境變量所占的空間中。

ENV_IS_EMBEDDED沒有定義

       這種情況會在堆區為環境變量區開辟空間,如果flash上存儲的是有效的(能通過校驗)環境變量,則需要把flash上的數據搬運到堆區指定的位置;如果flash上的存儲是錯誤的環境變量,那么使用默認的環境變量(default_environment)放到堆區。

(2)沒有存儲器上存儲有環境變量 

    “CFG_ENV_IS_NOWHERE”定義了則選擇這種模式,使用common/env_nowhere.c文件而不是用env_flash.c、env_nvram.c等等文件。

  這種情況下,使用默認的環境變量(default_environment)。先在堆區為環境變量開辟空間,然后啟動搬運工作。

二、環境變量初始化流程

  以環境變量位於NorFlash上,並且沒有使能“ENV_IS_EMBEDDED”功能為例,進行以下內容的分析。其他情況本文不討論。

1、校驗

 直接在NorFlash上校驗環境變量,實際上這一步是確定環境變量的源。如果NorFlash上存儲的是有效的環境變量的話,那么就從NorFlash上讀取數據。倘若NorFlash上存儲的是無效的環境變量,那么使用默認的環境變量作為源。

2、重定位

  將從存儲環境變量的存儲區加載到系統指定的位置。

3、涉及到的函數

(1)env_init

  完成校驗,並決定環境變量的源

  此函數在start_armboot函數的開始階段,會依次執行“init_sequence”中的每一個函數,其中一個就是env_init。

(2)env_relocate

  首先,在堆區為環境變量開辟存儲緩沖區。另外,當NorFlash上的環境變量區是無效的時候,選擇默認的環境變量區進行定位。當NorFlash上的環境變量區是有效的時候,調用env_relocate_spec進行重定位。

  此函數是在start_armboot函數的中途階段,在NorFlash和NandFlash都初始化后,會調用這個函數。

(3)env_relocate_spec

  此函數是被env_relocate所調用。

三、代碼分析

1、相關全局變量

1> env_ptr(common/env_flash.c)

env_t *env_ptr = (env_t *)CFG_ENV_ADDR; // 定義flash中環境變量的地址
#ifdef CMD_SAVEENV
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;

2> default_environment(common/env_common.c)

uchar default_environment[] = {
#ifdef    CONFIG_BOOTARGS
    "bootargs="    CONFIG_BOOTARGS            "\0"
#endif
somestrings

 #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"
};

2、env_init(common/env_flash.c)

    if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { //如果校驗成功 
gd->env_addr = (ulong)&(env_ptr->data); gd->env_valid = 1; //1代表flash中存在環境變量 return(0); } gd->env_addr = (ulong)&default_environment[0]; //不成功,則使用系統默認的環境變量 //default_environment僅僅是環境變量的data區,不包含頭部crc 、flags gd->env_valid = 0; //0代表使用默認的環境變量 return (0);

3、env_relocate(common/env_common.c)

void env_relocate (void)
{
     /*
     * We must allocate a buffer for the environment
     */
    env_ptr = (env_t *)malloc (CFG_ENV_SIZE); //為環境變量區分配空間
    DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
    if (gd->env_valid == 0) {  //env_init中決定了env_valid的值,倘若flash中存在的環境變量校驗錯誤
#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
//#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE)  ENV_SIZE在include/environment.h中定義
        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)); //將環境默認變量拷貝到RAM中的指定區域
         env_crc_update (); //更新crc
        gd->env_valid = 1; //env_valid確認有效了
    }
    else { //倘若flash中存在的環境變量校驗成功
        env_relocate_spec ();
        /*該函數實現真正的重定位功能,先從NAND flash中讀取環境變量,如果讀取成*/
    }
    gd->env_addr = (ulong)&(env_ptr->data); //將環境變量的首地址(不含crc頭部)賦給全局變量gd->env_addr
}

    修改env_common.c中第47行“#undef DEBUG_ENV”變為“#define DEBUG_ENV”,並在函數一開始處加上語句

  DEBUGF ("%s[%d] env_valid = 0x%8x\n", __FUNCTION__,__LINE__,
        gd->env_valid);  

重新編譯后下載,調試結果如下。

   可見執行完env_init()函數中env_valid被置為0,這是由於一開始NorFlash上並沒有存儲環境變量,當然會校驗錯誤。並且,可以看到環境變量緩沖區被開在堆區。

4、 env_relocate_spec(common/env_flash.c)

void env_relocate_spec (void) //此函數被env_relocate()函數調用
{
    memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE); //在env_relocate已經將env_ptr指向環境變量存儲區
}

 四、環境變量的源位置和加載位置

  回過頭來,再看一下環境變量的源在哪兒,加載位置又在哪兒?看一下重定位的關鍵函數調用:

memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE); 

  flash_addr是源位置,在0x70000

static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#define PHYS_FLASH_1        0x00000000 /* Flash Bank #1 */
#define CFG_FLASH_BASE        PHYS_FLASH_1
#define CFG_ENV_ADDR        (CFG_FLASH_BASE + 0x070000) /* addr of environment */
#define CFG_ENV_SIZE        0x10000    /* Total Size of Environment Sector */

  env_ptr是加載位置,位於堆區

 env_ptr = (env_t *)malloc (CFG_ENV_SIZE);  

 

總結

    env_init()函數讀取flash中環境變量區然后校驗,“gd->env_valid ”記錄了校驗成功與否。進入env_relocate函數,先將環境變量區設定在堆區,然后根據校驗標志位決定是從flash中拷貝,還是從默認環境變量區拷貝(這種情況還需要更新校驗crc)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM