1TM1Tonyvopo123@126.comBootloader分析2TM2Tonyvopo123@126.com熟悉BootLoader的实现原理认识Bootloader的主要任务熟悉BootLoader的结构框架U-boot使用3TM3Tonyvopo123@126.com引言本章详细地介绍了基于嵌入式系统中的OS启动加载程序――BootLoader的概念、软件设计的主要任务以及结构框架等内容。一个嵌入式Linux系统从软件的角度看通常可以分为四个层次:1.引导加载程序。包括固化在固件(firmware)中的boot代码(可选),和BootLoader两大部分。2.Linux内核。特定于嵌入式板子的定制内核以及内核的启动参数。3.文件系统。包括根文件系统和建立于Flash内存设备之上文件系统。通常用ramdisk来作为rootfs。4.用户应用程序。特定于用户的应用程序。有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面。常用的嵌入式GUI有:MicroWindows和MiniGUI。4TM4Tonyvopo123@126.com引导加载程序是系统加电后运行的第一段软件代码。回忆一下PC的体系结构我们可以知道,PC机中的引导加载程序由BIOS(其本质就是一段固件程序)和位于硬盘MBR中的OSBootLoader(比如,LILO和GRUB等)一起组成。BIOS在完成硬件检测和资源分配后,将硬盘MBR中的BootLoader读到系统的RAM中,然后将控制权交给OSBootLoader。BootLoader的主要运行任务就是将内核映象从硬盘上读到RAM中,然后跳转到内核的入口点去运行,也即开始启动操作系统。而在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。比如在一个基于ARM7TDMIcore的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。5TM5Tonyvopo123@126.com系统的启动通常有两种方式,一种是可以直接从Flash启动,另一种是可以将压缩的内存映像文件从Flash(为节省Flash资源、提高速度)中复制、解压到RAM,再从RAM启动。当电源打开时,一般的系统会去执行ROM(应用较多的是Flash)里面的启动代码。这些代码是用汇编语言编写的,其主要作用在于初始化CPU和板上的必备硬件如内存、中断控制器等。有时候用户还必须根据自己板子的硬件资源情况做适当的调整与修改。系统启动代码完成基本软硬件环境初始化后,对于有操作系统的情况下,启动操作系统、启动内存管理、任务调度、加载驱动程序等,最后执行应用程序或等待用户命令;对于没有操作系统的系统直接执行应用程序或等待用户命令。6TM6Tonyvopo123@126.com设置中断异常向量系统寄存器配置看门狗及外围电路初始化存储器电路初始化初始化栈指针变量初始化数据区准备高级语言入口函数调用启动代码是用来初始化电路以及用来为高级语言写的软件做好运行前准备的一小段汇编语言,在商业实时操作系统中,启动代码部分一般被称为板级支持包,英文缩写为BSP。它的主要功能就是:电路初始化和为高级语言编写的软件运行做准备。右图:嵌入式系统启动流程图7TM7Tonyvopo123@126.comBootloader概述简单地说,BootLoader就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。通常,BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的。尽管如此,我们仍然可以对BootLoader归纳出一些通用的概念来,以指导用户特定的BootLoader设计与实现。8TM8Tonyvopo123@126.com1.BootLoader所支持的CPU和嵌入式板每种不同的CPU体系结构都有不同的BootLoader。有些BootLoader也支持多种体系结构的CPU,比如U-Boot就同时支持ARM体系结构和MIPS体系结构。除了依赖于CPU的体系结构外,BootLoader实际上也依赖于具体的嵌入式板级设备的配置。这也就是说,对于两块不同的嵌入式板而言,即使它们是基于同一种CPU而构建的,要想让运行在一块板子上的BootLoader程序也能运行在另一块板子上,通常也都需要修改BootLoader的源程序。9TM9Tonyvopo123@126.com2.BootLoader的安装媒介(InstallationMedium)系统加电或复位后,所有的CPU通常都从某个由CPU制造商预先安排的地址上取指令。。而基于CPU构建的嵌入式系统通常都有某种类型的固态存储设备(比如:ROM、EEPROM或FLASH等)被映射到这个预先安排的地址上。因此在系统加电后,CPU将首先执行BootLoader程序。下图就是一个同时装有BootLoader、内核的启动参数、内核映像和根文件系统映像的固态存储设备的典型空间分配结构图。10TM10Tonyvopo123@126.com3.用来控制BootLoader的设备或机制主机和目标机之间一般通过串口建立连接,BootLoader软件在执行时通常会通过串口来进行I/O,比如:输出打印信息到串口,从串口读取用户控制字符等。4.BootLoader的启动过程是单阶段(SingleStage)还是多阶段(Multi-Stage)通常多阶段的BootLoader能提供更为复杂的功能,以及更好的可移植性。从固态存储设备上启动的BootLoader大多都是2阶段的启动过程,也即启动过程可以分为stage1和stage2两部分。而至于在stage1和stage2具体完成哪些任务将在下面讨论。11TM11Tonyvopo123@126.com5.BootLoader的操作模式(OperationMode)大多数BootLoader都包含两种不同的操作模式:“启动加载”模式和“下载”模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,BootLoader的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。启动加载(Bootloading)模式:这种模式也称为“自主”(Autonomous)模式。也即BootLoader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。下载(Downloading)模式:在这种模式下,目标机上的BootLoader将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。12TM12Tonyvopo123@126.com6.BootLoader与主机之间进行文件传输所用的通信设备及协议最常见的情况就是,目标机上的BootLoader通过串口与主机之间进行文件传输,传输协议通常是xmodem/ymodem/zmodem协议中的一种。但是,串口传输的速度是有限的,因此通过以太网连接并借助TFTP协议来下载文件是个更好的选择。在通过以太网连接和TFTP协议来下载文件时,主机方必须有一个软件用来的提供TFTP服务。13TM13Tonyvopo123@126.com假定内核映像与根文件系统映像都被加载到RAM中运行.另外,由于BootLoader的实现依赖于CPU的体系结构,因此大多数BootLoader都分为stage1和stage2两大部分。依赖于CPU体系结构的代码,比如设备初始化代码等,通常都放在stage1中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而stage2则通常用C语言来实现,这样可以实现给复杂的功能,而且代码会具有更好的可读性和可移植性。BootLoader的结构框架14TM14Tonyvopo123@126.comBootloader的stage1BootLoader的stage1通常包括以下步骤(以执行的先后顺序):(1)硬件设备初始化。(2)为加载BootLoader的stage2准备RAM空间。(3)拷贝BootLoader的stage2到RAM空间中。(4)设置好堆栈。(5)跳转到stage2的C入口点。15TM15Tonyvopo123@126.comBootloader的stage2(1/2)通常包括以下步骤(以执行的先后顺序):初始化本阶段要使用到的硬件设备。检测系统内存映射(memorymap)。将kernel映像和根文件系统映像从flash上读到RAM空间中。为内核设置启动参数。调用内核。16TM16Tonyvopo123@126.comBootloader的stage2确(2/2)stage2的代码通常用C语言来实现,以便于实现更复杂的功能和取得更好的代码可读性和可移植性。与普通C语言应用程序不同的是,在编译和链接Bootloader这样的程序时,我们不能使用glibc库中的任何支持函数。17TM17Tonyvopo123@126.comLinux的BootloaderBootloaer功能系统配置、中断接管、引导装载内核、根文件系统、参数传递、内核调试、内核和根文件系统的下载等等常见的uClinux(Linux)的Bootloader:RedbootBlobViviUbootarmBoot…18TM18Tonyvopo123@126.comU-boot命令U-Boot的常用命令的用法进入U-Boot控制界面后,可以运行各种命令,比如下载文件到内存,擦除、读写Flash,运行内存、NORFlash、NANDFlash中的程序,查看、修改、比较内存中的数据等。使用各种命令时,可以使用其开头的若干个字母代替它。比如tftpboot命令,可以使用t、tf、tft、tftp等字母代替,只要其他命令不以这些字母开头即可。当运行一个命令之后,如果它是可重复执行的(代码中使用U_BOOT_CMD定义这个命令时,第3个参数是1),若想再次运行可以直接输入回车。U-Boot接收的数据都是十六进制,输入时可以省略前缀0x、0X。19TM19Tonyvopo123@126.com(1)帮助命令help运行help命令可以看到U-Boot中所有命令的作用,如果要查看某个命令的使用方法,运行“help命令名”,比如“helpbootm”。可以使用“?”来代替“help”,比如直接输入“?”、“?bootm”。(2)下载命令U-Boot支持串口下载、网络下载,相关命令有:loadb、loads、loadx、loady和tftpboot、nfs。前几个串口下载命令使用方法相似,以loadx命令为例,它的用法为“loadx[off][baud]”。“[]”表示里面的参数可以省略,off表示文件下载后存放的内存地址,baud表示使用的波特率。如果baud参数省略,则使用当前的波特率;如果off参数省略,存放的地址为配置文件中定义的宏CFG_LOAD_ADDR。20TM20Tonyvopo123@126.comtftpboot命令使用TFTP协议从服务器下载文件,服务器的IP地址为环境变量serverip。用法为“tftpboot[loadAddress][bootfilename]”,loadAddress表示文件下载后存放的内存地址,bootfilename表示要下载的文件的名称。如果loadAddress省略,存放的地址为配置文件中定义的宏CFG_LOAD_ADDR;如果bootfilename省略,则使用开发板的IP