浅析arm的异常、中断和arm工作模式的联系

说到异常向量,会让人联想到中断向量。其实,中断是属于异常的子集的,也就是说中断其实是异常其中的一种。

   回到异常向量,他其实是一张表格,每个格子里存放的是一个地址,或者是一个跳转命令,不管是哪个,其目的都是让PC跳转到真正处理异常的代码的地方。

以下是arm的异常向量表:

wpsEE9.tmp

图1

初步介绍完异常向量,就来对比下ARM的arm的7种工作模式:

wpsEFA.tmp

图2

User : 非特权模式,大部分任务执行在这种模式

FIQ :   当一个高优先级(fast) 中断产生时将会进入这种模式

IRQ :   当一个低优先级(normal) 中断产生时将会进入这种模式

Supervisor :当复位或软中断指令执行时将会进入这种模式

Abort : 当存取异常时将会进入这种模式

Undef : 当执行未定义指令时会进入这种模式

System : 使用和User模式相同寄存器集的特权模式

可以发现arm的7种工作模式其实是和arm的异常向量表有着一定的对应关系的。

接着来看ARM的一个非常重要的寄存器——CPSR程序状态寄存器,如图二所示:该寄存器在arm的任何工作模式中都存在,且是被所以工作模式共用的。

寄存器每一位的含义如下图所示:

wpsF1A.tmp

图3

以上3者有着莫大的关联,结合三者分析,就会明白很多东西。

其一、arm的7种工作模式,和异常向量表有着一定的对应关系。 如SVC模式下发生普通中断(IRQ)arm自动切换到IRQ模式,进入IRQ模式后PC就会指向IRQ对应异常向量表,及0x18这个位置。

再比如复位时,就会进入svc模式,并且跳到Reset对应的异常向量表,及0x00位置(这也是为什么程序是从0x00开始执行的)

其二、工作模式的切换有主动和被动之分。上面所说的就是被动切换,他是随着某种异常的发生而导致的切换。

主动切换,就要靠cpsr这个寄存器了。可以看到这个寄存器的末四位就是用来设定进入哪种模式的。

何时需要cpsr主动切换模式呢:

1、一开始就想进入某种模式。如:一开始设置所有模式下的sp地址。示例如下:

wpsF1B.tmp

2、进入某种模式后,想切换到之前的模式。这个过程通常是通过读回SPSR的值。示例如下:

wpsF2B.tmp

接着,我们来区分异常和中断的区别和联系:

1、中断可以看作是异常的一种情况。

2、中断是可以屏蔽的,如通过cpsr寄存器的I位和F位分别屏蔽IRQ和FIQ。而异常是无法屏蔽的。

3、异常/中断发生时,PC都会指向相应的向量表。异常的发生往往会导致模式的自动切换。

4、IRQ和其他模式稍有不同。因为被动切换到IRQ模式下的情况有很多种,换句话就是,很多种中断,都会导致进入IRQ模式。进入IRQ模式还需要判断是那种情况导致了中断,所以IRQ往往还对应一张中断向量表。(区分于异常向量表)相当于异常向量表的子级表。

最后看,在模式切换时,都发生了什么?

1、当模式发生切换时(主动或者被动),硬件会自动帮我们完成一些事情。然后还需要软件完成一些事情。

做好这两件事,就可以在模式之间切换而不会相互影响,当然对应程序员而言只需要做好后者。

2、硬件帮我们完成的事情,是在模式切换时随之完成,而软件要完成的任务,是在模式切换之后。这点需要十分注意!比如当前是SVC模式切换到IRQ模式。那么软件需要完成的事情,是在当前IRQ模式下完成的。

3、那么硬件完成了什么事情,软件又需要做什么呢?

3.1、硬件完成的事情有:

wpsF2C.tmp

切换到新的模式后,用的就是当前模式下的sp以及lr,但是pc只有一个。由于硬件帮我们

完成的一些事。所以当前IRQ模式下的lr寄存器存放的其实是上个模式SVC的PC值。当前IRQ模式下的

SPSR寄存器存放的其实是上个模式SVC的CPSR值。这充分为返回上一个模式做好了准备。

3.2、所以软件需要完成的任务有:

3.2.1、保存当前共用寄存器的值,(如SVC模式和IRQ模式共用r0~r12 以及r15及pc)到当前模式的栈内存。保证之前模式的值不被破坏。

这里CPSR虽然也是共用的,但是不用保存到栈中,这是因为硬件会自动把上个模式的CPSR保存到当前模式的SPSR。

而SPSR直到中断返回,及切换到之前的模式才会用到。有点同学会问了,pc的值也会由硬件自动保存到lr,为什么还需要保存到栈中呢?这是因为lr和SPSR不同,在中断执行的过程中,很可能需要使用lr,为了不把之前的pc值冲掉还是先将其发到栈中保存。

3.2.2、进入中断处理函数。处理中断。

3.2.3、中断返回,将之前保存到栈里的值读回,并SPSR的值赋值给CPSR实现主动切换到之前的模式。示例代码:

wpsF2D.tmp

最后,聊一个面试经常问的问题,FIQ相比IRQ,FIQ称为快速中断,IRQ称为普通中断。FIQ为什么比IRQ快!

我们可以结合图1和图2进行分析:

1、先看图1,FIQ的异常向量地址为0x1C,位置处于最顶部,这就意味着,FIQ真正的异常处理代码可以紧接着0x1C,及无需跳转,不跳转意味着无需打断arm的流水线,所以可以提高中断响应。

2、再看图2,FIQ模式下具有更多的独立寄存器,如r8~r14,这些寄存器都是FIQ模式下独自享用的。这就意味着,当发生快速中断,进行模式切换时,只有少量的寄存器需要备份到栈中,从而也能节省时间,提高中断的响应速度。

以上两点就是FIQ为什么比IRQ快的原因,别小看节省的这么一点点时间,有的时候就是这么“兵贵神速”。

posted @ 2016-01-08 12:00 宋桓公 阅读(...) 评论(...) 编辑 收藏