3.2. 目标产品中BSP的实现
3.2.1 BSP独立实现
把核心和文件系统直接从主机下载到内存中运行,只适用于开发调试阶段。目标产品中核心和文件系统烧写在非易失性存储设备上,因此BSP要从这些设备中加载并启动核心。此时,BSP不需要与主机通信,可以将其单独实现在产品中。将BSP单独实现时,可以根据需要向其中灵活地添加多种功能:启动核心前检测内存是否能被正确读写,通过判断网卡、声卡等硬件的属性寄存器确定硬件设备是否正常等。此时,BSP要完成的工作如下:
(1)初始化硬件及存储设备。
(2)测试硬件设备是否正常。
(3)从相应的存储设备中加载核心到内存中,并启动核心。
硬件的初始化和配置与前面相同,主要完成CPU和内存的初始化。此时,BSP要从存储设备中加载并启动核心,因此要对存储设备(一般是FLASH或CF卡)进行初始化,使其能被正确寻址。BSP中读取核心的代码与具体的操作系统及文件格式无关,不能从文件系统层把核心作为一个文件读进来,只能从硬件接口来实现具体的操作,把核心从存储设备读入内存,然后把核心的开头当作一段程序的起点,使CPU转入核心执行[ 。
非易失性存储器FLASH和内存统一寻址,对它的访问和访问内存是一样的,可以利用寄存器将核心直接从FALSH读取到内存。CF卡相对内存来说属于外设,对其进行读取操作是通过控制其寄存器(数据寄存器、状态与控制寄存器)来实现的,向其控制寄存器发布ATA命令OA何处读取,读取数据的大小等)后,判断其状态寄存器是否准备好,才能从其数据寄存器中读取数据到内存中。把核心从非易失性存储设备读到内存中后,将CPU中的程序计数器PC置为核心在内存中的起始地址,实现系统的启动。
对应的伪码如下:
硬件(cup、内存等)初始化;
存储设备(FLASH、CF卡)初始化;
测试硬件设备是否正常;
根据CF卡的属性寄存器判断CF卡是否存在;
如果存在,跳转到从CF卡加载核心到内存的函数;
如果不存在,直接将核心从FLASH加载到内存中;
mov pc,一核心在内存中的起始地址;
从CF卡加载核心到内存的函数(void)
{
while(核心没加载完){
向CF卡发布ATA命令,确定从CF卡的哪一块开始读,
读多少块
while(CF卡的状态没准备好){等待;}
从CF卡的数据寄存器读数据到内存中;
核心大小减去所读的块数乘以块大小;
if(核心加载完){
-asm{mow pc,=核心在内存中的起始地址;}
}
}
3.2.2 在核心中实现BSP
BSP单独实现易于修改,当硬件改变时,只需要对相关硬件的初始化代码进行修改并重新编译。但是,对于嵌入式系统的存储介质FLASH,有些文件系统对它的分区有字节对齐性的要求,也就是说分区必须是特定大小或特定大小的倍数才能有写访问权限,如果把BSP单独写在一个分区中会造成存储空间的浪费。实质上,BSP是属于操作系统的一部分且和操作系统绑定在一起运行,在开发板硬件固定的情况下,可以将其实现在Linux核心中。在核心中实现BSP时,BSP应能向核心提供必要的底层硬件信息,实现核心从非易失性存储器FLASH到内存的加载和启动。
在嵌入式系统的存储介质FLASH中没有所谓的引导扇区,相应的嵌入式Linux内核映象zImage也没有如PC机上的引导扇区代码bootsect及辅助代码setup,而是由head.o、misc.o、head-xscale.o和piggy.o几个文件顺序连接而成。其中,head.o是由/arch/arm/boot/compressed/head.S汇编而成,是核心最先执行的代码,主要作用是用misc.o解压缩核心并使CPU转到核心解压缩后所在的内存地址执行。head-xscale.o是体系结构相关的代码。piggy.o是系统启动后保留在内存中的全部有用程序[3],也就是head.o要解压缩的代码。由以上分析可知,嵌入式Linux的内核不能自启动,要启动核必须满足以下两个条件:
(1)系统硬件已被正确初始化;
(2)核心在内存中,并且CPU中的程序计数器被置为核心在内存中的起始地址。
在核心中实现BSP时,BSP必须位于核心代码的最前面,即将其实现在head.S文件的最前面,完成如PC 机上的BIOS、bootsect和setup的功能。同时,要保证核心在加载到内存后必须能跳转到和没有BSP时核心中相同的地方执行。重新编译核心后,就将BSP实现在核心映象zImage中的开始代码中。把核心烧到FLASH的0地址,系统启动时首先执行上述代码,将核心加载到内存中执行,实现核心的自启动。