2.5.4 异常的进入与退出
1.异常进入
(1)入栈。当处理器发生异常时,首先自动把8个寄存器(xPSR、PC、LR、R12、R3、R2、R1、R0)压入栈,处理器自动完成。在自动入栈的过程中,把寄存器写入栈的时间顺序并不是与写入空间相对应的,但系统会保证正确的寄存器被保存到正确的位置。假设入栈地址为N,内部入栈示意图如图2.9所示。

图2.9 内部入栈示意图
(2)取向量。当处理器发生异常时,内核将根据向量表找出正确的异常向量,然后在服务程序的入口处预取指。处理器将取指与取数据分别通过总线控制,使入栈与取指这两项工作能同时进行,以便快速进入中断。
(3)更新寄存器。入栈和取向量操作完成之后,在执行服务例程之前,还必须更新一系列寄存器。
(4)更新SP。在入栈后,堆栈指针(PSP或MSP)会更新到新的位置。在执行异常服务例程时,将由MSP负责对堆栈的访问。
(5)更新xPSR。更新IPSR位段(处于xPSR的最低部分)的值为新响应的异常编号。
(6)修改PC。在取向量完成后,PC将指向服务例程的入口地址。
(7)更新LR。在出入异常服务的时候,LR的值将得到重新的诠释,这种特殊的值被称为EXC_RETURN。在异常进入时,由系统计算并赋给LR,并在异常返回时使用它。
2.异常退出
异常服务程序最后一条指令是把程序连接存储器(LR)的值加载到PC中,该操作指示中断服务结束。在从异常返回时,处理器将执行下列操作之一。
(1)若激活异常的优先级比所有被压栈(等待处理)的异常的优先级都高,则处理器会末尾连锁到一个激活异常。(https://www.daowen.com)
(2)若没有激活异常,或者被压栈的异常的最高优先级比激活异常的最高优先级要高,则处理器返回到上一个被压栈的中断服务程序。
(3)若没有激活的中断或被压栈的异常,则处理器返回线程模式。
在启动了中断返回序列后,下述的处理就将进行。
(1)出栈。先前压入栈中的寄存器在这里恢复。内部的出栈顺序与入栈时的相对应,堆栈指针的值也改回先前的值。
(2)更新NVIC寄存器。伴随着异常的返回,它的活动位也被硬件清除。对于外部中断,倘若中断输入再次被置为有效,挂起位也将再次置位,新一次的中断响应序列也可随之再次开始。
(3)异常返回值。异常返回值EXC_RETURN存放在LR中,这是一个高28位全为1的值,只有[3∶0]的值有特殊含义,EXC_RETURN各位含义如表2.7所示。当异常服务例程把这个值送往PC时,就会启动处理器的中断返回序列。因为LR的值是由ARM Cortex-M3自动设置的,所以只要没有特殊需求,就不要改动它。
表2.7 EXC_RETURN各位含义

因此,上述表格中EXC_RETURN的值有3种情况。
(1)0xFFFF_FFF1:返回处理器模式。
(2)0xFFFF_FFF9:返回线程模式,并使用主堆栈。
(3)0xFFFF_FFFD:返回线程模式,并使用进程堆栈。