分享

BootLoader

 黄南山 2018-03-10

BootLoader是系统加电启运行的第一段软件代码,回忆一下PC的体系结构我们可以知道,PC机中的引导加载程序由BIOS(其本质就是一段固件程序)和位于硬盘MBR中的引导程序一起组成。BIOS在完成硬件检测和资源分配后,将硬盘MBR中的引导程序读到系统的RAM中,然后将控制权交给引导程序。引导程序的主要运行任务就是将内核映象从硬盘上读到RAM中 然后跳转到内核的入口点去运行,也即开始启动操作系统。 

而在嵌入式系统中,通常并没有像BIOS那样的固件程序(有的嵌入式系统也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成.比如在一个基于 ARM7TDMI core的嵌入式系统中,系统在上电或复位时都从地址 0x00000000开始执行.而在这个地址处安排的通常就是系统的BootLoader程序。 

简单地说BootLoader就是在操作系统内核或用户应用程序运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图(有的CPU没有内存映射功能如 S3C44B0),从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核或用户应用程序准备好正确的环境。对于一个嵌入式系统来说,可能有的包括操作系统,有的小型系统也可以只包括应用程序,但是在这之前都需要BootLoader为它准备一个正确的环境。通常,BootLoader是依赖于硬件而实现的,特别是在嵌入式领域,为嵌入式系统建立一个通用的BootLoader是很困难的。

反过来,大部分Bootloader仍然具有很多共性,某些Bootloader也能够支持多种体系结构的嵌入式系统。例如,U-Boot就同时支持PowerPC、ARM、MIPS和X86等体系结构,支持的板子有上百种。通常,它们都能够自动从存储介质上启动,都能够引导操作系统启动,并且大部分都可以支持串口和以太网接口。

种类 /BootLoader 编辑

常用引导程序常用引导程序图册

嵌入式系统世界已经有各种各样的Bootloader,种类划分也有多种方式。除了按照处理器体系结构不同划分以外,还有功能复杂程度的不同。

首先区分一下“Bootloader”和“Monitor”的概念。严格来说,“Bootloader”只是引导设备并且执行主程序的固件;而“Monitor”还提供了更多的命令行接口,可以进行调试、读写内存、烧写Flash、配置环境变量等。“Monitor”在嵌入式系统开发过程中可以提供很好的调试功能,开发完成以后,就完全设置成了一个“Bootloader”。所以,习惯上大家把它们统称为Bootloader。

表列出了Linux的开放源码引导程序及其支持的体系结构。表中给出了X86 ARM PowerPC体系结构的常用引导程序,并且注明了每一种引导程序是不是“Monitor”。

(1)X86
X86的工作站和服务器上一般使用LILO和GRUB。LILO是Linux发行版主流的Bootloader。不过Redhat Linux发行版已经使用了GRUB,GRUB比LILO有更有好的显示界面,使用配置也更加灵活方便。在某些X86嵌入式单板机或者特殊设备上,会采用其他Bootloader,例如:rolo。这些Bootloader可以取代BIOS的功能,能够从FLASH中直接引导Linux启动。现在ROLO支持的开发板已经并入U-Boot,所以U-Boot也可以支持X86平台。

(2)ARM
ARM处理器的芯片商很多,所以每种芯片的开发板都有自己的Bootloader。结果ARM bootloader也变得多种多样。最早有为ARM720处理器的开发板的固件,又有了armboot,StrongARM平台的blob,还有S3C2410处理器开发板上的vivi等。现在armboot已经并入了U-Boot,所以U-Boot也支持ARM/XSCALE平台。U-Boot已经成为ARM平台事实上的标准Bootloader。

(3)PowerPC
PowerPC平台的处理器有标准的Bootloader,就是ppcboot。PPCBOOT在合并armboot等之后,创建了U-Boot,成为各种体系结构开发板的通用引导程序。U-Boot仍然是PowerPC平台的主要Bootloader。

(4)MIPS
MIPS公司开发的YAMON是标准的Bootloader,也有许多MIPS芯片商为自己的开发板写了Bootloader。现在,U-Boot也已经支持MIPS平台。

(5)SH
SH平台的标准Bootloader是sh-boot。Redboot在这种平台上也很好用。

(6)m68k
M68K平台没有标准的Bootloader。Redboot能够支持m68k系列的系统。值得说明的是Redboot,它几乎能够支持所有的体系结构,包括MIPS、SH、M68K等体系结构。Redboot是以eCos为基础,采用GPL许可的开源软件工程。

作用原理/BootLoader 编辑

1、Boot Loader 所支持的 CPU 和嵌入式板
每种不同的 CPU 体系结构都有不同的Boot Loader。有些 Boot Loader 也支持多种体系结构的 CPU,比如 U-Boot 就同时支持 ARM 体系结构和MIPS 体系结构。除了依赖于 CPU的体系结构外,Boot Loader 实际上也依赖于具体的嵌入式板级设备的配置。这也就是说,对于两块不同的嵌入式板而言,即使它们是基于同一种 CPU 而构建的,要想让运行在一块板子上的 Boot Loader 程序也能运行在另一块板子上,通常也都需要修改 Boot Loader 的源程序。

2、Boot Loader 的安装媒介(Installation Medium)
系统加电或复位后,所有的CPU 通常都从某个由 CPU 制造商预先安排的地址上取指令。比如,基于 ARM7TDMI core 的 CPU 在复位时通常都从地址 0x00000000 取它的第一条指令。而基于CPU 构建的嵌入式系统通常都有某种类型的固态存储设备(比如:ROM、EEPROM 或 FLASH 等)被映射到这个预先安排的地址上。因此在系统加电后,CPU 将首先执行Boot Loader 程序。

3、用来控制 Boot Loader 的设备或机制
主机和目标机之间一般通过串口建立连接,Boot Loader 软件在执行时通常会通过串口来进行 I/O,比如:输出打印信息到串口,从串口读取用户控制字符等。

4、Boot Loader 的启动过程是单阶段(Single Stage)还是多阶段(Multi-Stage)
通常多阶段的 Boot Loader 能提供更为复杂的功能,以及更好的可移植性。从固态存储设备上启动的。

6、BootLoader 与主机之间进行文件传输所用的通信设备及协议程,也即启动过程可以分为 stage 1和 stage 2 两部分。而至于在 stage 1 和 stage 2 具体完成哪些任务将在下面几篇讨论。

5、Boot Loader 的操作模式 (Operation Boot Loader 大多都是 2 阶段的启动过Mode)。

构成组件/BootLoader 编辑

BootLoader主要由以下两部分组成。
(1)OEM startup code
这部分代码是在BootLoader中最先被执行的。它的主要功能是初始化最小范围的硬件设备,比如设置CPU工作频率、关闭看门狗、设置cache、设置RAM的刷新率、填写内存控制寄存器(通知CPU有效的数据总线引脚数)等。由于系统刚刚启动,不适合使用复杂的高级语言,因此这部分代码主要由汇编程序完成。在汇编程序段设置完堆栈后,就跳转到C语言的Main函数入口(位于<PLATNAME>/eboot/main.c);

(2)Main code
这部分代码由C语言实现,是BLCOMMON代码的一部分,它可以用来执行比较复杂的操作。比如检测内存和Flash的有效性、检测外部设备接口、检测串口并且向已经连接的主机发送调试信息、通过串口等待命令、启动网络接口、建立内存映射等汇编无法完成的工作。

Main code包含以下代码段:
Image download代码段
Image的下载可以通过以下接口。

① A. Parallel port I/O接口。这是通过主机和目标机的并口之间的数据传输来完成下载工作。具体实现代码,读者可以参考/kernel/hal/mdppfs.c文件;

② Ethernet port I/O接口。这是通过主机和目标机的网络接口之间的数据传输来完成下载工作。具体实现代码,读者可以参考WINCE420/public/common/oak/DRIVE|RS/ETHDBG/EBOOT文件夹;

③ Debug serial I/O接口。这是通过主机和目标机的串口之间的数据传输来完成下载工作。利用串口来传输的缺点非常明显,那就是速度太慢;

通过事先Flash write代码将镜像文件固化入Flash。只要BootLoader被设计成能从Flash加载镜像文件,本选项就可以使用。 [1]

启动方式/BootLoader 编辑

网络启动示意图网络启动示意图图册

1、网络启动方式
这种方式开发板不需要配置较大的存储介质,跟无盘工作站有点类似。但是使用这种启动方式之前,需要把Bootloader安装到板上的EPROM或者Flash中。Bootloader通过以太网接口远程下载Linux内核映像或者文件系统。第4章介绍的交叉开发环境就是以网络启动方式建立的。这种方式对于嵌入式系统开发来说非常重要。使用这种方式也有前提条件,就是目标板有串口、以太网接口或者其他连接方式。串口一般可以作为控制台,同时可以用来下载内核影像和RAMDISK文件系统。串口通信传输速率过低,不适合用来挂接NFS文件系统。所以以太网接口成为通用的互连设备,一般的开发板都可以配置10M以太网接口。

对于PDA等手持设备来说,以太网的RJ-45接口显得大了些,而USB接口,特别是USB的迷你接口,尺寸非常小。对于开发的嵌入式系统,可以把USB接口虚拟成以太网接口来通讯。这种方式在开发主机和开发板两端都需要驱动程序。

另外,还要在服务器上配置启动相关网络服务。Bootloader下载文件一般都使用TFTP网络协议,还可以通过DHCP的方式动态配置IP地址。DHCP/BOOTP服务为Bootloader分配IP地址,配置网络参数,然后才能够支持网络传输功能。如果Bootloader可以直接设置网络参数,就可以不使用DHCP。TFTP服务为Bootloader客户端提供文件下载功能,把内核映像和其他文件放在/tftpboot目录下。这样Bootloader可以通过简单的TFTP协议远程下载内核映像到内存。

2、磁盘启动方式
传统的Linux系统运行在台式机或者服务器上,这些计算机一般都使用BIOS引导,并且使用磁盘作为存储介质。如果进入BIOS设置菜单,可以探测处理器、内存、硬盘等设备,可以设置BIOS从软盘、光盘或者某块硬盘启动。也就是说,BIOS并不直接引导操作系统。那么在硬盘的主引导区,还需要一个Bootloader。这个Bootloader可以从磁盘文件系统中把操作系统引导起来。

Linux传统上是通过LILO(LInux LOader)引导的,后来又出现了GNU的软件GRUB(GRand Unified Bootloader)。这2种Bootloader广泛应用在X86的Linux系统上。你的开发主机可能就使用了其中一种,熟悉它们有助于配置多种系统引导功能。LILO软件工程是由Werner Almesberger创建,专门为引导Linux开发的。现在LILO的维护者是John Coffman,最新版本下载站点:<http://lilo.go./>。LILO有详细的文档,例如LILO套件中附带使用手册和参考手册。此外,还可以在LDP的“LILO mini-HOWTO”中找到LILO的使用指南。

GRUB是GNU计划的主要bootloader。GRUB最初是由Erich Boleyn为GNU Mach操作系统撰写的引导程序。后来有Gordon Matzigkeit和Okuji Yoshinori接替Erich的工作,继续维护和开发GRUB。GRUB的网站http://www./software/grub/上有对套件使用的说明文件,叫作《GRUB manual》。GRUB能够使用TFTP和BOOTP或者DHCP通过网络启动,这种功能对于系统开发过程很有用。除了传统的Linux系统上的引导程序以外,还有其他一些引导程序,也可以支持磁盘引导启动。例如:LoadLin可以从DOS下启动Linux;还有ROLO、LinuxBIOS,U-Boot也支持这种功能。

3、Flash启动方式
大多数嵌入式系统上都使用Flash存储介质。Flash有很多类型,包括NOR Flash、NAND Flash和其他半导体盘。其中,NOR Flash(也就是线性Flash)使用最为普遍。NOR Flash可以支持随机访问,所以代码是可以直接在Flash上执行的。Bootloader一般是存储在Flash芯片上的。另外,Linux内核映像和RAMDISK也可以存储在Flash上。通常需要把Flash分区使用,每个区的大小应该是Flash擦除块大小的整数倍。

Bootloader一般放在Flash的底端或者顶端,这要根据处理器的复位向量设置。要使Bootloader的入口位于处理器上电执行第一条指令的位置。

接下来分配参数区,这里可以作为Bootloader的参数保存区域。再下来内核映像区。Bootloader引导Linux内核,就是要从这个地方把内核映像解压到RAM中去,然后跳转到内核映像入口执行。然后是文件系统区。如果使用Ramdisk文件系统,则需要Bootloader把它解压到RAM中。如果使用JFFS2文件系统,将直接挂接为根文件系统。最后还可以分出一些数据区,这要根据实际需要和Flash大小来考虑了。

这些分区是开发者定义的,Bootloader一般直接读写对应的偏移地址。到了Linux内核空间,可以配置成MTD设备来访问Flash分区。但是,有的Bootloader也支持分区的功能,例如:Redboot可以创建Flash分区表,并且内核MTD驱动可以解析出redboot的分区表。除了NOR Flash,还有NAND Flash、Compact Flash、DiskOnChip等。这些Flash具有芯片价格低,存储容量大的特点。但是这些芯片一般通过专用控制器的I/O方式来访问,不能随机访问,因此引导方式跟NOR Flash也不同。在这些芯片上,需要配置专用的引导程序。通常,这种引导程序起始的一段代码就把整个引导程序复制到RAM中运行,从而实现自举启动,这跟从磁盘上启动有些相似。

操作模式/BootLoader 编辑

大多数BootLoader都包含两种不同的操作模式。“启动加载”模式和“下载”模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,BootLoader的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。 

启动加载(Boot loading)模式:这种模式也称为“自主”(Autonomous)模式,也即BootLoader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。这种模式是BootLoader的正常工作模式。因此在嵌入式产品发布的时候,BootLoader显然必须工作在这种模式下。

下载(Down loading)模式:在这种模式下 目标机上的BootLoader将通过串口连接或网络连接等通信手段从主机下载文件,比如:下载应用程序、数据文件、内核映像等.从主机下载的文件通常首先被BootLoader保存到目标机的RAM中然后再被BootLoader写到目标机上的固态存储设备中。BootLoader的这种模式通常在系统更新时使用。工作于这种模式下的BootLoader通常都会向它的终端用户提供一个简单的命令行接口。 

在教学系统中提供的BootLoader中没有实现自主模式,可以通过修改代码来实现该功能。  BootLoader与主机之间进行文件传输所用的通信设备及协议 。

最常见的情况就是,目标机上的BootLoader通过串口与主机之间进行文件传输,传输可以简单的采用直接数据收发,当然在串口上也可以采用xmode/ymode/zmode协议以及在以太网上采用TPTP协议。

此外,在论及这个话题时,主机方所用的软件也要考虑。比如,在通过以太网连接和TFTP协议来下载文件时,主机方必须有一个软件用来提供TFTP服务。 

引导加载程序是系统加电后运行的第一段代码。我们熟悉的PC中的引导程序一般由BIOS和位于MBR的OS bootloader(例如LILO或者GRUB)一起组成。然而在嵌入式系统中通常没有像BIOS那样的固件程序(有的嵌入式CPU有),因此整个系统的加载启动任务就完全由bootloader来完成。在嵌入式Linux中,引导加载程序即等效为bootloader。

安装位置 /BootLoader 编辑

Boot loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。

系统加电或复位后,所有的CPU 通常都从某个预先安排的地址上取指令。例如,基于ARM7TDMI core 的CPU 在复位时通常都从地址0x00000000取它的第一条指令。而基于CPU 构建的嵌入式系统通常都有某种类型的固态存储设备(比如:ROM、EEPROM、或 Flash 等)被映射到这个预先安排的地址上。因此在系统加电后,CPU 将首先执行 Bootloader 程序。通常总是将Boot Loader 安装在嵌入式系统的存储设备的最前端。

固态存储设备的空间划分(地址从低到高顺序):Bootloader,Bootloader参数,内核映像,根文件系统映像。

bootloader是依赖于硬件而实现的,特别是在嵌入式系统中。不同的体系结构需求的bootloader是不同的;除了体系结构,bootloader还依赖于具体的嵌入式板级设备的配置。也就是说,对于两块不同的嵌入式板而言,即使它们基于相同的CPU构建,运行在其中一块电路板上的bootloader,未必能够运行在另一块电路开发板上。

Bootloader的启动过程可以是单阶段的,也可以是多阶段的。通常多阶段的bootloader能提供更为复杂的功能,以及更好的可移植性。从固态存储设备上启动的bootloader大多数是二阶段的启动过程,也即启动过程可以分为stage 1和stage 2两部分。

编写步骤/BootLoader 编辑

第一步:要进行相关硬件的初使化,比如在at91rm9200这块嵌入式板子上(以后都使用这一款芯片,主要是我对这款芯片比较熟悉,嘿嘿),大概要做接下来的几方面的工作,其一:将CPU
CPU

CPU也称为中央处理器,是电子计算机的主要设备之一。其功能主要是解释计算机指令以及处理计算机软件中的数据。所谓的计算机的可编程性主要是指对CPU的编程。CPU是计算机中的核心配件,只有火柴盒那么大,几十张纸那么厚,但它却是一台计算机的运算核心和控制核心。计算机中所有操作都由CPU负责读取指令,对指令译码并执行指令的核心部件。CPU、内部存储器和输入/输出设备是电子计算机的三大核心部件。 

模式切换进系统模式,关闭系统中断,关闭看门狗,根据具体情况进行内存内存内存的正式叫法是内存储器,以此来与外存储器区分开。物理上它安装在计算机内部,通常安装在主板上,所以称为内存。它的作用是供暂时存储处理器需要处理的数据或处理后的结果,可见内存是计算机处理器的工作空间。它是处理器运行的程序和数据必须驻留于其中的一个临时存储区域,是计算机十分重要的部件。区域映射,初始化内存控制区,包括所使用的内存条的相关参数,刷新频率等,其二:设定系统运行频率,包括使用外部晶振晶振晶振:即所谓石英晶体谐振器和石英晶体时钟振荡器的统称。不过由于在消费类电子产品中,谐振器用的更多,所以一般的概念中把晶振就等同于谐振器理解了。

后者就是通常所指钟振,设置CPU频率,设置总线总线总线是将信息以一个或多个源部件传送到一个或多个目的部件的一组传输线。通俗的说,就是多个部件间的公共连线,用于在各个部件之间传输信息。人们常常以MHz表示的速度来描述总线频率。频率,设置外部设备所采用的频率等。其三:设置系统中断相关,包括定时器,定时器是装有时段或时刻控制机构的开关装置。它有一个频率稳定的振荡源,通过齿轮传动或集成电路分频计数,当将时间累加到预置数值时,或指示到预置的时刻处,定时器即发送信号控制执行机构。

中断,是否使用FIQ中断,外部中断等,还有就是中断优先级设置,这里只实现两个优先级,只有时钟中断高一级,其它都一样,而中断向量初始化时都将这些中断向量指向0x18处,并关闭这里的所有中断,如果板子还接有诸如FLASH设备的话,还需要设置诸如FLASH相关操制寄存器,其四:需要关闭CACHE,到此为止,芯片相关内容就完成初始化了。

第二步:中断向量表,ARM的中断与PC机芯片的中断向量表有一点差异,嵌入式设备为了简单,当发生中断时,由CPU直接跳入由0x0开始的一部分区域(ARM芯片自身决定了它中断时就会跳入0x0开始的一片区域内,具体跳到哪个地址是由中断的模式决定的,一般用到的就是复位中断,FIQ,IRQ中断,SWI中断,指令异常中断,数据异常中断,预取指令异常中断),而当CPU进入相应的由0x0开始的向量表中时,这就需要用户自己编程接管中断处理程序了,这就是需要用户自己编写中断向量表,中断向量表里存放的就是一些跳转指令,比如当CPU发生一个IRQ中断时,就会自动跳入到0x18处,这里就是用户自己编写的一个跳转指令,假如用户在此编写了一条跳转到0x20010000处的指令,那么这个地址就是一个总的IRQ中断处理入口,一个CPU可能有多个IRQ中断,在这个总的入口处如何区分不同的中断呢?就由用户编程来决定了,具体实现请参见以后相关部分,中断向量表的一般用一个vector.S文件,当然,如何命名那是你自己的喜爱,但有一点需要声明,那就是在链接时一定要将它定位在0x0处。

第三步:设置堆栈,一般使用三个栈,一个是IRQ栈,一个是系统模式下的栈(系统模式下和用户模式共享寄存器和内存空间,这主要是为了简单),设置栈的目的主要是为了进行函数调用和局部变量的存放,不可能全用汇编,也不可能不用局部变量

第四步:将自己以后的代码段和数据段全部拷贝至内存,并将BSS段清零

第五步:进行串口,串口是计算机上一种非常通用的设备通信协议,大多数计算机包含两个基于RS232的串口。串口同时也是仪器仪表设备的通信协议,并可用于获取远程采集设备的数据的初始化(主要是为了与用户交互,进行与PC机的文件传输),FLASH的初始化这里在FLASH中存放BOOT和内核),FLASH驱动的编写(这里的驱动有别于平常所说的驱动,由于FLASH不像SDRAM,只要设定了相关控制器之后就可以直接读写指定地址的数据,对FLASH的写操作是一块一块数据进行,而不是一个字节一个字节地写,具体请查阅相关资料)

第六步:等待一定的秒数,来接收用户进行输入,如果在指定的秒数内用户未输入任何字符,那么BOOT就开始在FLASH中的指定位置(可以由自己指定,这么做主要是为了简单)读取内核的所有数据到内存中(具体是内存中的什么位置由自己指定,也可以采用Linux之类的做法,就是在内存的起始位置加上一个0x8000处),将跳转到内核的第一条代码处);如果用户在指定的秒数内键入了字符(这主要是为了方便开发,如果开发定型之后完全可以不要这段代码),那么就在串口与用户进行交互,接受用户在串口输入的命令,比如用户要求下载文件在FLASH中指定的位置等,具体内容可参考U-BOOT之类的开源项目到这里为止,BOOT部分已完成,这个BOOT非常简单,仅仅只是将PC机上传下来的文件固化到FLASH中,然后再将FLASH中的操作系统内核部分加载进内存中,并将CPU的控制权交给操作系统。[2]

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多