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;}
阅读全文
0 0
- 5(2)、uboot源码——uboot的环境变量
- uboot 源码分析(2)uboot 环境变量实现简析
- UBOOT之源码分析——初始化环境变量
- uboot环境变量的讲解
- uboot - 环境变量的同步
- uboot的环境变量
- uboot常用的环境变量
- uboot的环境变量
- UBOOT的环境变量
- uboot的环境变量操作
- uboot环境变量的讲解
- 5、uboot源码——start_armboot函数
- 嵌入式linux开发uboot移植(六)——uboot环境变量
- uboot源码分析(2)
- uboot源码分析(2)
- uboot源码分析(2)
- uboot的常用环境变量1~2
- uboot环境变量的设置(未完待续)
- SpringMVC详解
- 自定义标题栏
- pat 1059. Prime Factors
- UESTC 1603 BanG Dreamer 小根堆、贪心+set<pair<int, int>>+low_bound
- WCF、WebAPI、WCFREST、WebService之间的区别
- 5(2)、uboot源码——uboot的环境变量
- 使用 HTMLTestRunner.py 修改为Python3版本
- Java Web jsp连接数据库并将数据库数据显示在浏览器页面
- CreateEvent的用法
- 实现mysql远程访问
- Java多线程总结
- uva10391
- Spark SQL性能优化
- 去掉微信小程序的滚动条