目录
一、异常的概念
1、什么是异常?
2、处理异常时,处理器要考虑哪些问题?
二、ARM异常源
1、异常源的分类
2、异常模式
三、ARM异常响应
1、CPSR寄存器内容备份(自动执行)
2、修改CPSR的值(自动执行)
(1) 修改模式
(2) 修改中断禁止位
(3) 修改状态位
3、保存返回地址(自动执行)
4、跳转到异常向量表(自动执行)
5、执行异常处理程序(自己编写)
6、异常处理完毕的返回动作(自己编写)
(1) 恢复之前的状态
(2) 回到之前中断的下一个位置
四、完整流程示意图
一、异常的概念
1、什么是异常?
异常指的是处理器在正常执行程序的过程中遇到的不正常事件。异常发生时,处理器会暂停当前程序转而去处理异常事件,异常事件处理完成之后再回到之前被打断的地方继续执行程序。
比如,老师在上课,这时突然有人敲门,老师就会暂停讲课去开门,事情处理完毕以后,老师继续讲课。这个过程中,老师上课 = 正常执行程序,有人敲门 = 异常事件。
2、处理异常时,处理器要考虑哪些问题?
不同处理器对异常的处理大体相似,但是不同处理器在具体实现上可能会有所不同。处理器在处理异常的时候,需要考虑的问题大致如下:
- 异常源的判断。
- 并非有事件发生,处理器就会去处理,比如老师上课的时候,学生咳嗽一声,这种情况就不算异常。
- 异常的响应
- 跳转前的准备工作。比如保存跳转前的地址、进入到相应的异常模式
- 异常处理工作。这里就是去调用异常处理程序了
- 异常处理结束的善后工作。比如异常如何返回
二、ARM异常源
所谓异常源,就是导致异常产生的事件。异常源和工作模式存在一定的关联,异常源出现的时候,处理器会进入相应的工作模式,然后去执行相应的功能。
1、异常源的分类
异常源大致有如下七种,这里需要和工作模式区分开,异常源是终止CPU正常运行的原因,工作模式则是CPU当前的工作状态。
异常源类型 (优先级由高到低) | 异常源说明 |
Reset | 复位电平有效 |
Data Abort | 数据终止。比如地址不允许被访问 |
FIQ | 快速中断请求引脚有效,一般是外部硬件产生的,优先级较高。 |
IRQ | 外部中断请求引脚有效,一般是外部硬件产生的,优先级较低 |
Prefetch Abort | 指令预取终止。比如对应地址不存在指令 |
Software Interrupt | 软中断,一般是程序产生的 |
Undefined Instruction | 遇到不能处理的指令。比如CPU拿到指令以后无法解析 |
2、异常模式
在ARM的基本工作模式中有5个属于异常模式,即ARM遇到某种异常后会切换成对应的异常模式,不同的异常源可能会进入到同一种工作模式。异常源和工作模式之间的关系如下:
异常源 | 异常模式 |
FIQ | FIQ |
IRQ | IRQ |
Reset / SWI | SVC |
Data Abort / Prefetch Abort | Abort |
Undefined Instruction | Undef |
三、ARM异常响应
当异常发生的时候,CPU会停下手里的任务,跳转去执行异常处理程序,但是在跳转之前,需要做一些准备工作,比如保存中断之前的工作模式和运算状态、中断位置的下一条指令的地址。
1、CPSR寄存器内容备份(自动执行)
拷贝CPSR寄存器中的内容到对应异常模式下的SPSR_<mode>寄存器。下面是不同工作模式所使用的寄存器。
一开始是处在User模式下,现在IRQ异常产生了,CPU会进入到 IRQ 模式,但是IRQ也要使用CPSR寄存器,所以只能将User模式下的寄存器数据暂存到 SPSR_irq 中。
2、修改CPSR的值(自动执行)
现在CPSR归IRQ模式使用了,主要完成的工作有如下三个:
- 修改模式位为IRQ。
- 修改中断禁止位,禁止相应的中断。
- 修改状态位进入ARM状态。
(1) 修改模式
拿到CPSR寄存器的第一件事当然就是改成相应的异常模式了。
(2) 修改中断禁止位
这里禁止相应中断的目的是,CPU在处理当前中断的时候,不希望被其他同优先级的中断打扰(除非中断优先级更高)。这里就分为了两种情况:
如果发生的是IRQ异常,其他IRQ中断发生时,CPU不予理会;FIQ中断发生时,先停下手里的中断处理任务,先去处理FIQ中断,处理完FIQ中断再回来处理IRQ中断。
如果发生的是FIQ异常,那么该异常的处理过程无法被打断,因为不存在更高优先级的中断,同优先级的FIQ中断已经被禁用了。
(3) 修改状态位
大多数情况下使用的状态位都是ARM状态,在处理异常的时候,这一步可以直接省略;如果当前处理器的状态是Thumb状态,这时就需要修改状态位为ARM状态。
3、保存返回地址(自动执行)
后面异常处理完毕以后,处理器要回到中断的下一个位置继续运行程序,这里我们就需要事先保存中断位置的下一条指令的地址到 LR_<mode>。
每一种工作模式有着自己的 LR寄存器,如果发生的是IRQ异常,那么就会保存到 r14_irq 寄存器
问:什么不保存到User模式下的 r14 寄存器?
答:最后返回的时候,是由IRQ模式切换到User模式,IRQ模式下是无法使用 User模式下的r14寄存器的。
4、跳转到异常向量表(自动执行)
准备工作都做好了,为什么不直接跳转到异常处理程序呢?这是当初设计ARM的工程师们给我们留的一个接口,因为他们也不知道实际异常处理程序放在哪,也不能直接写死,不同异常的对应的处理程序是不一样的,所以先跳转到异常向量表。
异常向量表在内存中占据32个字节,每个异常源都分配了4个字节的存储空间,注意,这4个字节不是用来存放异常处理程序的,而是存放跳转指令来直接跳转到异常处理程序的入口位置。
注:ARM的异常向量表的基地址默认在0x00地址,但可以通过配置协处理器来修改其地址
5、执行异常处理程序(自己编写)
6、异常处理完毕的返回动作(自己编写)
(1) 恢复之前的状态
SPSR_<mode>备份了中断之前的工作模式和运行状态,所以需要将SPSR_<mode>的值复制给CPSR使处理器恢复之前的状态。
(2) 回到之前中断的下一个位置
在跳转之前,LR__<mode>保存了中断处的下一条指令的地址,所以需要将LR_<mode>的值复制给PC使程序跳转回被打断的地址继续执行。