(环境如下: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()函数

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

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

 int env_init(void)
{
#if defined(ENV_IS_EMBEDDED) //搜寻代码 发现ENV_IS_EMBEDDED没有定义,所以执行#else部分
ulong total;
int crc1_ok = , crc2_ok = ;
env_t *tmp_env1, *tmp_env2; total = CFG_ENV_SIZE; tmp_env1 = env_ptr;
tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE); crc1_ok = (crc32(, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
crc2_ok = (crc32(, tmp_env2->data, ENV_SIZE) == tmp_env2->crc); if (!crc1_ok && !crc2_ok)
gd->env_valid = ;
else if(crc1_ok && !crc2_ok)
gd->env_valid = ;
else if(!crc1_ok && crc2_ok)
gd->env_valid = ;
else {
/* both ok - check serial */
if(tmp_env1->flags == && tmp_env2->flags == )
gd->env_valid = ;
else if(tmp_env2->flags == && tmp_env1->flags == )
gd->env_valid = ;
else if(tmp_env1->flags > tmp_env2->flags)
gd->env_valid = ;
else if(tmp_env2->flags > tmp_env1->flags)
gd->env_valid = ;
else /* flags are equal - almost impossible */
gd->env_valid = ;
} if (gd->env_valid == )
env_ptr = tmp_env1;
else if (gd->env_valid == )
env_ptr = tmp_env2;
#else /* ENV_IS_EMBEDDED */ //执行此处
gd->env_addr = (ulong)&default_environment[]; //获取默认的环境变量数组的地址
gd->env_valid = ; //环境变量准备好标准位,=1表示准备OK
#endif /* ENV_IS_EMBEDDED */ return ();
}

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

  

 void env_relocate (void)
{
DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
gd->reloc_off); #ifdef CONFIG_AMIGAONEG3SE //未定于,不执行
enable_nvram();
#endif #ifdef ENV_IS_EMBEDDED //未定义 不执行
/*
* The environment buffer is embedded with the text segment,
* just relocate the environment pointer
*/
env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#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 /*
* After relocation to RAM, we can always use the "memory" functions
*/
env_get_char = env_get_char_memory; //env_get_char指向env_get_char_memory函数(这个函数执行返回对应便宜量的实际地址) if (gd->env_valid == ) { //gd->env_valid = 1,执行else
#if defined(CONFIG_GTH) || defined(CFG_ENV_IS_NOWHERE) /* Environment not changable */
puts ("Using default environment\n\n");
#else
puts ("*** Warning - bad CRC, using default environment\n\n");
SHOW_BOOT_PROGRESS (-);
#endif if (sizeof(default_environment) > ENV_SIZE)
{
puts ("*** Error - default environment is too large\n\n");
return;
} memset (env_ptr, , sizeof(env_t));
memcpy (env_ptr->data,
default_environment,
sizeof(default_environment));
#ifdef CFG_REDUNDAND_ENVIRONMENT
env_ptr->flags = 0xFF;
#endif
env_crc_update ();
gd->env_valid = ;
}
else {
env_relocate_spec (); //执行此处
}
gd->env_addr = (ulong)&(env_ptr->data); #ifdef CONFIG_AMIGAONEG3SE
disable_nvram();
#endif
}

4、跳去env_relocate_spec();

 void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
