UBOOT——环境变量的实现原理


uboot 环境变量实现原理:

首先我们先要搞清楚uboot中环境变量的作用,uboot中环境变量的作用就是在不改变源码、不用重新编译的情况下,可以使我们通过

设置环境变量的值来改变uboot的一些设置,如bootdelay时间、机器码的值等等。

下面我们来具体看一下uboot中环境变量如何实现

首先看一下环境变量的初始化函数:

  env_init定义在commen/env_movi.c中 函数中实际执行的就是把default_environment的地址赋值给全局变量gd中的env_addr 和env_valid两个值;

  

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数组

 

 

在来看一下env_relocate  这个函数

重点是一下两句代码

      env_ptr = (env_t *)malloc (CFG_ENV_SIZE); 这句代码作用是给uboot环境变量开辟一块16k大小的内存

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

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM