众所周知,对于X86架构:按下电源按钮后,机器开始执行位于0xFFFFFFF0的代码,然后它开始执行BIOS中的代码以进行硬件初始化。在BIOS执行完毕后,它使用引导加载程序将操作系统映像加载到内存中。最后,操作系统代码开始运行。 那么,在ARM架构中,在用户按下电源按钮后,启动过程是什么样子的呢? 谢谢!
众所周知,对于X86架构:按下电源按钮后,机器开始执行位于0xFFFFFFF0的代码,然后它开始执行BIOS中的代码以进行硬件初始化。在BIOS执行完毕后,它使用引导加载程序将操作系统映像加载到内存中。最后,操作系统代码开始运行。 那么,在ARM架构中,在用户按下电源按钮后,启动过程是什么样子的呢? 谢谢!
目前,在ARM架构中有两个异常模型(重置被认为是一种异常):
经典模型,用于pre-Cortex芯片和当前的Cortex-A/R芯片。在其中,地址为0的内存包含多个异常处理程序:
Offset Handler
===============
00 Reset
04 Undefined Instruction
08 Supervisor Call (SVC)
0C Prefetch Abort
10 Data Abort
14 (Reserved)
18 Interrupt (IRQ)
1C Fast Interrupt (FIQ)
当异常发生时,处理器会从特定偏移量开始执行,因此通常该表包含到代码中进一步的完整处理程序的单指令分支。 典型的经典向量表如下所示:
00000000 LDR PC, =Reset
00000004 LDR PC, =Undef
00000008 LDR PC, =SVC
0000000C LDR PC, =PrefAbort
00000010 LDR PC, =DataAbort
00000014 NOP
00000018 LDR PC, =IRQ
0000001C LDR PC, =FIQ
运行时,向量表可以重定位到0xFFFF0000,通常作为紧密耦合的内存范围以实现最快的异常处理。然而,通常情况下上电复位会从0x00000000开始(但在一些芯片中可以通过处理器引脚设置为0xFFFF0000)。
新的微控制器型号用于Cortex-M系列芯片。在那里,0处的向量表实际上是一个向量(指针)表,而不是指令。第一个条目包含SP寄存器的启动值,第二个是复位向量。这允许直接使用C编写复位处理程序,因为处理器会设置堆栈。同样,该表可在运行时重定位。Cortex-M的典型向量表开始如下:
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
[...more vectors...]
请注意,在现代复杂芯片(例如OMAP3或Apple的A4)中,执行的第一段代码通常不是用户代码,而是芯片上的引导程序(Boot ROM)。它可能会检查各种条件来确定从哪里加载用户代码,是否加载用户代码(例如,它可能需要有效的数字签名)。在这种情况下,用户代码可能必须符合不同的启动规约。开机后,CPU将开始执行异常模式,第一个是重置。由于在此时的执行期间,CPU不知道寄存器的状态,因此重置必须以监管者模式运行。为了实现这一点,需要编写一小段代码(请参见末尾)。之后,可以通过将地址加载到PC来处理其他异常。
.globl _start
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
reset:
mrs r0,cpsr /* set the cpu to SVC32 mode */
bic r0,r0,#0x1f /* (superviser mode, M=10011) */
orr r0,r0,#0x13
msr cpsr,r0