以下内容参考韦东山老师的《嵌入式Linux应用开发完全手册》。
在说ARM中断体系结构前,需要了解ARM体系CPU的工作模式,因CPU进入中断时需要切换到不同的工作模式,然后执行中断响应。主要有7种工作模式:
1.用户模式(usr):ARM处理器正常的运行状态。
2.中断模式(irq):用于通用的中断处理。
3.快速中断模式(fiq):用于高速数据传输或通道处理。
4.管理模式(svc):操作系统使用的保护模式。
5.系统模式(sys):运行具有特权的操作系统任务。
6.数据访问终止模式(abt):当数据或者指令预取终止时进入该模式。可用于虚拟存储和数据保护。
7.未定义指令终止模式(und):当未定义的指令执行时进入该模式。可用于支持硬件协处理的软件仿真。
除了用户模式,其他模式可称为特权模式。大多数程序运行于用户模式,进入特权模式是为了处理中断、异常、或者访问被保护的系统资源。
所以当有中断发生时,CPU须由用户模式进入到中断模式。那么CPU怎么进入中断模式呢?这就需要了解不同模式下的寄存器的使用喽。
ARM920T有31个通用的32为寄存器和6个程序状态寄存器。当进入不同的模式时就使用该模式下的寄存器。
部分寄存器在不同的模式下有自己的副本,当进入某工作模式时,该工作模式下的副本寄存器将被使用。由图中可以看到FIQ(快速中断模式)的副本寄存器最多,这就使得进入快速中断模式时需要保存的寄存器状态也就最少,倘若r1-r8不做修改的话几乎不需要保存。这应该也是它被称为快速中断的原因。
在这些寄存器中,r13称为栈指针寄存器;r14称为程序连接寄存器;r15称为程序计数器。
关于r14和r15,当执行BL指令时,r14得到r15的备份。指令执行完后,再将r14的值赋给r15.当发生中断或者异常时,不同模式下的r14得到r15的备份,异常处理完后再赋给r15。
除了上述的16个寄存器外,还有一个非常重要的主角:CPSR寄存器(当前程序状态寄存器),该寄存器标识了各种状态和工作模式。
有了该图就不难理解head.S中Reset下面的语句了:
Reset:
ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
msr cpsr_c, #0xd2 @ 进入中断模式
ldr sp, =3072 @ 设置中断模式栈指针
msr cpsr_c, #0xd3 @ 进入管理模式
ldr sp, =4096 @ 设置管理模式栈指针,
@ 其实复位之后,CPU就处于管理模式,
@ 前面的“ldr sp, =4096”完成同样的功能,此句可省略
0xd2为0x11010010其中后五位”10010“设置进入中断模式,前三位”110“设置IRQ和FIQ禁止,CPU工作于ARM工作状态。
0xd3为0x11010011其中后五位”10011“设置进入管理模式,前三位”110“仍然是IRP和FIQ禁止,CPU工作于ARM工作状态。
为什么要设置栈指针,且该指针指向4096和3072呢?
这是分别设定中断模式和管理模式下的堆栈指针到4096 (SRAM顶层),ARM在各种执行模式下都需要设置各自的堆栈指针,这就是为什么你看到那么多次ldr sp的操作了。另外,由于堆栈向下生长,这是为什么可以将堆栈指针设定到地址空间顶层的原因。除此之外还有SPSR寄存器(程序状态保存寄存器),当不同的模式进行切换时,在SPSR中保存前一个工作模式的CPSR值,这样,当返回前一个模式时,只需要将SPSR的值恢复到CPSR即可。
当中断发生时,具体的操作是怎么进行的呢?
一、当冲断发生时,CPU将切换进入相应的工作模式,此时,CPU核将自动完成如下事情:
1)在异常工作模式的连接寄存器R14中保存前一个工作模式的下一个指令的地址,对于ARM状态,进入或者退出异常模式时PC的地址:
2)将CPSR的值复制到异常模式的SPSR。
3)将CPSR的工作模式设置为该异常的工作模式。
4)令PC的值等于该异常模式在异常向量表中的地址,即跳转去执行异常向量表中的相应指令。
二、从异常工作模式退出到之前的工作模式时,需要通过软件完成如下操作。
1)将连接寄存器保存的前一个工作模式的指令地址减去一个适当的值赋给PC寄存器,具体如下。
2)将SPSR的值恢复到CPSR。
前面介绍了当有中断发生时的处理情况,那么CPU是如何检测到有异常发生呢?主要有两种方式:
1)查询方式:程序循环检测割设备的状态并做出相应的响应。
2)中断方式:当事件发生时,硬件会设置某个寄存器。CPU每执行完一个指令,就通过硬件查看该寄存器,如果该寄