ARM的启动过程是什么?

68

众所周知,对于X86架构:按下电源按钮后,机器开始执行位于0xFFFFFFF0的代码,然后它开始执行BIOS中的代码以进行硬件初始化。在BIOS执行完毕后,它使用引导加载程序将操作系统映像加载到内存中。最后,操作系统代码开始运行。 那么,在ARM架构中,在用户按下电源按钮后,启动过程是什么样子的呢? 谢谢!


1
ARM处理器被广泛应用于许多不同的应用和板子中。具有该处理器的特定板子可以以任何方式自由唤醒该处理器。您有特定的硬件设备想法吗? - Chris H
嗨,克里斯,感谢您的评论。我将使用A8或A9开发板进行测试。从arm.com上了解到,A8的开发板是Beagle Board,A9的开发板是Panda Board。我的目的是进行Trust Zone测试。如果您能给我一些建议,我将不胜感激。我应该购买哪个开发板(个人更喜欢A9,因为它更新)?A9 / A8的启动顺序是什么?启动过程是否涉及Trust Zone操作? - Fengwei Zhang
3个回答

75

目前,在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)。它可能会检查各种条件来确定从哪里加载用户代码,是否加载用户代码(例如,它可能需要有效的数字签名)。在这种情况下,用户代码可能必须符合不同的启动规约。

7
这是一个好的、全面的答案,但有一个错误的陈述:在支持“高向量”(从实质上讲,从ARM11开始)的ARM处理器上,上电复位(以及随后的异常,直到被软件更改)使用位于0x00000000或0xffff0000的向量表,具体取决于配置输入信号,因此在不同的SoC之间可能会有所不同。例如,请参见http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/Bgbciiaf.html - unixsmurf
1
@unixsmurf:你说得对,我忘记了。我会修改我的答案,谢谢! - Igor Skochinsky

3

开机后,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

3
在按下电源按钮后,对于ARM架构,操作系统代码开始运行。对于类似PC的ARM平台(平板电脑、手机等),ARM CPU将从0x0或0xffff0000中获取指令(对于Cortex-M而言,它是数据而不是指令)。典型的ARM SOC具有一些引导ROM使用这种机制。对于最终用户,您需要查阅手册以确定如何使您的代码运行。也就是说,许多ARM SOC内置了BIOS使用该向量,但您需要使用其他方法来使您的代码运行。
通常,ARM SOC支持多个引导设备。设备是通过一些FUSE(由制造工具设置)或采样引脚确定的。这些引脚在运行系统中将成为CPU输出,但已被拉高/拉低以配置引导设备。每个引导设备都有其独特的细节;ROM很简单,但NAND闪存、SPI闪存、MMC等需要一些配置详细信息。这些信息通常也由芯片上的FUSE和/或采样引脚提供。设备的一小部分可以被读取以进一步配置设备。
对于一个深度嵌入式的ARM芯片,它可能只能从板载闪存启动,这个过程要简单得多;但根据问题的背景,我认为你是指更先进的ARM CPU。更先进的ARM系统有一个引导加载程序。这是因为ROM加载器加载的代码量通常是有限的和/或受限制的。此外,设置SDRAM通常是复杂的,引导加载程序可能被设计为从内部静态RAM运行,从而配置SDRAM。
参见:为什么我们需要引导加载程序 运行操作系统有其独特的问题。对于ARM Linux来说,它是ATAGS,现在是devicetree。人们可以编写自己的引导加载程序或使用许多开源项目之一,其中u-boot是最常见的。U-boot支持vxWorks、Linux、NetBSD、Plan9、OSE、QNX、Integrity和OpenRTOS以及二进制图像。
许多原始的ARM Linux设备支持Linux的直接启动,而无需引导加载程序。然而,在主流中,Linux不支持除了一些非常老的ARM SOC/核心之外的这种方式。

列出了一个Linux引导加载程序的清单,详见相关问题 或者 CorebootUbootWikipedia的比较Barebox是一个鲜为人知但结构良好且现代化的ARM引导加载程序。 RedBoot也在一些ARM系统中使用;内核树支持RedBoot分区。 - artless noise

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接