Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。通常,Boot Loader 是严重地依赖于硬件而实现的,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的 Boot Loader 几乎是不可能的。尽管如此,我们仍然可以对 Boot Loader 归纳出一些通用的概念来,以指导用户特定的 Boot Loader 设计与实现。
大多数 Boot Loader 都包含两种不同的操作模式:"启动加载"模式和"下载"模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。 启动加载(Boot loading)模式:这种模式也称为"自主"(Autonomous)模式。也即 Boot Loader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。这种模式是 Boot Loader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下。 下载(Downloading)模式:在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 Boot Loader 保存到目标机的 RAM 中,然后再被 Boot Loader 写到目标机上的FLASH 类固态存储设备中。Boot Loader 的这种模式通常在次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用 Boot Loader 的这种工作模式。工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的命令行接口。 像 Blob 或 U-Boot 等这样功能强大的 Boot Loader 通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。比如,Blob 在启动时处于正常的启动加载模式,但是它会延时 10 秒等待终端用户按下任意键而将 blob 切换到下载模式。如果在 10 秒内没有用户按键,则 blob 继续启动 Linux 内核。
每种不同的 CPU 体系结构都有不同的 Boot Loader。有些 Boot Loader 也支持多种体系结构的 CPU,比如 U-Boot 就同时支持 ARM 体系结构和MIPS 体系结构。除了依赖于 CPU 的体系结构外,Boot Loader 实际上也依赖于具体的嵌入式板级设备的配置。这也就是说,对于两块不同的嵌入式板而言,即使它们是基于同一种 CPU 而构建的,要想让运行在一块板子上的 Boot Loader 程序也能运行在另一块板子上,通常也都需要修改 Boot Loader 的源程序。
系统加电或复位后,所有的 CPU 通常都从某个由 CPU 制造商预先安排的地址上取指令。比如,基于 ARM7TDMI core 的 CPU 在复位时通常都从地址 0x00000000 取它的条指令。而基于 CPU 构建的嵌入式系统通常都有某种类型的固态存储设备(比如:ROM、EEPROM 或 FLASH 等)被映射到这个预先安排的地址上。因此在系统加电后,CPU 将首先执行 Boot Loader 程序。
下图就是一个同时装有 Boot Loader、内核的启动参数、内核映像和根文件系统映像的固态存储设备的典型空间分配结构图。
图 固态存储设备的典型空间分配结构
系统上电复位后, 在完成各种初始化配置后首先判断0x500地址单元中值是否为0xFF, 如果是,则说明系统从未下载过用户程序, 系统会一直运行Boot loader程序等待PC 机发送下载命令; 如果0x500中的值不是0xFF, 则说明系统中已经下载过用户程序了, 这时候根据0x500中的值来设置定时器T imer2的初值并开始计时, 如果UART2 在指定的自举周期内未接收到PC 机发来的下载命令(说明系统不需要下载程序), 系统会自动跳出Boo tloader程序而去运行已有的用户代码, 如果UART2在自举周期内接收到了下载命令, Boo tloader程序会进入循环状态等待PC机发送数据。如图所示。
图 程序流程图。
如前文所述, PC 机发送的数据是从. hex 文件中提取的, PC机首先发送扩展地址部分, 下位机接收保存后会继续等待接收32个指令字( 96字节)并保存到RAM 中, 然后根据接收到的地址擦除FLASH 存储器中的1行, 擦除FLASH 是通过调用汇编函数E raseMem来进行的, 函数原型如下:
mov# 0x4041, NVMCON ; 使NVMCON 寄存器为擦除FLASH模式
mov # 0x55, W 0
movW0, NVMKEY
mov # 0xAA, W0
movW 0, NVMKEY ; 将0x55、0xAA 写入密钥寄存器
bsetNVMCON, #WR ; 开始擦除
nop
nop
return
擦除FLASH存储器的一行后需要把接收到的32个指令字写入到FLASH 存储器写锁存器中, 这一过程可以通过函数W riteLatch 实现, 函数原型如下:
movW0, TBLPAG ; 写表寄存器
tb lw tlW3, [W1]
tb lw thW2, [W1] ; 写入锁存器
return
这一步完成之后就可以将接收到的32个指令字写入FLASH 存储器了, 其方法与擦除FLASH 类似, 写完一行后向PC 机发送应答。待FLASH 存储器全部写完之后, PC 机会发送表示结束下载的命令, 下位机接收后退出Boo tloader程序, 进入新的用户程序继续运行, 从而完成整个在线自编程过程。
Bootloader相当于PC主板上的B IOS, 是层的引导软件。Boo tloader是一段固化在嵌入式系统目标系统ROM或者是诸如FLASH 等非易失存储器中的一段程序, 它的主要作用就是引导操作系统或用户程序的运行。系统上电后Boo tloader将首先接管系统, 在进行一些最基本的上电自检后, Bootloader将对系统的硬件进行初始化, 为引导操作系统作好准备, 接下来, Bootloader需要将操作系统的代码拷贝到主存储器的特定地址, Boot loader将控制权交给操作系统, 由操作系统完成接下来的工作;在不含操作系统的系统中, Bootloader可以完成这样一些操作: 分配程序存储空间; 重新映射复位和中断向量; 将程序代码从片外加载到程序区, 执行时再将代码加载到RAM 中以便快速执行; 检测是否需要下载新的用户代码, 若需要则通过某种通信方式接收新代码并将其写入指定程序存储空间中, 若不需要, 则执行原有用户代码。