RTOS的引导是指将操作系统装入内存并开始执行的过程。
在嵌入式系统的实际应用中,针对不同应用环境,对时间效率和空间效率有不同的要求。
通常不可能同时满足两种要求,需根据具体情况进行折中处理,由此,RTOS的引导分为如下两种模式。
BootLoader是RTOS内核运行之前执行的一段小程序,它将RTOS内核从外部存储介质复制到内存中,并让PC跳转到刚复制到的内存的内核的首条指令。
在嵌入式系统中,BootLoader依赖于硬件,几乎不可能建立一个通用的BootLoader。
不同的CPU体系结构都有不同的BootLoader,另外,BootLoader还依赖于具体的嵌入式板级设备的配置。
对于采用高性能RAM的系统,出于成本因素,RAM空间有一定限制,此时一般采用BootLoader引导方式:
由Loader程序把RTOS内核中的数据段复制到RAM中,代码段在Flash中运行。
因为代码段在低速的Flash中运行,该方式在节省空间的同时,却牺牲了时间。这种引导方式适合于硬件成本低、运行速度相对较慢的嵌入式系统,但是启动时间却较快。
另外,如果RAM空间没有限制,足够程序运行时,由Loader程序把RTOS内核从非易失性存储介质全部复制到RAM中,对于某些压缩的内核,复制后还需要解压。此时,不能满足对启动速度要求特别高的系统,但是系统的运行速度却能够得到保障。
对于实时性要求较高的系统,通常要求系统能够快速启动。
由于将Flash中的代码复制到RAM中的操作会带来一定的时间开销,因此,对于此类系统启动时无须BootLoader,而直接在NORFLASH或ROM等可以做主存的非易失性存储介质中运行,以达到较快的启动速度。但这种引导模式不能满足运行速度的要求,因为Flash的访存时间与RAM的访存时间存在数量级上的差距。
出于空闲效率的要求,需要对RTOS内核使用压缩工具进行压缩,在RTOS引导时,采用逆向解压算法解压。
同时,出于实时性考虑,压缩算法不能过于复杂,否则压缩、解压过程消耗大量时间将与启动时间限制发生严重冲突。
采用压缩策略并不一定会增加系统启动时间,因为压缩,解压过程虽然消耗了一定的时间,但由于内核体积减小,由Flash复制到RAM中的时间相应减少,有可能反而减少了时间消耗。
以VxWorks操作系统为例,VxWorks Image分为在ROM中运行和在RAM中运行两种。
在ROM中运行的是非压缩的,不需要解压。
在RAM中运行的是压缩的,引导时需要解压COPY所有的text和data到RAM中。
从上面可以看出,在PC上,BIOS满足上面的特性,因为PC启动时就是从BIOS的地址处启动的,然后BIOS的代码读取硬盘的第一扇区的数据,即引导程序,然后将控制器交给引导程序,然后将控制器交给引导程序,再由引导程序加载操作系统内核代码运行。
而在嵌入式系统中,ViVi、Uboot等就是BootLoader,这些程序都是开机时就启动,启动后,会从NAND Flash或SD卡等存储设备中将RTOS内核程序代码复制到SDRAM中,然后执行内核代码。
Vivi,Uboot代码量大的原因主要是:它们都支持多种嵌入式平台,都可以看成一个通用的BootLoader;除了上面的启动,RTOS加载两个功能,他们还支持更多功能,如支持各种命令,这些命令主要可以分为如下两大类。
有些BootLoader,如ARM公司的Bootmonitor还支持文件系统,能以文件系统的方式管理NANDFlash、SDCARD、COMPCAT CARD上的数据。有了上面两大类操作的支持后,BootLoader已经不再是纯粹的BootLoader了,它已经具备了一些操作系统的基本功能,只是不支持操作系统支持的任务管理、调度、切换等功能。
其实像VIVI、Uboot这些BootLoader在电子产品中很少用到,因为电子产品强调性能、成本,并且不太愿意用户有太大的修改权利。同时,由于Uboot尺寸大,启动时间很长,严重影响系统性能和成本,因此,BootLoader越小越好。
也许大家会说,如果BootLoader只是这两个功能,那干嘛还独立出这个BootLoader,直接将这部分代码写到操作系统。
真正在商用产品中,就是这样,只不过它的功能还在,所以仍然称为BootLoader。
只不过这个简单的BootLoader是和内核一起编译,并且通过链接器链接在一起的,这种BootLoader对应于aCoral系统的start.s。
大家知道程序最后运行必须要有随机可读写存储器来存储变量,且速度要快,但是RAM价格昂贵,于是又导致了SDRAM的产生。
链接文件就是一个告诉链接器如何安排一个镜像文件各个部分先后顺序的文件,就像街上的门牌号一样,总是会有个001号,那么就要从该位置开始。
ENTRY(__ENTRY)
MEMORY
{
RAM(wx) : org =0x30000000, len=64M
}
SECTIONS
{
.text:
{
test_start = .;
*(.text)
*(.init.text)
*(.rodata*)
}
}
链接文件acoral.lds的一开始有这样一条代码ENTRY(__ENTRY),根据GNU链接文件的规则:ENTRY(begin)指明程序的入口点为begin标号。这样镜像文件的入口点就是__ENTRY。