ARM基础学习-异常中断处理

中断类型

当异常中断发生的时候,系统执行完当前指令后,将跳转到相应的异常中断处理程序,当处理程序执行完毕后,程序返回到发生中断的指令的下一条指令处执行;在进入异常中断处理程序时,要保存被中断的执行现场,在异常中断处理程序退出时,要恢复被中断的程序的执行现场;

异常中断类型:
这里写图片描述

1.复位异常发生后,进入到管理模式(svc) 下。
2.软中断发生后, 进入到 管理模式(svc) 下。
3.未定义指令异常发生后, 进入到 未定义指令中止模式(und)下。
4.指令预取中止异常发生后, 进入到 数据访问中止模式(abt)下;
5.数据访问中止异常发生后, 进入到 数据访问中止模式(abt) 下:
6.外部中断发生后, 进入到 外部中断模式(irq)下;
7.快速中断发生后, 进入到 快速中断模式(fiq)下;

中断向量表和中断优先级

中断向量表指定了各异常中断及其处理程序的对应关系;通常存放在存储地址的低端;每个中断对应的中断向量表中的4个字节存放了一个跳转指令或者一个向PC寄存器赋值的数据访问指令,通过跳转指令,程序跳转到相应的异常处理处理程序处执行;

几个异常同时发生的时候需要设置优先级来处理这些异常:

这里写图片描述

ARM对异常中断的响应过程

(1)ARM处理器对异常中断的响应过程

  1. 保存处理器当前状态、中断屏蔽位以及各条件标志位。这是通过将当前程序状态寄存器CPSR的内容保存到将要执行的异常中断对应的SPSR寄存器中实现的。各异常中断有自己的物理SPSR寄存器。
  2. 设置当前程序状态寄存器CPSR中相应的位。包括设置CPSR中的位,使处理器进入相应的执行模式;设置CPSR中的位,禁IRQ中断,当进入FIQ模式时,禁止FIQ中断。
  3. 将寄存器Ir_mode(R14)设置成返回地址。
  4. 将程序计数器值(PC),设置成该异常中断的中断向量地址,从而跳转到相应异常中断处理程序处执行。

(2)从异常中断处理程序中返回

  1. 恢复被中断程序的处理器状态,即将SPSR_mode寄存器内容复制到CPSR中。
  2. 返回到发生异常中断的指令下一条指令处执行,即将Ir_mode寄存器的内容复制到程序计数器PC中。

(3)响应复位异常中断

如下情况会导致复位:

  1. 上电复位:在上电后,复位使内部达到预定的状态,特别是程序跳到初始入口;
  2. 复位引脚上的复位脉冲:这是由外部其他控制信号引起的;
  3. 对系统电源检测发现过压或欠压;
  4. 时钟异常复位。

当发生复位 时,处理器硬件响应中断,自动执行如下操作:

  1. 强制进入管理模式;
  2. 强制进入ARM状态;
  3. 禁止IRQ中断和FIQ中断;
  4. 跳转到绝对地址PC=0x00000000处执行;

(4)未定义指令异常

如下情况会导致:

  1. 遇到一条无法执行的指令,此指令没有定义;
  2. 执行一条对协处理器的操作指令,在正常情况下,协处理器应该应答,但协处理器没有应答。

处理器响应中断后,硬件自动执行下列操作 :

  1. 把程序状态寄存器CPSR拷贝给SPSR_und;
  2. 强制进入未定义模式;
  3. 强制进入到ARM模式;
  4. 禁止IRQ中断
  5. 把下一条指令的地址拷贝给LR;
  6. 跳转到绝对地址PC=0x00000004处执行;

关于从异常中断处理程序的返回:

未定义指令异常中断是由当前执行的指令自身产生的,当产生中断时,程序计数器PC的值还未更新,它指向当前指令后面的第二条指令(对于ARM指令,它指向当前指令地址加8字节的位置;对于Thumb指令,它指向当前指令地址加4字节的位置)。当未定义指令异常中断发生时,处理器自动将值(pc-4)保存到lr_und中,此时(pc-4)指向当前指令的下一条指令,所以从未定义指令异常中断返回可以通过如下指令来实现:

MOV  PC,LR

当异常中断处理程序中使用了数据栈时,可以使用下面的指令在进入异常中断处理程序时保存被中断程序的执行现场,在退出异常中断处理程序时恢复被中断程序的执行现场。异常中断程序中使用的数据栈由用户提供。

