第十五章 启动代码
本章讨论在基于ARM处理器的系统中运行的启动代码。它研究了处理器在复位后立即运行的代码,针对的是裸机系统。
裸机系统是指不使用操作系统而直接运行代码的系统。
15.1 启动裸机系统
当处理器复位时,它会在异常向量表中的复位向量位置开始执行。异常向量表的位置可能在地址0x00000000或地址0xFFFF0000。复位处理程序代码必须执行以下部分或全部操作:
在多核系统中,将非主核心置于休眠状态。
初始化异常向量。
初始化内存系统,包括MPU。
初始化核心模式的堆栈和寄存器。
初始化任何关键的I/O设备。
执行VFP的必要初始化。
启用中断。
更改核心模式或状态。
调用
main()
应用程序。
首先需要考虑的是异常向量表的位置。必须确保它包含一组有效的指令,以便分支到相应的处理程序。
GNU汇编器中的_start
指令可以告诉链接器将代码定位在特定地址,并且可以用于将代码放置在向量表中。在主程序执行期间,您可能希望从TCM访问向量表,以便快速访问异常处理程序。系统可能配置为在处理器启动前,使用从接口将启动代码从非易失性存储器复制到TCM中。
当核心复位后,预取单元可能会在启动代码复制到位于向量表的TCM中时被阻塞。当启动代码复制到TCM中时,预取逻辑被释放,并将直接从TCM中获取代码。
或者,向量表和异常处理程序也可能作为上电复位初始化代码的一部分,从外部ROM复制到TCM中。当代码复制到TCM后,TCM将被重新定位到向量表基地址。
下文示例1展示了一个可以放置在异常向量表中的代码示例。
然后,您可能需要为您的应用程序可能使用的各种模式初始化堆栈指针。下示例2展示了为FIQ和IRQ模式初始化堆栈指针的代码。
接下来的步骤是设置缓存、MPU和分支预测器。示例3展示了这类代码的示例。您需要先禁用MPU和缓存,并使缓存失效。示例代码针对的是Cortex-R7处理器。
对于Cortex-R4和Cortex-R5处理器,数据缓存失效可以通过一条CP15指令完成,即MCR p15, 0, r0, c15, c5, 0
,但对于Cortex-R7处理器,启动代码必须显式地循环遍历缓存行并使其失效。
在Cortex-R4和Cortex-R5处理器中,分支预测在处理器复位后会自动启用。而在Cortex-R7中,分支预测可以在分支目标地址缓存失效后安全启用。启用分支预测通常会提高初始化代码的性能。
之后,您可以对MPU的一些区域进行编程,如下示例4中的示例代码所示。
Tcm可能必须在内存映射中重新定位并作为引导代码的一部分启用。如下示例5所示。
如果系统中存在二级缓存,并且在没有操作系统的情况下运行,此时也可能需要使其失效并启用。此外,还必须启用VFP访问权限。
接下来的步骤将取决于系统的具体情况。例如,可能需要:
对将保存未初始化C变量的内存进行零初始化。
将其他变量的初始值从ROM映像复制到RAM。
设置应用程序的堆栈和堆空间。
初始化C库函数。
调用顶级构造函数(对于C++代码)。
执行其他标准的嵌入式C初始化。
对于多核处理器,例如Cortex-R7处理器,常见的方法是允许集群中的单个核心执行系统初始化。如果相同的代码在不同的核心上运行,它将导致核心进入WFI状态并休眠,如第16章《电源管理》所述。CPU0初始化SCU标签RAM后,其他核心可能会醒来。示例6展示了示例代码,该代码确定它正在运行的处理器,然后根据是否在CPU0上运行,或者跳转到初始化代码,或者进入休眠状态。SMP操作系统通常会在稍后唤醒次要核心。