ulong total = CFG_ENV_SIZE;
int ret; ret = nand_read(&nand_info[], CFG_ENV_OFFSET, &total, (u_char*)env_ptr); //将nandlflash里面的环境变量,拷贝到env_ptr指向的内存
if (ret || total != CFG_ENV_SIZE)
return use_default(); if (crc32(, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}

如果没有执行过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"结尾)),并且与传入的名字对比,如果相同则返回=后面的数据的地址,此数据即可拿来各种使用了

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

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

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

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

U-BOOT分析之:环境变量的更多相关文章

  1. linux下jdk环境变量配置深度分析----解决环境变量不生效的问题

    1.linux下jdk环境变量配置 是否需要配置环境变量,主要看java -version 显示的版本是否为你期望的版本 1.1 不需要配置环境变量的情况 使用java -version查看,版本显示 ...

  2. u-boot-1.1.6环境变量

    学习目标: 1.分析u-boot-1.1.6环境变量,了解环境变量初始化.设置以及过程 2.为后面能够掌握u-boot-1.1.6如何启动内核过程打下基础 1.环境变量的概念 在分析uboot环境变量 ...

  3. uboot环境变量实现分析

    u-boot的环境变量用来存储一些经常使用的参数变量,uboot希望将环境变量存储在静态存储器中(如nand nor eeprom mmc). 其中有一些也是大家经常使用,有一些是使用人员自己定义的, ...

  4. mac攻略(七) -- 环境变量PATH分析

      一.首先需要了解 1>mac 一般使用bash作为默认shell 2>Mac系统的环境变量,加载顺序为: 1.系统级别的 /etc/profile /etc/bashrc /etc/p ...

  5. Spring Boot 环境变量读取 和 属性对象的绑定

    网上看到的一些方法,结合我看到的 和我们现在使用的.整理成此文: 第一种方法 参见catoop的博客之 Spring Boot 环境变量读取 和 属性对象的绑定(尊重原创) 第二种方法 class不用 ...

  6. 十五、Spring Boot 环境变量读取 和 属性对象的绑定

    凡是被spring管理的类,实现接口 EnvironmentAware 重写方法 setEnvironment 可以在工程启动时,获取到系统环境变量和application配置文件中的变量. 如: @ ...

  7. MPC8313ERDB在Linux从NAND FLASH读取UBoot环境变量的代码分析

    MPC8313ERDB在Linux从NAND FLASH读取UBoot环境变量的代码分析 Yao.GUET@2014-05-19 一.故事起因 由于文件系统的增大,已经大大的超出了8MB的NOR FL ...

  8. Tomcat启动分析(我们为什么要配置CATALINA_HOME环境变量)

    原文:http://www.cnblogs.com/heshan664754022/archive/2013/03/27/2984357.html Tomcat启动分析(我们为什么要配置CATALIN ...

  9. Linux环境变量设置中配置文件分析(/etc/profile,~/.bashrc等)(转)

    说明:在研究中发现,对于不同版本的Linux系统有着不同的文件,但是总的入口是不变的/etc/profile,下面只是展示加载顺序的研究过程,所以会有些系统没有这个文件等问题. 一.配置文件与作用域: ...

随机推荐

  1. coreseek+sphinx+mysql+thinkphp整合

    1.安装coreseek 1.1首先升级或安装系统依赖库 yum install make gcc g++ automake libtool mysql-client libmysqlclient15 ...

  2. Dom4J解析技术

    前面的话  本文主要讲解有关Dom4j技术和xpath配合下的优化!   目录:    为什么需要Dom4J    DOM4J怎么用    xpath怎么配合DOM4J 一  为什么需要Dom4J 一 ...

  3. Ubuntu Server 14.04 集成

    方便工作出差显示项目整合了下平时常用软件: OS: Ubuntu Server 14.04 VM:VMware Workstation 12.1.0 (不同版本好像会不兼容) 已经安装软件: 1. s ...

  4. C和指针 第十六章 标准函数库 信号

    信号名<signal.h> 程序中大多数错误都是程序本身导致的,但是,有些程序遇到的事件却不是程序本身所引发的.比如用户终止程序,程序无法预知此类事件发生的情况,信号就是为了对此类事件做出 ...

  5. 常用ubuntu命令

    解压缩.7z sudo apt-get install p7zip-full 7z x PACKAGE.7z 查看图片 eog A.png 关闭打开触摸板(触点) sudo rmmod psmouse ...

  6. JavaScript的==和===运算符

    JavaScript提供两个相等运算符:==和 ===.      简单说,它们的区别是相等运算符( ==)比较两个值是否相等,严格相等运算符( ===)比较它们是否为“同一个值”.如果两个值不是同一 ...

  7. maven向本地仓库导入jar包(处理官网没有的jar包)

    对于官网没有的jar包,maven向本地仓库导入jar包用如下命令 mvn install:install-file -DgroupId=包名 -DartifactId=项目名 -Dversion=版 ...

  8. Idea+TestNg配置test-output输出

    说明:testNG的工程我是使用eclipse创建的,直接导入到idea中,运行test时不会生产test-output,只能在idea的控制台中查看运行结果,然后到处报告,经过不懈的百度终于找到怎么 ...

  9. Qt - 错误总结 - QObject::connect: Cannot queue arguments of type 'PVCI_CAN_OBJ' (Make sure 'PVCI_CAN_OBJ' is registered using qRegisterMetaType().)

    背景:一个线程通过signal-slot发送PVCI_CAN_OBJ类型的值到主线程中, 错误提示: QObject::connect: Cannot queue arguments of type ...

  10. DLL 生成与使用的全过程(2010-01-18 14:50:17)

    转载自 水滴的博客http://blog.sina.com.cn/spiritofwater   个人学习用 转载▼   分类: 技术 由dll导出的lib文件: 包含了每一个dll导出函数的符号名和 ...