STMFD   sp! , {reglist,lr}
....
LDMFD   sp! , {reglist,pc}^

reglist时异常中断处理程序中使用的寄存器列表。标识符^指示将SPSR_mode寄存器的内容复制到CPSR中,该指令只能在特权模式下使用。

(5)软件中断异常

是由指令SWI引起的,程序在执行这一指令后,进入异常中断。处理器响应中断后,硬件自动执行下列操作 :

  1. 把程序状态寄存器CPSR拷贝给SPSR_svc;
  2. 强制进入管理模式;
  3. 强制进入到ARM状态;
  4. 禁止IRQ中断。
  5. 把下一条指令的地址拷贝给LR;
  6. 跳转到绝对地址PC=0x00000008处执行;

关于从异常中断处理程序的返回:

软件中断异常是由当前执行的指令自身产生的,当产生中断时,程序计数器PC的值还未更新,它指向当前指令后面的第二条指令(对于ARM指令,它指向当前指令地址加8字节的位置;对于Thumb指令,它指向当前指令地址加4字节的位置)。当软件中断发生时,处理器自动将值(pc-4)保存到lr_siw中,此时(pc-4)指向当前指令的下一条指令,所以从软件中断返回可以通过如下指令来实现:

MOV PC,LR

当异常中断处理程序中使用了数据栈时,可以使用下面的指令在进入异常中断处理程序时保存被中断程序的执行现场,在退出异常中断处理程序时恢复被中断程序的执行现场。异常中断程序中使用的数据栈由用户提供。

STMFD   sp! , {reglist,lr}
....
LDMFD   sp! , {reglist,pc}^

reglist时异常中断处理程序中使用的寄存器列表。标识符^指示将SPSR_mode寄存器的内容复制到CPSR中,该指令只能在特权模式下使用。

(5)预取指中止异常

由程序存储器引起的中止异常叫做预取指中止异常;
由数据存储器引起的中止异常叫做数据中止异常。

由于ARM的指令是3级流水线结构,读取指令周期是提前进行的,因此把读取指令的过程一般称预取指。在指令预取时,如果目标地址是非法的,该指令被标记成有问题的指令,这时,流水线上该指令之前的指令继续执行。有两种可能如下:

  1. 当执行这条指令前程序发生跳转,则这条无效指令不引起异常中断;
  2. 当执行到这条指令时,处理器会发生预取指中止异常,引起中断。

处理器响应中断后,硬件自动执行下列操作 :

  1. 把程序状态寄存器CPSR拷贝给SPSR_abt;
  2. 强制进入中止异常模式;
  3. 强制进入到ARM状态;
  4. 禁止IRQ中断。
  5. 把中断时PC的地址拷贝给LR;
  6. 跳转到绝对地址PC=0x0000000C处执行;

关于从异常中断处理程序的返回:

在指令预取时,如果目标地址是非法的,该指令被标记成有问题的指令,这时,流水线上该指令之前的指令继续执行,当执行到该被标记成有问题的指令时,处理器产生指令预取中止异常中断。发生指令预取异常中断时,程序要返回到该有问题的指令处,重新读取并执行该指令,因此指令预取中止异常中断应该返回到产生该指令预取中止异常中断的指令处,而不是当前指令的下一条指令。

指令预取异常是由当前执行的指令自身产生的,当产生中断时,程序计数器PC的值还未更新,它指向当前指令后面的第二条指令(对于ARM指令,它指向当前指令地址加8字节的位置;对于Thumb指令,它指向当前指令地址加4字节的位置)。当指令预取中止异常中断发生时,处理器自动将值(pc-4)保存到lr_abt中,此时(pc-4)指向当前指令的下一条指令,所以从软件中断返回可以通过如下指令来实现:

SUBS PC,LR,#4

当异常中断处理程序中使用了数据栈时,可以使用下面的指令在进入异常中断处理程序时保存被中断程序的执行现场,在退出异常中断处理程序时恢复被中断程序的执行现场。异常中断程序中使用的数据栈由用户提供。

SUBS LR,LR,#4
STMFD sp! , {reglist,lr}
….
LDMFD sp! , {reglist,pc}^

reglist时异常中断处理程序中使用的寄存器列表。标识符^指示将SPSR_mode寄存器的内容复制到CPSR中,该指令只能在特权模式下使用。

