ARM异常处理过程

ARM程序在正常执行中,遇到一些特殊情况,需要放下正在执行的工作,去解决异常,然后再返回原来的地方继续工作,这样的一套机制称为ARM异常处理机制。

首先,程序正在正常执行,遇到异常后,不能直接去解决异常,因为此刻程序的一些变量,栈等需要保存,因为等到异常返回后,你要在之前被打断的地方继续要原来的目的进行。在程序去处理异常时,需要保存现场,记录当前的状态。

那ARM怎样去记录当前的状态呢?具体有以下几个方面:
1.将CPSR保存到相应异常模式下的SPSR_<mode>,同时当ARM处于Thumb状态时,要设置T位为ARM状态,禁止中断标志位;

2.将PC保存到相应异常模式下的LR_<mode>中;

3.将状态寄存器CPSR设置为对应异常模式,CPSR最后四个bit位是异常模式选择;

4.将PC寄存器指向对应处理异常处理程序的入口,即PC指向异常向量表对应异常类型的地址。

(1)、复位(Reset)
(2)、未定义的指令(Undef)
(3)、软件中断(SWI)
(4)、指令预取终止(Abort)
(5)、数据访问异常(DATAABORT)
(6)、外部中断请求(IRQ)
(7)、快速中断请求(FIQ)

异常向量表就是一条条跳转语句,因为只占用四个字节,所以异常处理程序无法存储在异常向量表中,需要跳转到其他地方去执行异常处理程序。

因此,在异常处理之前,首先要完成以上这些操作,不过这些都是硬件自动完成的,所以我们不必操心,但是,在异常处理程序结束后,返回之前的状态这个过程则需要我们人为设置的。

异常结束返回时:

从SPSR_<mode>恢复CPSR,即恢复异常之前的CPU的状态 

将LR_<mode>恢复PC,PC指向程序被打断的地方继续进行,但是不同的异常返回,PC的计算有所不同,下文会讲解到。

这些操作都是在ARM状态下执行的。

好了,异常处理机制暂时完成。


下面来讲清楚一些细节问题,上文说到的异常返回时,PC的计算有所不同,那我们来讲一下具体有哪些不同:

首先我们要知道,讲一下完成指令的过程,ARM状态下,在异常产生时内核将lr_<mode>=pc-4,意思就是说,这个步骤是要记录异常返回之后要执行的地址。

但是,lr_<mode>的值是要根据异常的类型进行调整的,如下:

     MOV   r0,#1            pc-8    正在执行

    MOV   r1,#2            pc-4    译码    这里保存到lr_<mode>

    ADD    r0,r0,r1      pc       取指       

 一条指令(ARM状态下,一条指令四个字节)分三个阶段:取指->译码->执行,取指地址(pc)=正在执行的地址+8

 (1)从软件中断SWI和未定义异常返回:

    MOV   r0,#1            pc-8   

    MOV   r1,#2            pc-4  

    ADD    r0,r0,r1      pc    

这两种异常是执行SWI指令或未定义指令发生了异常,即是在执行阶段发生了异常,所以lr保存的是MOV   r1,#2这条指令的地址(pc现在指向异常向量表的0x8(异常处理程序的入口)的地址),

所以异常返回后,执行的指令是从MOV   r1,#2这里开始,所以lr_<mode>的值直接给pc即可,即:

    MOVS   pc,lr_<mode>   

(2)从FIQ、IRQ和预取指令异常返回:

这两种异常必须要等到当前指令执行完才能去执行异常处理程序,所以执行完当前指令后,预取指令pc和译码指令都已经更新了(+4),如下图:执行MOV   r0,#8这条指令时,中断信号来了,

但是要等到这条指令执行完才能去执行异常处理程序,此时异常处理返回时要从MOV   r1,#2这条指令开始执行。

    MOV   r0,#1            pc-8     <-异常信号到来

    MOV   r1,#2            pc-4     

    ADD    r0,r0,r1      pc 

但是执行完MOV   r0,#1后,pc已经更新,指向了下一条指令,如下: 

    MOV   r0,#1            pc-12   

    MOV   r1,#2            pc-8     

    ADD    r0,r0,r1      pc-4 

    MOV   r1,r0          pc

若异常返回时,此时pc-4为ADD    r0,r0,r1指令,但是程序应该从MOV   r1,#2这条指令开始,所以不能直接将lr_<mode>给pc,而是将lr_<mode> - 4 给pc,即:

    SUBS   pc,lr,#4  

(3)预取指令异常  

该异常在取指令时发生异常,但是要在执行阶段才响应异常,lr_<mode>为MOV   r1,#2 的地址

    MOV   r0,#1            pc-8    <-异常处理

    MOV   r1,#2            pc-4     

    ADD    r0,r0,r1      pc    <-异常信号到来

此异常可能是取指令时内存没有访问权限或者为空,所以在异常处理程序中将内存内容修改好,在返回时再次执行MOV   r0,#1,所以返回时pc应指向MOV   r0,#1,即

  SUBS   pc,lr,#4

(4)从数据访问异常返回: 

    LDR   r0,r3            pc-8     <-异常信号到来

    MOV   r1,#2            pc-4     

    ADD    r0,r0,r1      pc 

此异常是在是在执行LDR   r0,r3时访问数据错误导致的异常,返回时要重新执行LDR   r0,r3 ,

    LDR   r0,r3            pc-12   

    MOV   r1,#2            pc-8     

    ADD    r0,r0,r1      pc -4

    MOV   r1,r0          pc

此时pc已经更新,若要重新执行LDR   r0,r3,将pcl指向lr_<mode> - 8 ,即:

    SUBS   pc, lr, #8


所以总结一下,异常处理程序返回时的地址应根据异常的类型决定

(1)判断异常程序是在指令执行阶段进行还是指令执行完后进行,即pc有没有更新;

(2)异常程序处理完后是否要重新执行指令。

猜你喜欢

转载自www.cnblogs.com/bky-eng/p/9612705.html
今日推荐