uboot源码——环境变量
生活随笔
收集整理的這篇文章主要介紹了
uboot源码——环境变量
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
以下內容源于朱有鵬嵌入式課程的學習,如有侵權,請告知刪除。
參考資料: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;
- 由于SD卡的環境變量分區中也有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_MULTIif (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_MULTIif (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_MULTIeth_set_enetaddr(0, argv[2]); #endifreturn 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_AMIGAONEG3SEif (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; }總結
以上是生活随笔為你收集整理的uboot源码——环境变量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构课设:仓库管理系统(C++)
- 下一篇: Java JDK 8的安装与配置