回顾U-boot(一)

如果我们要想让一个操作系统在我们的板子上运转起来,我们就必须首先对我们的板子进行一些基本配置和初始化,然后才可以将操作系统引导进来运行。而我们的u-boot就是来干这个事情的

现在我们的windows的引导程序一般是BIOS+Bootloader,我们的u-boot是一个通用的bootloader,即boot+loader,boot阶段启动系统,初始化硬件设备,建立内存空间映射图,将系统的软硬件带到一个合适的状态。loader阶段将操作系统内核文件加载至内存,之后跳转到内核所在地址运行。

bootloader的实现非常依赖具体的硬件,在嵌入式系统中的硬件配置千差万别,因此我们的bootloader一般都需要移植,它有两个模式:启动加载模式和命令模式。

1.启动加载模式(用户使用产品):上电后,bootloader从板子的某个固态存储器上将操作系统内核加载到内存中运行,整个过程没有用户介入
2.命令模式(下载更新模式):由开发人员在开发阶段使用,在此模式中,开发人员可以使用各种命令,通过串口或者网络将u-boot.bin下载到内存位置运行,或者烧写到Nand Flash固态存储设备中。

对于u-boot的启动方式有三种:网络启动方式、磁盘启动方式和Flash启动方式。我们最常用的就是第三种,Flash启动模式。NOR Flash和NAND Flash两种,NOR Flash采用线性存储模式,支持随机访问,代码放上去可以直接执行,Nand Flash 的特点是采用非线性存储模式,程序无法在其中运行,它只能作为程序或数据的存储载体,存储在其中的程序只能先拷贝到RAM 中才能运行。

U-boot之所以这么通用,原因是他具有很多特点:开放源代码、支持多种嵌入式操作系统内核、支持多种处理器系列、较高的稳定性、高度灵活的功能设置、丰富的设备驱动源码以及较为丰富的开发调试文档与强大的网络技术支持。另外u-boot对操作系统和产品研发提供了灵活丰富的支持,主要表现在:可以引导压缩或非压缩系统内核,可以灵活设置/传递多个关键参数给操作系统,适合系统在不同开发阶段的调试要求与产品发布,支持多种文件系统,支持多种目标板环境参数存储介质,采用CRC32校验,可校验内核及镜像文件是否完好,提供多种控制台接口,使用户可以在不需要ICE的情况下通过串口/以太网/USB等接口下载数据并烧录到存储设备中去(这个功能在实际的产品中是很实用的,尤其是在软件现场升级的时候),以及提供丰富的设备驱动等

什么是《编译地址》?什么是《运行地址》?
(一)编译地址: 32位的处理器,它的每一条指令是4个字节,以4个字节存储顺序,进行顺序执行,CPU是顺序执行的,只要没发生什么跳转,它会顺序进行执行行, 编译器会对每一条指令分配一个编译地址,这是编译器分配的,在编译过程中分配的地址,我们称之为编译地址。
(二)运行地址:是指程序指令真正运行的地址,是由用户指定的,用户将运行地址烧录到哪里,哪里就是运行的地址。
比如有一个指令的编译地址是0x5,实际运行的地址是0x200,如果用户将指令烧到0x200上,那么这条指令的运行地址就是0x200,
当编译地址和运行地址不同的时候会出现什么结果?结果是不能跳转,编译后会产生跳转地址,如果实际地址和编译后产生的地址不相等,那么就不能跳转。
C语言编译地址:都希望把编译地址和实际运行地址放在一起的,但是汇编代码因为不需要做c语言到汇编的转换,可以任意的去写地址,所以直接写的就是他的运行地址这就是为什么任何bootloader刚开始会有一段汇编代码,因为起始代码编译地址和实际地址不相等,这段代码和汇编无关,跳转用的运行地址。
编译地址和运行地址如何来算呢?
1. 假如有两个编译地址a=0x10,b=0x7,b的运行地址是0x300,那么a的运行地址就是b的运行地址加上两者编译地址的差值,a-b=0x10-0x7=0x3,a的运行地址就是0x300+0x3=0x303。

2.   假设uboot上两条指令的编译地址为a=0x33000007和b=0x33000001,这两条指令都落在bank6上,现在要计算出他们对应的运行地址,要找出运行地址的始地址,这个是由用户烧录进去的,假设运行地址的首地址是0x0,则a的运行地址为0x7,b为0x1,就是这样算出来的。