(6) 数据中止异常

ARM处理器访问数据存储器时,在读取数据的同时数据存储器发出了中止信号,引起数据中止异常。如果数据访问指令的目标地址不存在,或者该地址不允许当前指令访问,处理器产生数据访问中止异常中断;
处理器响应中断后,硬件自动执行下列操作 :

  1. 把程序状态寄存器CPSR拷贝给SPSR_abt;
  2. 强制进入中止异常模式;
  3. 强制进入到ARM状态;
  4. 禁止IRQ中断;
  5. 把中断时的PC的地址拷贝给LR;
  6. 跳转到绝对地址PC=0x00000010处执行;

关于从异常中断处理程序的返回:

发生数据访问异常中断时,程序要返回到该有问题的指令处,重新访问该数据,因此数据访问异常中断应该返回到产生该数据访问中止异常中断的指令处,而不是当前指令的下一条指令。

数据访问异常中断由当前执行的指令在ALU里执行时产生,当数据访问异常中断发生时,程序计数器pc的值已经更新,它指向当前指令后面第3条指令(对于ARM指令,它指向当前指令地址加12字节的位置;对于Thumb指令,它指向当前指令地址加6字节的位置)。此时处理器将值(pc-4)保存到lr_abt中,它指向当前指令后面第2条指令,所以返回操作可以通过下面指令实现:

SUBS PC, LR, #8

当异常中断处理程序中使用了数据栈时,可以使用下面的指令在进入异常中断处理程序时保存被中断程序的执行现场,在退出异常中断处理程序时恢复被中断程序的执行现场。异常中断程序中使用的数据栈由用户提供。

SUBS LR,LR,#8
STMFD   sp! , {reglist,lr}
....
LDMFD   sp! , {reglist,pc}^

reglist时异常中断处理程序中使用的寄存器列表。标识符^指示将SPSR_mode寄存器的内容复制到CPSR中,该指令只能在特权模式下使用。

(7)中断请求(IRQ)异常

例如:定时器中断、串行口通讯中断、外部信号中断和A/D处理中断等。IRQ中断是可屏蔽的。在状态寄存器中的I位就是IRQ的屏蔽位。当I=1时。则屏蔽IRQ中断,当I=0时,则允许中断。处理器复位后置I为1,关闭中断。处理器响应中断后,硬件自动执行下列操作 :

  1. 把程序状态寄存器CPSR拷贝给SPSR_irq;
  2. 强制进入IRQ异常模式;
  3. 强制进入到ARM状态;
  4. 禁止IRQ中断;
  5. 把中断时的PC的地址值拷贝给LR;
  6. 跳转到绝对地址PC=0x00000018处执行;

关于从异常中断处理程序的返回:

通常处理器执行完当前指令后,查询IRQ中断引脚,并查看系统是否允许IRQ中断,如果某个中断引脚有效,并且系统允许该中断产生,处理器将产生IRQ异常中断,当IRQ异常中断产生时,程序计数器pc的值已经更新,它指向当前指令后面第3条指令(对于ARM指令,它指向当前指令地址加12字节的位置;对于Thumb指令,它指向当前指令地址加6字节的位置),当IRQ异常中断产生时,处理器将值(pc-4)保存到IRQ异常模式下的寄存器lr_irq中,它指向当前指令之后的第2条指令,因此正确返回地址可以通过下面指令算出:

SUBS   PC,LR,#4 

当异常中断处理程序中使用了数据栈时,可以使用下面的指令在进入异常中断处理程序时保存被中断程序的执行现场,在退出异常中断处理程序时恢复被中断程序的执行现场。异常中断程序中使用的数据栈由用户提供。

SUBS LR, LR, #4
STMFD   sp! , {reglist,lr}
 ....
LDMFD   sp! , {reglist,pc}^

reglist时异常中断处理程序中使用的寄存器列表。标识符^指示将SPSR_mode寄存器的内容复制到CPSR中,该指令只能在特权模式下使用。

注:为什么PC会指向当前执行指令的后12个字节?

当前指令执行时(此时PC指向当前指令后面的第2条指令),如果发生IRQ中断,ARM检测到IRQ中断后,取指和执行单元都不会改变,只有译码单元会改变,译码单元改为开始译码中断指令。执行完当前指令后,PC值加4个字节(此时PC指向刚刚那条指令后面的第3条指令),译码单元将译完的中断指令送到执行单元,执行单元执行中断指令,保存PC-4(此时PC指向当前指令后面的第2条指令)的值到LR_irq,同时跳转到IRQ中断向量处。(详细可看ARM流水线机制)

