U-BOOT分析之:环境变量

(环境如下:U-BOOT  S3C2440  LINUX) 记录自己的学习过程,如果分析有问题,请帮忙指正。

 

最近在研究U-BOOT的代码,其中的环境变量个人觉得用处非常大,所以重点学习和分析一下。

U-BOOT的第一个执行的文件为start.S,可以从链接文件分析出来(u-boot.lds)

进入U-BOOT执行过程如下:

1、设置CPU进入SVC32模式(set the cpu to SVC32 mode)

2、关看门狗(turn off the watchdog )

3、关中断(mask all IRQs by setting all bits in the INTMR - default)

4、比较_start和_TEXT_BASE(链接脚本里面定义代码的运行地址TEXT_BASE = 0x33F80000),判断如果不是仿真启动,则执行cpu_init_crit

     注:如果代码是烧录到板子则_start地址没有调整前是0,如果是仿真器则直接下载到RAM,这会下载到链接地址上,即TEXT_BASE 

5、cpu_init_crit执行如下(flush v4 I/D caches,disable MMU stuff and caches,setup RAM timing),即关mmu,设置存储管理器(lowlevel_init)

     注:设置完存储管理器后SDRAM NANDFLASH 等外围设备才能使用

6、规划内存空间,并且设置栈(自己规划空间的分配如下:CFG_MALLOC_LEN,CFG_GBL_DATA_SIZE,CONFIG_STACKSIZE_IRQ,CONFIG_STACKSIZE_FIQ,12)

7、设置时钟  clock_init()

8、拷贝代码到SDRAM   CopyCode2Ram()

     注,r0 r1 r2分别为CopyCode2Ram的三个参数,即起始地址,目的地址,拷贝的长度(同样,如果是仿真器则跳过这段代码)

9、清除bss段(把未初始化的全部变量和则静态变量初始化为0)

10、设置PreLoadedONRAM标志位,方便后面判断是否是debug模式

11、获取start_armboot的链接地址,并且跳转到start_armboot,此时跳转到SDRAM中执行

12、start_armboot函数首先给两个结构体分配空间,并且设置结构体成员值为0

  注:gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));  gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

13、接下来执行各种初始化,即init_sequence指针数组里面的各个初始化函数,其中env_init即环境变量初始化

环境变量分析:

1、进入env_init()函数

 1 init_fnc_t *init_sequence[] = {
 2     cpu_init,        /* basic cpu dependent setup */
 3     board_init,        /* basic board dependent setup */
 4     interrupt_init,        /* set up exceptions */
 5     env_init,        /* initialize environment */   //我们关注的函数
 6     init_baudrate,        /* initialze baudrate settings */
 7     serial_init,        /* serial communications setup */
 8     console_init_f,        /* stage 1 init of console */
 9     display_banner,        /* say that we are here */
10 #if defined(CONFIG_DISPLAY_CPUINFO)
11     print_cpuinfo,        /* display cpu info (and speed) */
12 #endif
13 #if defined(CONFIG_DISPLAY_BOARDINFO)
14     checkboard,        /* display board info */
15 #endif
16     dram_init,        /* configure available RAM banks */
17     display_dram_config,
18     NULL,
19 };
1     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {   //循环执行上面结构体的内容,其中就有调用到env_init()
2         if ((*init_fnc_ptr)() != 0) {
3             hang ();
4         }
5     }

2、那么程序进入Env_nand.c执行

 1 int env_init(void)
 2 {
 3 #if defined(ENV_IS_EMBEDDED)   //搜寻代码 发现ENV_IS_EMBEDDED没有定义,所以执行#else部分
 4     ulong total;
 5     int crc1_ok = 0, crc2_ok = 0;
 6     env_t *tmp_env1, *tmp_env2;
 7 
 8     total = CFG_ENV_SIZE;
 9 
10     tmp_env1 = env_ptr;
11     tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);
12 
13     crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
14     crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
15 
16     if (!crc1_ok && !crc2_ok)
17         gd->env_valid = 0;
18     else if(crc1_ok && !crc2_ok)
19         gd->env_valid = 1;
20     else if(!crc1_ok && crc2_ok)
21         gd->env_valid = 2;
22     else {
23         /* both ok - check serial */
24         if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
25             gd->env_valid = 2;
26         else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
27             gd->env_valid = 1;
28         else if(tmp_env1->flags > tmp_env2->flags)
29             gd->env_valid = 1;
30         else if(tmp_env2->flags > tmp_env1->flags)
31             gd->env_valid = 2;
32         else /* flags are equal - almost impossible */
33             gd->env_valid = 1;
34     }
35 
36     if (gd->env_valid == 1)
37         env_ptr = tmp_env1;
38     else if (gd->env_valid == 2)
39         env_ptr = tmp_env2;
40 #else /* ENV_IS_EMBEDDED */    //执行此处
41     gd->env_addr  = (ulong)&default_environment[0];    //获取默认的环境变量数组的地址
42     gd->env_valid = 1;                                 //环境变量准备好标准位,=1表示准备OK
43 #endif /* ENV_IS_EMBEDDED */
44 
45     return (0);
46 }

