前面一段时间一直在移植U-Boot,Linux内核和构建根文件系统,其中有些地方还不是很明白,现在回过头来,理解一下U-boot的启动流程,以及u-Boot是如何加载引导内核启动的。这里的分析也都是以U-Boot-2009.08版本为基础的,可能会和以前的版本有所不同。在这里也不打算一句句分析U-Boot的源码,只是想把U-Boot一步一步怎么最终能够加载Linux内核的过程,分析一下。
首先,我们应该理解Bootloader是什么?它有什么作用?其实它就是系统上电后运行的和小段程序。
1 BootLoader的概念
在系统上电后,需要一段程序来进行初始化:关闭WATCHDOG,改变系统时钟,初始化存储控制器,将更多的代码复制到内存中。并将操作系统内核复制到内存中运行,这就段程序代码就叫做Bootloader。没有一个Bootloader完全支持所有CPU,所以我们要想使用Bootloaser一般情况下要自己进行修改,我们可以增强Bootloader的功能,让它具有网络功能,可以通过NFS远程下载Linux内核和根文件系统,可以烧写Linux内核和根文件系统到NandFlash中,而这些功能对于最终的用户来说是没有什么意义的,它们看到的只是Bootloader引导Linux内核启动这一个功能,而其余的功能只对开发人员很有用处。也就是说在开发期间这些功能是必不可少的。
(1)启动加载模式:这种模式也称为“自主”模式。也就是Bootloader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入,这种模式是在嵌入式产品发布里的通用模式。
(2)下载模式:在这种模式下,目标机上的Bootloader将通过串口连接或网络连接等通信手段从主机下载文件,例如:下载内核映像和根文件系统映像等。从主机下载的文件 通常首先被Bootloader保存到目标机的RAM中,然后再被Bootloader写到目标上的Flash类的固态存储设备中,Bootloader的这种模式是在在开发时使用的工作于这种模式的Bootloader通常都 会向它的终端用户提供一个简单的命令行接口。
在嵌入式Linux系统中从软件的角度通常可以分为4个层次:
(1)引导加载程序,包括固化在固件中的boot代码(可选)和Bootloader两大部分。
有些CPU在运行Bootloader之前运行一段固化的程序 ,比如x86结构的CPU就是先运行BIOS中的固件,然后才运行硬盘的第一个分区中的BootLoader。在大多数的嵌入式系统中并没有固件,Bootloader是上电后第一个执行的程序。
(2)Linux内核
嵌入式定制的内核以及启动参数,启动参数可以是Bootloader传递给内核的,也可以是内核默认的。
(3)文件系统
包括根文件系统和建立于Flash内存设备之上的文件系统。里面包括了Linux系统能够运行所必要的应用程序和库文件等。比如可以给用户提供操作Linux的控制shell程序。
(4)用户应用程序
特定于用户的应用程序,它们也存储在文件系统中,有时在用户应用程序和内核层之间可以还会包括一个嵌入式图形用户界面。
2. Bootloader启动的两个阶段
从固态存储设备上启动的Bootloader大多都是两阶段的启动过程,第一阶段使用汇编来实现。它完成一些依赖于CPU体系结构的初始化,并调用第二阶段的代码,第二阶段则通常使用C语言来实现,这样可以实现更复杂的功能,而且代码会有更好的可读性和可移植性。
(1) Bootloader第一阶段的功能
1)硬件设备初始化
2)为加载Bootloader的第二阶段准备RAM空间。
3)复制Bootloader的第二阶段代码到RAM空间中。
4)设置好栈
5)跳转到第二阶段代码的C入口点。
在第一阶段进行的硬件初始化一般包括:关闭WATCHDOG,关中断,设置 CPU的速度和时钟频率RAM初始化等。这些不都是必需的。
(2)Bootloader第二阶段的功能
1)初始化本阶段要使用的硬件设备
2)检测系统内存映射
3)将内核映像和根文件系映象从Flash望到RAM空间中
4)为内核设置启动参数
5)调用内核
将内核存放在适当的位置后,直接跳到它的入口点即可调用内核,调用内核之前,下列条件要满足
(1)CPU寄存器的设置
R0=0.
R1=机器类型ID;对于ARM结构的CPU,其机器类型ID在linux/arch/arm/tools/mach-types
R2=启动参数标记列表在RAM中起始基地址
(2)CPU工作模式
必须禁止中断(IRQs和FIQs)
CPU必须为SVC模式
(3)Cach和MMU的设置
MMU必须关闭
指令Cach可以打开也可以关闭
数据Cach必须关闭
阅读(275) | 评论(0) | 转发(0) |