关于处理器异常
在执行正常指令流的程序时,程序计数器再其地址空间连续增加,还可以跳转到附近标签、分支或者子程序处。
当处理器异常出现时正常执行流程被转移,使处理器处理来自内部或者外部源产生的异常事件。例如下列事件:
- 产生外部中断;
- 处理器试图执行未定义指令;
- 访问操作系统的特权功能;
在处理异常之前需要保存处理器当前状态,这样才能在执行完异常后可以恢复执行当前程序。ARM处理器的7种类型的异常如下表:
异常 | 解释 |
---|---|
复位异常 | 当处理器复位引脚电平有效时,这种异常仅期望出现在开机或者重启时,软件复位可以通过跳转到复位向量(0x0000)处来实现。 |
未定义指令异常 | 当处理器或任何协处理器都不能识别当前指令时发生。 |
软中断异常(swi) | 这是用户定义的同步中断指令。它允许出现运行在用户模式下,需要请求在超级模式下运行的特权操作,如RTOS(实时操作系统)的函数。 |
指令预取中止异常 | 当处理器试图执行一条不能获得的指令,因为地址是非法的。 |
数据访问异常 | 当数据传送指令试图读取或者存储数据在非法地址处。 |
中断异常(IRQ) | 当处理器外部中断请求引脚电平有效(低电平)和CPSR寄存器的中断屏蔽位清除时。 |
快速中断异常(FIQ) | 当处理器外部快速中断请求引脚电平有效(低电平)和CPSR寄存器的快速中断屏蔽位清除时。 |
异常向量表
处理器异常是通过向量表来控制的,这个向量表是一个保留的32字节区域,通常在内存映射底部。每种异常只有一个字(4个字节)的空间大小,剩下的一个字空间保留。当异常出现时处理器自动跳转到相应向量表地址处。由于向量表空间不能装下所有异常处理代码,所以向量表中包含的是跳转指令或者装载PC寄存器的指令用于跳转到相应异常处理函数处继续执行。异常向量表如下:
向量地址 | 异常类型 | 异常模式 | 优先级 (1=high, 6=low) |
---|---|---|---|
0x0 | Reset | Supervisor (SVC) | 1 |
0x4 | Undefined | Instruction Undef | 6 |
0x8 | Software Interrupt (SWI) | Supervisor (SVC) | 6 |
0xC | Prefetch | Abort Abort | 5 |
0x10 | Data Abort | Abort | 2 |
0x14 | Reserved | Not applicable | Not applicable |
0x18 | Interrupt (IRQ) | Interrupt (IRQ) | 4 |
0x1C | Fast Interrupt (FIQ) | Fast Interrupt (FIQ) | 3 |
处理器进入异常
当一个异常出现时,处理器要做以下几个步骤:
- 复制
Current Program Status Register
(CPSR)寄存器的值到Saved Program Status Register
(SPSR)寄存器,以保存当前处理器模式、中断屏蔽位和条件标志位。 -
改变相应的CPSR模式位,以便:
- 改变相应模式和映射此模式下的相应寄存器组
- 禁止中断,IRQ在任何异常类型下都要禁止,FIQ在FIQ异常和复位异常下要禁止
- 将返回地址保存到
lr
寄存器中。 - 设置程序计数器为此异常向量表的地址,强制跳转到相应异常向量处。
处理器从异常返回
处理器从异常处理返回的方式依赖于这个异常处理函数是否使用了栈操作。这两种方式下必须包括:
- 根据
SPSR
寄存器的值恢复CPSR
寄存器的值 - 根据
lr
寄存器的值恢复程序计数器的值
简单的返回方式不需要从堆栈中恢复目标模式的寄存器值,异常处理函数通过这两个步操来保证数据处理指令的运行:
- 设置 S 标志位
- 将程序计数器作为目标寄存器
注:复位异常不需要返回因为复位后应该直接从主函数处开始执行。
如果异常处理函数使用了堆栈来存储寄存器的值这些值必须被保护起来,可以使用一个多项加载的指令带上^
限定符来返回。例如,异常处理函数可以使用一条指令返回:
LDMFD sp!,{r0-r12,pc}^
^
限定符指明CPSR
寄存器从SPSR
寄存器中恢复,但必须在特权模式下使用。
翻译自《ARM Developer Suite》第五章