ARM的异常处理机制

异常种类

ARM共有如下7种异常模式:

  • 复位(RESET):当处理器复位引脚有效时,系统产生复位异常中断。复位异常中断通常在系统加电和系统复位时发生,直接跳转到复位中断向量处执行称为软复位。
  • 未定义的指令(UDEF):当ARM处理器或者是系统中的协处理器认为当前指令未定义时,会产生未定义的指令异常中断。
  • 软件中断(SWI):这是一个由SWI指令触发的中断。
  • 指令预取终止(PrefechAbort):如果处理器预取的指令的地址不存在,或者该地址不允许当前指令访问,就会产生指令预取终止异常中断。
  • 数据访问终止(DATAABORT):如果数据访问指令的目标地址不存在,或者该地址不允许当前指令访问就会产生数据访问终止异常中断。
  • 外部中断请求(IRQ):当处理器的外部中断请求引脚有效,而且CPSR的寄存器的I控制位被清除时,就会产生外部中断请求异常中断。
  • 快速中断请求(FIQ):当处理器的外部快速中断请求引脚有效,并且CPSR的F控制位被清除时,就会产生外部中断请求异常中断。

异常中断向量表

        当异常发生时,CPU会主动将PC赋值为低地址或高地址,该地址处有一条指令用于处理该类型异常,我们将存储这些指令的地方称为异常中断向量表。ARM规定每个向量占用4字节空间(通常会放一个跳转指令或一个向PC寄存器赋值的数据访问指令。通过这两种指令,将程序跳转到相应的异常中断处理程序处执行),共32个字节。

        异常发生时,ARM会将处理其切换到对应的模式来处理异常。此外,不同种类的异常有可能会同时发生,此时ARM会按照一定的优先级策略来处理这些异常。

        上述相关的信息见下表所示。

ARM的异常处理机制_第1张图片 

        图中未定义指令与软件中断异常的优先级都是6,这其实没有关系,因为这两类异常不可能同时发生。 

异常处理

        要实际处理上述七种异常,需要软硬件的协同,这里记录的是硬件对异常的处理步骤,并不涉及软件部分。在实际编程过程中,只有首先明白硬件对异常处理逻辑后,才能正确的进行软件处理。

        硬件对异常的处理分为两部分:发生异常时的处理(进入部分)和异常结束处理(离开部分),而且无论是哪种异常,硬件对它们的处理过程大致相同,只有个别的细节不同,下面首先讨论共性,然后再具体类型具体说明。

进入部分

        当异常发生时,处理器大致按照如下的流程进行处理:

  1. 将下一条指令的地址保存在对应模式的LR寄存器中,异常处理退出时需要;
  2. 保存处理器当前状态,即将CPSR保存到相应的模式的SPSR中;
  3. 修改CPSR中的相应位,包括设置模式位和中断屏蔽位;
  4. 将PC设置成对应的异常中断向量的地址。

        上述过程用伪代码表示为:

R14_ = return link
SPSR_ = CPSR
CPSR[4:0] = exception mode number
CPSR[5] = 0 //异常处理时处理器一定是工作在ARM状态的
if  == Reset or FIQ then
    CPSR[6] = 1 //有条件的屏蔽FIQ中断
CPSR[7] = 1 // 总是屏蔽IRQ中断
PC = exception vector address

复位异常

R14_svc = UNPREDICTABLE value
SPSR_svc = UNPREDICTABLE value
CPSR[4:0] = 0b10011 // 复位异常在特权模式下运行
CPSR[5] = 0
CPSR[6] = 1 // 关闭FIR和IRQ中断
CPSR[7] = 1
if high vectors configured then
    PC = 0xFFFF0000
else
    PC = 0x00000000

        注意:复位异常的处理是不需要返回的,所以其R14和SPSR的值是未定义的。

未定义指令异常

R14_und = PC - 4
SPSR_und = CPSR
CPSR[4:0] = 0b11011 // 处理器进入未定义指令模式
CPSR[5] = 0
CPSR[7] = 1 // 只禁止IRQ,FIQ不变
if high vectors configured then
    PC = 0xFFFF0004
