5(2)、uboot源码——uboot的环境变量

来源:互联网 发布:哪个打字软件最好用 编辑:程序博客网 时间:2024/05/23 22:02

以下内容源于朱有鹏《物联网大讲堂》课程的学习整理,以及博客http://www.cnblogs.com/biaohc/p/6398515.html的学习整理,如有侵权,请告知删除。


一、uboot的环境变量基础

1、环境变量的作用

  • 在不改变源码、不用重新编译的情况下,可以通过设置环境变量的值来改变uboot的一些设置,如bootdelay时间、机器码的值等等。

2、环境变量的优先级

(1)uboot代码当中有一个值,SD卡中环境变量分区也有一个值。

  • uboot程序实际运行时规则是:如果环境变量为空则使用uboot代码中的值;如果环境变量不为空则优先使用环境变量对应的值。

(2)譬如machid(机器码)。

  • uboot中在x210_sd.h中定义了一个机器码2456,写死在程序中的不能更改(如果要修改,则要重新编译烧录);
  • SD卡的环境变量分区中也有machid;
  • 有了machid环境变量后,系统启动时会优先使用环境变量的machid,这就是优先级问题。

3、环境变量在uboot中工作方式

(1)默认环境变量

  • 在uboot/common/env_common.c的default_environment中;
  • 本质是一个字符数组,大小为CFG_ENV_SIZE(16kb);
  • 很多个环境变量连续分布组成的,每个环境变量最末端以'\0'结束。

(2)SD卡中环境变量分区

  • 在uboot的raw分区中,SD卡中有专门的分区用来存储;
  • 存储时,把DDR中的环境变量整体写入SD卡的环境变量分区。
  • 因此saveenv时,是所有的环境变量都被保存了一遍,而不是只保存更改了的。

(3)DDR中环境变量

  • 在default_environment中,实质是字符数组。
  • 在uboot中其实是一个全局变量,链接时在数据段,重定位时default_environment就被重定位到DDR中一个内存地址处了。
  • 这个地址处的这个全局字符数组就是uboot运行时的DDR中的环境变量。

(4)总结

  • SD卡的环境变量分区一开始是空白的,uboot第一次运行时加载的是uboot代码中的那份环境变量,叫默认环境变量。
  • 在saveenv时,DDR中的环境变量会被更新到SD卡的环境变量分区中。下次开机在环境变量relocate时,会将SD卡中的环境变量加载到DDR中去
  • default_environment中的内容虽然被uboot源代码初始化为一定的值,但是在env_relocate时,代码会把环境变量从SD卡中拷贝到内存中,然后去判断SD卡中的env分区的crc是否通过,如果不通过则使用default_environment字符数组,通过了使用SD卡内的环境变量。

4、环境变量的初始化

(1)没有初始化flash设备前,进行环境变量初级初始化

  • 函数env_init定义在commen/env_movi.c中;
  • 把gd全局变量中的 env_valid = 1; env_addr = 全局变量default_enviroment数组的首地址。


(2)初始化flash设备之后


  • 初始化flash后,进行环境变量的重定位工作,即把环境变量从flash中copy到内存中,用一个全局变量env_ptr指向这段内存;
  • 复制是通过movi_read_env这个函数实现的,实际就是把sd卡中环境变量分区全部复制到env_ptr指向的这段内存中;
  • 然后在对这段内存中的环境变量进行crc校验,如果失败的话,则把default_enviroment中的环境变量复制到这里。
  • env_ptr = (env_t *)malloc (CFG_ENV_SIZE); 这句代码作用是给uboot环境变量开辟一块16k大小的内存
  • env_relocate_spec ();这句代码的作用是把sd卡中的uboot环境变量整个分区复制到开辟的这个内存地址处;
  • 见博客http://blog.csdn.net/oqqhutu12345678/article/details/69365347的(四2)。

代码跟踪:env_relocate_spec ()函数:




  • 输出*** Warning - bad CRC or moviNAND, using default environment:;
  • 清0环境变量内存,把default_environment中的值复制到环境变量内存;
  • 计算crc,写入内存中的crc位;
  • 设置gd中的env_valid为1;


二、环境变量相关命令源码解析(举例)

1、printenv,实现函数为do_printfenv


  • do_printenv函数首先区分是否argc=1,若argc=1则循环打印所有的环境变量出来,否则后面的参数就是要打印的环境变量,给哪个就打印哪个。
  • argc=1时,用双重for循环来依次处理所有的环境变量的打印。第一重for循环就是处理各个环境变量,所以有多少个环境变量则第一重就执行循环多少圈。
  • 要明白整个环境变量在内存中如何存储的问题。

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

原创粉丝点击