2.1.2 嵌入式系统的启动概述
在嵌入式系统加电后,会触发CPU的复位信号(reset),导致CPU复位。CPU复位操作完成之后,一般情况下会直接跳转到内存空间的固定位置,取得第一条指令,并开始执行。不同的CPU,第一条开始执行的指令的位置是不一样的,比如,在ARM系列的CPU中,第一条开始执行的指令在地址空间的开始处(即0x00000000位置,在32位CPU情况下),而在Intel系列的IA32构架CPU中,CPU开始执行的第一条指令,则位于0xFFFFFFF0位置。第一条指令所在的位置(一般称为启动向量),一般情况下是Boot ROM所在的位置,在Boot ROM中,存放了CPU开始执行的第一条指令。这是一条跳转指令,跳转到另外一个固定的位置继续执行。一个很常用的做法是在Boot ROM中存放了嵌入式系统的初始化代码,启动向量所在的跳转指令,其目标跳转地址则是这些初始化代码的开始处。这样嵌入式系统一旦加电,第一部分正式执行的代码,就是硬件系统的初始化代码。
对于硬件系统的初始化,有的情况下会十分复杂,需要初始化的硬件芯片(或硬件设备)非常多,这样必然导致初始化代码十分庞大,把这些庞大的初始化代码放在Boot ROM中是不合适的。因此在这种情况下,Boot ROM里面一般只存放了关键部件的初始化代码,比如CPU的初始化(工作模式的选择等)、MMU的初始化(页表、段表的建立)、中断控制器的初始化、简单输入/输出接口(比如,COM接口)的初始化等。另外,设备的初始化代码与嵌入式操作系统放在一起,作为操作系统的一部分代码来实现。
Boot ROM中的硬件初始化代码执行完毕,对基本的硬件环境完成初始化之后,下一步工作就是加载操作系统和应用软件了(在嵌入式系统中,操作系统和应用软件往往编译在一个二进制模块中)。这个过程会根据不同的配置,以及不同规模的应用,有不同的实现方式。在接下来的部分当中,我们对常见的加载方式进行描述。
一般情况下,操作系统和应用代码的映像存储在Flash当中,因此在加载的时候,必然涉及对Flash的操作。在嵌入式系统中,Flash一般是直接映射到CPU的地址空间中的,因此,使用CPU的访问内存指令,就可以直接完成对Flash的操作,无需额外提供Flash设备的驱动程序。但这种方式有一个缺点,就是占用了CPU的地址空间。若不采取这样的方式,而是把Flash当做存储外设(比如硬盘),则必须提供特定的驱动程序,来支撑对这种形态的Flash的访问。由于这时候操作系统还没有加载,Flash的驱动程序只能存放在Boot ROM中。