else
    PC = 0x00000004

SWI软件中断

R14_svc = PC - 4
SPSR_svc = CPSR
CPSR[4:0] = 0b10011 // 处理器进入特权模式
CPSR[5] = 0
CPSR[7] = 1 // 只禁止IRQ,FIQ不变
if high vectors configured then
    PC = 0xFFFF0008
else
    PC = 0x00000008

指令预取中止异常中断

R14_abt = PC - 4
SPSR_abt = CPSR
CPSR[4:0] = 0b10111 // 处理器进入中止模式
CPSR[5] = 0
CPSR[7] = 1 // 只禁止IRQ,FIQ不变
if high vectors configured then
    PC = 0xFFFF000C
else
    PC = 0x0000000C

数据访问中止异常中断

R14_abt = PC - 4
SPSR_abt = CPSR
CPSR[4:0] = 0b10111 // 处理器进入中止模式
CPSR[5] = 0
CPSR[7] = 1 // 只禁止IRQ,FIQ不变
if high vectors configured then
    PC = 0xFFFF0010
else
    PC = 0x00000010

IRQ异常

R14_irq = PC - 4
SPSR_irq = CPSR
CPSR[4:0] = 0b10010 // 处理器进入IRQ模式
CPSR[5] = 0
CPSR[7] = 1 // 只禁止IRQ,FIQ不变
if high vectors configured then
    PC = 0xFFFF0018
else
    PC = 0x00000018

FIQ异常

R14_fiq = PC - 4
SPSR_fiq = CPSR
CPSR[4:0] = 0b10001 // 处理器进入FIQ模式
CPSR[5] = 0
CPSR[6] = 1 // 禁止FIQ、IRQ
CPSR[7] = 1
if high vectors configured then
    PC = 0xFFFF0018
else
    PC = 0x00000018

离开部分

        当异常处理结束后,需要执行如下两步操作才能返回到被异常中断的地方继续执行:

  1. 恢复处理器状态,即把SPSR_mode的内容复制到CPSR中;
  2. 清除相应的中断禁用标记;
  3. 根据lr_mode的值恢复PC的值,从而从被中断的地方继续执行。

SWI软件中断

未定义指令异常中断

        由于这两种异常是在指令执行过程中发生的,此时PC指向当前指令后面的第二条指令(对于ARM状态为当前指令地址加8,对于THUMB状态为当前指令地址加4),因为在中断发生时,处理器将PC-4的结果保存到了lr_mode中,所以在返回时,只需要直接将lr_mode的值复制到PC中即可。

IRQ和FIR异常中断

        因为对IRQ和FIQ的处理是在一条指令结束时发生的,此时PC的值指向当前指令后面的第三条指令(对于ARM状态为当前指令地址加12,对于THUMB状态为当前指令地址加6),因为在中断发生时,处理器将PC-4的结果保存到了lr_mode中,所以在返回时,需要将lr_mode-4的结果赋值给PC。

指令预取中止异常

        指令预取中止异常虽然在指令的取址阶段就发生了,但是真正对该异常的处理是在执行该指令时发生的,此时PC的值指向当前指令后面的第二条指令(对于ARM状态为当前指令地址加8,对于THUMB状态为当前指令地址加4)。该异常的处理结束返回时,应该返回到产生该异常的指令地址处重新执行该指令,而不是返回到产生该异常的指令的下一条指令处执行。因为在中断发生时,处理器将PC-4的结果保存到了lr_mode中,所以在返回时,需要将lr_mode-4的结果赋值给PC。

数据访问中止异常

        发生该异常时,PC指向当前指令后面的第三条指令(对于ARM状态为当前指令地址加12,对于THUMB状态为当前指令地址加6)。同样的,对该异常的处理返回时,应该返回到产生该异常的指令地址处重新执行该指令。因为在中断发生时,处理器将PC-4的结果保存到了lr_mode中,所以在返回时,需要将lr_mode-8的结果赋值给PC。

你可能感兴趣的:(ARM体系结构,ARM,异常)