(8)快速中断(FIQ)请求异常。

FIQ快速中断是可屏蔽的。在状态寄存器中的F位就是FIQ的屏蔽位。当F=1时。则屏蔽FIQ中断,当F=0时,则允许中断。处理器复位后置F为1,关闭中断。处理器响应中断后,硬件自动执行下列操作:
1. 把程序状态寄存器CPSR拷贝给SPSR_fiq;
2. 强制进入FIQ异常模式;
3. 强制进入到ARM状态;
4. 禁止FIQ中断;
5. 把中断时的PC的地址值拷贝给LR;
6. 跳转到绝对地址PC=0x0000001C处执行;

关于从异常中断处理程序的返回:

通常处理器执行完当前指令后,查询FIQ中断引脚,并查看系统是否允许FIQ中断,如果某个中断引脚有效,并且系统允许该中断产生,处理器将产生FIQ异常中断,当FIQ异常中断产生时,程序计数器pc的值已经更新,它指向当前指令后面第3条指令(对于ARM指令,它指向当前指令地址加12字节的位置;对于Thumb指令,它指向当前指令地址加6字节的位置),当FIQ异常中断产生时,处理器将值(pc-4)保存到IRQ异常模式下的寄存器lr_fiq中,它指向当前指令之后的第2条指令,因此正确返回地址可以通过下面指令算出:

SUBS   PC,LR,#4 

当异常中断处理程序中使用了数据栈时,可以使用下面的指令在进入异常中断处理程序时保存被中断程序的执行现场,在退出异常中断处理程序时恢复被中断程序的执行现场。异常中断程序中使用的数据栈由用户提供。

SUBS LR, LR, #4
STMFD   sp! , {reglist,lr}
....
LDMFD   sp! , {reglist,pc}^

reglist时异常中断处理程序中使用的寄存器列表。标识符^指示将SPSR_mode寄存器的内容复制到CPSR中,该指令只能在特权模式下使用。

FIQ和IRQ补充

FIQ和IRQ都是用于外部设备向CPU请求中断服务,这两个异常中断的引脚都是低电平有效,都可以通过CPSR的I控制位来设置是否屏蔽;

FIQ比IRQ的异常中断优先级高,所以FIQ通常用于对于相应时间要求比较苛刻的任务,FIQ异常中断向量为0X1C,位于中断向量表的最后,这样FIQ异常中断程序可以字节放在地址0X1C后面,这样节省了中断向量表中的跳转指令;

当系统存在cache时,可以把FIQ异常中断向量和处理程序放在一起锁定在cache中,从而大大提高相应时间,同时FIQ异常模式有额外的5个寄存器,可以有效的提高执行速度;

对于中断处理程序重入和不可重入

不可以重入的中断程序,在函数前用关键字__irq声明;不可重入的中断处理函数里会做如下操作:
1. 保存APCS规定的被破坏的寄存器;
2. 保存其他中断处理程序用到的寄存器;
3. 同时将(LR - 4)赋予程序计数器PC实现中断处理程序的返回,并且恢复CPSR寄存器的内容;

缺省情况下ARM 中断是不可重入的,因为一旦进入异常响应状态,ARM 自动关闭中断使能。如果在异常处理过程中简单地打开中断使能而发生中断嵌套,显然新的异常处理将破坏原来的中断现场而导致出错。但有时候中断的可重入又是需要的,对应可重入异常中断处理程序需要做如下特别操作:

  1. 将返回地址保存到IRQ的数据栈中;
  2. 保存工作寄存器和SPSR_irq;
  3. 清除中断标志位;
  4. 将处理器切换到系统模式,重新使能中断;
  5. 保存用户模式的LR寄存器和被调用者不保存的寄存器;
  6. 调用C语言的IRQ/FIQ异常中断处理程序;
  7. 当C语言的IRQ/FIQ异常中断处理程序返回后,恢复用户模式的寄存器,并禁止中断;
  8. 切换到IRQ模式,禁止中断;
  9. 恢复工作寄存器和寄存器LR_irq;
  10. 从IRQ异常中断处理程序中返回;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章