一、ARM异常处理
1.ARM处理器工作模式
a.用户(User或usr)模式非特权模式
b.系统(System或sys)模式特权模式
c.一般中断(IRQ或irq)模式特权模式
d.快速中断(FIQ或fiq)模式特权模式
e.管理(Supervisor或svc)模式特权模式
f.中止(Abort或abt)模式特权模式
g.未定义指令终止(Undefined或und)模式特权模式
2.ARM处理器模式切换
ARM处理器工作模式通过CPSR里的M[4:0]位进行区分。如图1所示。
图1 CPSR控制位
通过向模式位M[4:0]里写入相应的数据切换到不同的模式。
在ARM处理器中,只有MRS(Moveto Register from State register)指令可以对状态寄存器CPSR和SPSR进行读操作;只有MSR(Moveto State register from Register)指令可以对状态寄存器CPSR和SPSR进行写操作。MRS与MSR配合使用,可以实现对CPSR或SPSR寄存器的读-修改-写操作,可以切换处理器模式、或者允许/禁止IRQ/FIQ中断等。
由于xPSR(xPSR表示CPSR或SPSR,下同)寄存器代表了CPU的状态,其每个位有特殊意义,在执行对xPSR状态寄存器写入时(读取时不存在该用法),为了防止误操作和方便记忆,将xPSR里32位分成4个区域,每个区域用小写字母表示:
c 控制域屏蔽 PSR[7..0]
x 扩展域屏蔽 PSR[15..8]
s 状态域屏蔽 PSR[23..16]
f 标志域屏蔽 PSR[31..24]
向对应区域进行写入时,使用xPSR_x可以指定写入区域,而不影响状态寄存器其他位。
表1列出了不同模式的二进制数表示。
表1不同工作模式对应二进制
模式名 | USR | FIQ | IRQ | SVC | ABT | UND | SYS |
M[4:0] | 10000 | 10001 | 10010 | 10011 | 10111 | 11011 | 11111 |
3.异常分类
1)异常的分类:7种
a.复位异常
b.未定义指令异常
c.软件中断:SWI
d.指令预取中止
e.数据访问中止
f.一般中断
g.快速中断
2)异常模式:5种(ARM处理器7种工作模式中,有5种是异常模式)
a.SVC(管理模式)(加电后,进入SVC模式)
b.IRQ(一般中断模式)
c.FIQ(快速中断模式)
d.ABT(中止模式)
e.UND(未定义指令终止模式)
4.异常返回地址
一条指令的执行分为取指、译码、执行三个主要阶段,CPU由于使用流水线技术,造成当前执行指令的地址应该是PC-8(32位机一条指令4字节),那么执行指令的下条指令应该是PC-4。在异常发生时,CPU自动会将PC-4的值保存到LR里,但是该值是否正确还要看异常类型才能决定。
各异常类型的返回地址说明如下:
(1)复位异常中断处理程序不需要返回。
整个应用系统是从复位异常中断处理程序开始执行的,因而它不需要返回。
(2)软中断指令(SWI)异常和未定义指令异常。
SWI异常中断和未定义指令异常中断是由当前执行的指令自身产生的,当SWI或未定义指令异常中断产生时,程序计数器PC的值还未更新,它指向当前指令后面第2条指令(对于ARM指令来说,它指向当前指令地址加8个字节的位置)。当SWI和未定义指令异常中断发生时,处理器将值(PC-4)保存到异常模式下的寄存器lr中。这时(PC-4)即指向当前指令的下一条指令。因此返回操作可以通过下面的指令来实现:
MOV PC,LR
(3)IRQ和FIQ异常
通常处理器执行完当前指令后,查询IRQ中断引脚及FIQ中断引脚,并且查看系统是否允许IRQ中断及FIQ中断。如果有中断引脚有效,,并且系统允许该中断产生,处理器将产生IRQ异常中断或FIQ异常中断。当IRQ和FIQ异常中断产生时,程序计数器PC的值已经更新,它指向当前指令后面第3条指令(对于ARM指令来说,它指向当前指令地址加12个字节的位置)。当IRQ和FIQ异常中断发生时,处理器将值(PC-4)保存到异常模式下的寄存器lr中。这时(PC-4)即指向当前指令后的第2条指令。因此返回地址可以通过下面的指令算出:
SUBS PC,LR,#4
(4)指令预取中止异常
在指令预取时,如果目标地址是非法的,该指令将被标记成有问题的指令。这时,流水线上该指令之前的指令继续执行。当执行到该被标记成有问题的指令时,处理器产生指令预取中止异常中断。当发生指令预取中止异常中断时,程序要返回到该有问题的指令处,重新读取并执行该指令。因此指令预取中止异常中断程序应该返回到产生该指令预取中止异常中断的指令处,而不是发生中断的指令的下一条指令。指令预取中止异常中断是由当前执行的指令自身产生的,当指令预取中止异常中断产生时,程序计数器PC的值还未更新,它指向当前指令后面第2条指令(对于ARM指令来说,它指向当前指令地址加8个字节的位置)。此时处理器将值(PC-4)保存到异常模式下的寄存器lr中,它(PC-4)即指向当前指令的下一条指令。因此返回操作可以通过下面的指令来实现:
SUBS PC,LR,#4
(5)数据访问中止异常
当发生数据访问中止异常中断时,程序要返回到该有问题的指令处,重新访问该数据。因此数据访问中止异常中断应该返回到产生该数据访问中止异常中断的指令处,而不是当前指令的下—条指令。
数据访问中止异常中断是由数据访问指令产生的,当数据访问中止异常中断产生时,程序计数器PC的值已经更新,它指向当前指令后面第3条指令(对于ARM指令来说,它指向当前指令地址加12个字节的位置)。此时处理器将值(PC-4)保存到异常模式下的寄存器lr中,它(PC-4)即指向当前指令的后第二条指令。因此返回操作可以通过下面的指令来实现:
SUBS PC,LR,#8
5.异常向量表
异常向量表是一段特定内存地址空间,每种ARM异常对应一个字长空间(4字节),正好是一条32位指令长度,当异常发生时,CPU强制将PC的值设置为当前异常对应的固定内存地址。异常向量表如下:
表2异常向量表
地址 | 异常类别 | 异常模式 | 优先级(6最低) |
0x00000000 | 复位异常 | SVC(管理模式) | 1 |
0x00000004 | 未定义指令异常 | UND(未定义指令终止模式) | 6 |
0x00000008 | 软件中断 | SVC(管理模式) | 6 |
0x0000000c | 指令预取中止 | ABT(中止模式) | 5 |
0x00000010 | 数据访问中止 | ABT(中止模式) | 2 |
0x00000014 | 保留 | 未使用 | 未使用 |
0x00000018 | 一般中断 | IRQ(一般中断模式) | 4 |
0x0000001c | 快速中断 | FIQ(快速中断模式) | 3 |
跳入异常向量表操作是异常发生时,硬件自动完成的。因为异常向量是一个固定的内存地址,所以我们可以通过向该地址处写一条跳转指令(机器指令级别),让它跳向我们自己定义的异常处理程序的入口,就可以完成异常处理了。
二、异常处理流程
1.异常发生时的硬件操作
1)保存执行状态:将CPSR复制到发生的异常模式下SPSR中。
2)模式切换:将CPSR模式位强制设置为与异常类型相对应的值,同时处理器进入到ARM执行模式,禁止所有IRQ中断,当进入FIQ快速中断模式时禁止FIQ中断。
3)保存返回地址:将下一条指令的地址(被打断程序)保存在LR(异常模式下LR)中。
4)跳入异常向量表:强制设置PC的值为相应异常向量地址,跳转到异常处理程序中。
2.跳转到异常处理程序后的软件工作
1)保存执行现场:也就是保存当前操作寄存器里的数据,可以通过栈操作指令实现:
STMFD sp!, {r0-r12, lr}
(sp!中的!号,表示在指令执行完成后,要改变(回写)寄存器sp的值。)
2)进入异常处理:也就是跳转到自己定义的处理程序入口,指令如下:
BL xxx_handler
3)恢复现场:也就是要恢复被打断程序运行时寄存器数据,恢复程序运行时状态CPSR,并且通过进入异常时保存的返回地址,返回到被打断程序继续执行。指令如下:
LEMFD sp!, {r0-r12, pc}^
(^表示将spsr的值复制到cpsr)