3、继续往下分析发现和环境变量有关的函数,env_relocate ();

  

 1 void env_relocate (void)
 2 {
 3     DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
 4         gd->reloc_off);
 5 
 6 #ifdef CONFIG_AMIGAONEG3SE      //未定于,不执行
 7     enable_nvram();
 8 #endif
 9 
10 #ifdef ENV_IS_EMBEDDED     //未定义  不执行
11     /*
12      * The environment buffer is embedded with the text segment,
13      * just relocate the environment pointer
14      */
15     env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
16     DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
17 #else     //执行
18     /*
19      * We must allocate a buffer for the environment
20      */
21     env_ptr = (env_t *)malloc (CFG_ENV_SIZE);   //给环境变量分配地址
22     DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
23 #endif
24 
25     /*
26      * After relocation to RAM, we can always use the "memory" functions
27      */
28     env_get_char = env_get_char_memory;     //env_get_char指向env_get_char_memory函数(这个函数执行返回对应便宜量的实际地址)
29     
30     if (gd->env_valid == 0) {                   //gd->env_valid = 1,执行else
31 #if defined(CONFIG_GTH)    || defined(CFG_ENV_IS_NOWHERE)    /* Environment not changable */    
32         puts ("Using default environment\n\n");
33 #else
34         puts ("*** Warning - bad CRC, using default environment\n\n");       
35         SHOW_BOOT_PROGRESS (-1);
36 #endif
37 
38         if (sizeof(default_environment) > ENV_SIZE)
39         {
40             puts ("*** Error - default environment is too large\n\n");
41             return;
42         }
43 
44         memset (env_ptr, 0, sizeof(env_t));
45         memcpy (env_ptr->data,
46             default_environment,
47             sizeof(default_environment));
48 #ifdef CFG_REDUNDAND_ENVIRONMENT
49         env_ptr->flags = 0xFF;
50 #endif
51         env_crc_update ();
52         gd->env_valid = 1;
53     }
54     else {
55         env_relocate_spec ();    //执行此处
56     }
57     gd->env_addr = (ulong)&(env_ptr->data);   
58 
59 #ifdef CONFIG_AMIGAONEG3SE
60     disable_nvram();
61 #endif
62 }

4、跳去env_relocate_spec();

 1 void env_relocate_spec (void)
 2 {
 3 #if !defined(ENV_IS_EMBEDDED)
 4     ulong total = CFG_ENV_SIZE;
 5     int ret;
 6 
 7     ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);  //将nandlflash里面的环境变量,拷贝到env_ptr指向的内存
 8       if (ret || total != CFG_ENV_SIZE)    
 9         return use_default();
10 
11     if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
12         return use_default();
13 #endif /* ! ENV_IS_EMBEDDED */
14 }

     如果没有执行过save,即没有把环境变量保存到nandflash。则执行use_default();使用默认的default_environment[]环境变量

5、跳出env_relocate_spec(); 

      gd->env_addr = (ulong)&(env_ptr->data);    //跳转地址,指向当前使用的环境变量数据

6、至此环境变量的准备工作已经完成。后面就可以正常使用了。例如s = getenv ("bootdelay");

7、getenv("bootdelay")函数会提取环境变量的指令(每条指令之间以("\0"结尾)),并且与传入的名字对比,如果相同则返回=后面的数据的地址,此数据即可拿来各种使用了    

 1 char *getenv (char *name)
 2 {
 3     int i, nxt;
 4 
 5     WATCHDOG_RESET();
 6 
 7     for (i=0; env_get_char(i) != '\0'; i=nxt+1) {      //循环提取字符串,与传入名字比较是否匹配
 8         int val;
 9 
10         for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) { //提取一条完整的字符,使i=下一条字符的起始位置
11             if (nxt >= CFG_ENV_SIZE) {
12                 return (NULL);
13             }
14         }
15         if ((val=envmatch((uchar *)name, i)) < 0)   //比较函数传入参数name与提取到数据比较,如果匹配,则返回名字后面的数据的偏移量
16             continue;
17         return ((char *)env_get_addr(val));       //将偏移量转换为实际的地址,并且返回地址,此地址就可以拿来使用了
18     }
19 
20     return (NULL);
21 }

 

8、执行save指令,可以调用int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])函数:

1 int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
2 {
3     extern char * env_name_spec;
4 
5     printf ("Saving Environment to %s...\n", env_name_spec);   //打印
6 
7     return (saveenv() ? 1 : 0);  //跳转到下面的函数继续执行
8 }
 1 int saveenv(void)
 2 {
 3     ulong total;
 4     int ret = 0;
 5 
 6     puts ("Erasing Nand...");    //打印
 7     if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))    //擦除nandflash中的环境变量
 8         return 1;
 9 
10     puts ("Writing to Nand... ");      //打印
11     total = CFG_ENV_SIZE;
12     ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);    //将当前环境变量的值写入到nandflash
13     if (ret || total != CFG_ENV_SIZE)
14         return 1;
15 
16     puts ("done\n");
17     return ret;
18 }

 

从上面分析,我们可以设置各种环境变量的各种参数,在u-boot需要使用的地方调用他们,使用非常方便。并且需要永久保存的直接写入nandflash。

posted @ 2016-03-24 11:15  小健V5  阅读(969)  评论(0编辑  收藏  举报