>

                 为什么要分配编译地址?这样做有什么好处,有什么作用?
    比如在函数a中定义了函数b,当执行到函数b时要进行指令跳转,要跳转到b函数所对应的起始地址上去,编译时,编译器给每条指令都分配了编译地址,如果编译器已经给分配了地址就可以直接进行跳转,查找b函数跳转指令所对应的表,进行直接跳转,因为有个编译地址和指令对应的一个表,如果没有分配,编译器就查找不到这个跳转地址,要进行计算,非常麻烦。

                                                                   什么是《相对地址》?
    以NOR Flash为例,NOR Falsh是映射到bank0上面,SDRAM是映射到bank6上面,uboot和内核最终是在SDRAM上面运行,最开始我们是从Nor Flash的零地址开始往后烧录,uboot中至少有一段代码编译地址和运行地址是不一样的,编译uboot或内核时,都会将编译地址放入到SDRAM中,他们最终都会在SDRAM中执行,刚开始uboot在Nor Flash中运行,运行地址是一个低端地址,是bank0中的一个地址,但编译地址是bank6中的地址,这样就会导致绝对跳转指令执行的失败,所以就引出了相对地址的概念。
                                                                  那么什么是相对地址呢?
 至少在bank0中uboot这段代码要知道不能用b+编译地址这样的方法去跳转指令,因为这段代码的编译地址和运行地址不一样,那如何去做呢?
要去计算这个指令运行的真实地址,计算出来后再做跳转,应该是b+运行地址,不能出现b+编译地址,而是b+运行地址,而运行地址是算出来的。

_TEXT_BASE:
.word TEXT_BASE //0x33F80000,在board/config.mk中
这段话表示,用户告诉编译器编译地址的起始地址

bootloader通常有分两步执行,第一阶段用汇编编写,因为bootloade要求短小精悍,而上面的编译地址和运行地址也说明了为什么需要汇编的原因,第二阶段用C语言编写,以实现复杂的功能。

第一阶段:

这里写图片描述

本阶段
1. 初始化部分硬件设备:关看门狗,设置系统时钟,初始化sdram,关闭CPU内部指令/数据 cache。
2. 为加载bootloader的第二阶段准备RAM空间
3. 拷贝bootloader的第二阶段的代码到RAM空间中
4. 设置堆栈
5. 跳转到第二阶段C入口点

第二阶段:

这里写图片描述

本阶段:
1. 初始化本阶段要使用到的硬件设备
2. 检测系统内存映射
3. 将kernel映像和根文件系统映像从flash上读到RAM空间中
4. 为内核设置启动参数
5. 调用内核

对于第一阶段的硬件初始化,下面谈一谈为什么要这样初始化:

  1. 关看门狗:前面已经提到过,看门狗是为了防止系统死机而不能重启的相当于一个定时器的作用,我们要不断去喂狗,以防止cpu自动复位,因此,如果我们在规定时间内未喂狗,那么cpu将复位,我们的启动代码永远也运行不完,因此关闭看门狗
  2. 关闭所有中断:因为uboot只是完成硬件初始化,环境参数设置,代码搬运等工作,用不到中断。屏蔽中断是为了避免因为意外中断使得boot失败,毕竟很多外设还没有初始化,对应中断代码也都没有准备好。
  3. 设置时钟频率:起始可以不设,系统能不能跑起来和频率没有任何关系,频率的设置是要让外围的设备能承受所设置的频率,如果频率过高则会导致cpu操作外围设备失败,说白了:设置频率,就为了CPU能去操作外围设备。
  4. 关闭MMU/数据cache:MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权。MMU的作用是把虚拟地址转换为物理地址,但是我们的目的是设置控制寄存器,而控制寄存器本来就是物理地址,因此不用开起MMU。数据cache的关闭是为了防止系统从cache里面去取数据,而RAM中的数据还没过来,导致数据预取异常。

说到catch就必须提到一个关键字Volatile,以后在设置寄存器时会经常遇到,他的本质:是告诉编译器不要对我的代码进行优化,作用是让编写者感觉不倒变量的变化情况(也就是说,让它执行速度加快吧)优化的过程:是将常用的代码取出来放到catch中,它没有从实际的物理地址去取,它直接从cpu的缓存中去取,但常用的代码就是为了感觉一些常用变量的变化。优化原因:如果正在取数据的时候发生跳变,那么就感觉不到变量的变化了,所以在这种情况下要用Volatile关键字告诉编译器不要做优化,每次从实际的物理地址中去取指令,这就是为什么关闭catch关闭MMU。但在C语言中是不会关闭catch和MMU的,会打开,如果编写者要感觉外界变化,或变化太快,从catch中取数据会有误差,就加一个关键字Volatile。

第二阶段的C代码在下篇博客分析。

参考链接:http://blog.csdn.net/hare_lee/article/details/6916325

猜你喜欢

转载自blog.csdn.net/Peter_tang6/article/details/77340879
今日推荐