UBOOT——環境變量的實現原理

uboot 環境變量實現原理:數組

首先咱們先要搞清楚uboot中環境變量的做用,uboot中環境變量的做用就是在不改變源碼、不用從新編譯的狀況下,能夠使咱們經過安全

設置環境變量的值來改變uboot的一些設置,如bootdelay時間、機器碼的值等等。ide

下面咱們來具體看一下uboot中環境變量如何實現函數

首先看一下環境變量的初始化函數:ui

  env_init定義在commen/env_movi.c中 函數中實際執行的就是把default_environment的地址賦值給全局變量gd中的env_addr 和env_valid兩個值;this

  

int env_init(void) { #if defined(ENV_IS_EMBEDDED)
   #else /* ENV_IS_EMBEDDED */ gd->env_addr  = (ulong)&default_environment[0]; gd->env_valid = 1; #endif /* ENV_IS_EMBEDDED */

    return (0); }

來看一下default_environment數組spa

 

 

在來看一下env_relocate  這個函數code

重點是一下兩句代碼blog

      env_ptr = (env_t *)malloc (CFG_ENV_SIZE); 這句代碼做用是給uboot環境變量開闢一塊16k大小的內存ip

      env_relocate_spec ();  這句代碼的做用是把sd卡中的uboot環境變量整個分區複製到開闢的這個內存地址處;      

void env_relocate (void) {  #ifdef ENV_IS_EMBEDDED #else
    /* * 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); #endif

    if (gd->env_valid == 0) {  } else { env_relocate_spec (); } gd->env_addr = (ulong)&(env_ptr->data);  }

經過movi_read_env函數把sd卡中的環境變量複製到內存中

主藥用到的是   movi_read_env(virt_to_phys((ulong)env_ptr)); 函數   

        crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc 

        use_default()

三個函數: movi_read_env把sd卡中的uboot的環境變量分區複製到env_ptr中;

     crc32 計算內存中環境變量的crc的值,若是不相等則執行

     use_default函數 

 

void env_relocate_spec (void) { #if !defined(ENV_IS_EMBEDDED)
    uint *magic = (uint*)(PHYS_SDRAM_1); if ((0x24564236 != magic[0]) || (0x20764316 != magic[1])) movi_read_env(virt_to_phys((ulong)env_ptr)); if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) return use_default(); #endif /* ! ENV_IS_EMBEDDED */ }

 

下面看一下use_default函數的代碼:

1:輸出*** Warning - bad CRC or moviNAND, using default environment:

2:清0環境變量內存,把default_environment中的值複製到環境變量內存

3:計算crc,寫入內存中的crc位

4:設置gd中的env_valid爲1;

static void use_default() { puts ("*** Warning - bad CRC or moviNAND, 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; }

這樣環境變量初始化算是完成了;

咱們在回顧一下環境變量初始化都作了哪些工做:

1:在uboot尚未初始化flash設備(nand movinand 等flash)的時候,先進行環境變量初級初始化,即把gd全局變量中的 env_valid = 1; env_addr 等於全局變量default_enviroment數組的首地址

2:初始化完flash設置之後就要進行環境變量的重定位工做了,即把環境變量從flash中copy到內存中,用一個全局變量env_ptr指向這段內存;複製工做時經過movi_read_env這個函數實現的,實際就是把sd卡中

環境變量分區所有複製到env_ptr指向的這段內存中,而後在對這段內存中的環境變量進行crc校驗,若是失敗的話,則把default_enviroment中的環境變量複製到這裏;

(這裏對代碼分析env_relocate函數中用malloc設置了一段內存來存放環境變量,一直沒有用free來釋放這段內存,這裏是否存在安全隱患?)

 

------------------------------------------------------------------------------------------------------------

接下來咱們在看一下uboot中關於環境變量的一些命令

第一個 printenv 實現函數爲do_printfenv

代碼以下:

 1 int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  2 {  3     int i, j, k, nxt;  4     int rcode = 0;  5 
 6     if (argc == 1) {        /* Print all env variables */
 7         for (i=0; env_get_char(i) != '\0'; i=nxt+1) {  8             for (nxt=i; env_get_char(nxt) != '\0'; ++nxt)  9  ; 10             for (k=i; k<nxt; ++k) 11  putc(env_get_char(k)); 12             putc  ('\n'); 13 
14             if (ctrlc()) { 15                 puts ("\n ** Abort\n"); 16                 return 1; 17  } 18  } 19 
20         printf("\nEnvironment size: %d/%ld bytes\n", 21             i, (ulong)ENV_SIZE); 22 
23         return 0; 24  } 25 
26     for (i=1; i<argc; ++i) {    /* print single env variables */
27         char *name = argv[i]; 28 
29         k = -1; 30 
31         for (j=0; env_get_char(j) != '\0'; j=nxt+1) { 32 
33             for (nxt=j; env_get_char(nxt) != '\0'; ++nxt) 34  ; 35             k = envmatch((uchar *)name, j); 36             if (k < 0) { 37                 continue; 38  } 39  puts (name); 40             putc ('='); 41             while (k < nxt) 42                 putc(env_get_char(k++)); 43             putc ('\n'); 44             break; 45  } 46         if (k < 0) { 47             printf ("## Error: \"%s\" not defined\n", name); 48             rcode ++; 49  } 50  } 51     return rcode; 52 }

 

uchar env_get_char_memory (int index) { if (gd->env_valid) { return ( *((uchar *)(gd->env_addr + index)) ); } else { return ( default_environment[index] ); } }

 

第二個命令:setenv命令對用的函數是do_setenv 命令,實際上調用的是_do_setenv函數

下面咱們來分析一下這個函數

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) { 

        /* 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[i]) 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;  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[i]) + 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[i]; *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[i] = 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 defined(CONFIG_CMD_NET)
    if (strcmp(argv[1],"bootfile") == 0) { copy_filename (BootFile, argv[2], sizeof(BootFile)); return 0; } #endif #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; }
相關文章
相關標籤/搜索