uCOS-II的中断-ARM7实现中断嵌套的方法探究

【@.1 中断嵌套与CPU支持】

在uCOS-II,或者是任何一个可剥夺型OS系统中,中断嵌套是一个必须要解决的问题。从结论上来说,并不是所有的CPU都支持中断嵌套的,即便是ARM系列内核。对于ARM7系列,例如LPC2xxx系列芯片,硬件上是不支持中断嵌套的,而对于新的CortexM3系列,中断嵌套是可配置的,但是中断嵌套时保存现场的操作并不完整,并没有把R0~R15所有寄存器都保存到堆栈中,而是只保存R0~R4。这就需要我们手动软件实现全部或部分的中断现场保护机制。不过首先通过分析ARM7系列芯片来看看中断嵌套的硬件要求。

ARM7系列的内核一共有7中模式,如下图所示:

image

其中

(1) User Mode:用户模式。唯一非特权模式,可执行指令受限。(读写CPSR禁止)
(2) System Mode:特权模式。 
(3) IRQ Mode:中断模式

(4) FIQ Mode:快速中断模式。可打断IRQ模式

(5) Supervisor Mode:监视模式。软中断(SWI)处理函数在这种模式下执行。 
(6) Abort Mode:所有同内存保护相关的异常均在这种模式下执行。 
(7) Undefined Mode:处理无效指令的异常处理函数在这种模式下执行。

每种模式都有自己的一套R0~R14,以及CPSR,这样能保证跳转其他模式时能直接保存现场。而如果我们要手动保存现场时还必须将这些寄存器压入到堆栈中,这样就用C或汇编写一些比较底层的代码了。当进入中断或异常时会自动进入响应的模式进行处理。而这些都是由程序状态寄存器CPSR保存的。每个CPU内部的状态寄存器可能结构不同,但是对于ARM来说大体的结构差不多。ARM7中的CPSR的结构如下:

 

image

其中CPSR的末尾几位即保存了当前的CPU模式。

当每种异常发生,硬件上会做以下操作:

1.CPSR的Mode位置位成当前模式,控制位置位

2.保存打断前模式的R0~R14到对应寄存器,CPSR到SPSR。

3.新模式的PC跳转到内存指定地址,即异常入口地址。

image

这就需要我们在启动代码的对应地址段协商地址偏移的标签。下面对几个常用的异常进行介绍:

一.Reset。发生在首次上电或者手动按下Reset键(CPU的Reset引脚给个低电平):

image

上电或Reset之后一般会进入固化在flash中的bootloader,bootloader的工作流程比较复杂,大致上需要判断一些引脚电平来进入相应的模式。比如若判断到ISP引脚(P0.14 in LPC2119)低电平,会进入ISP模式烧写程序。判断Boot0和Boot1的电平组合可以进入对应的外部flash的启动。正常情况下会进入flash中的0x00000000地址的Reset入口。按照启动代码的编写进行一些必要的寄存器操作,以及初始化各个模式的堆栈,最后进入到main函数。

二.Irq中断。一般中断可以注册成irq或者fiq中断。若注册为irq中断时的流程如下:

image

1.CPSR模式位置为IRQ模式

2.将当前的PC存入到irq的R14中,也就是程序的返回地址,当退出irq时会从这里取出地址给PC,程序回到原处。

3.CPSR中irq使能位清零,禁止irq中断响应。可以看到这就是不能中断嵌套的一个重要原因,因为硬件上会禁止irq的响应,除非你手动将其打开。

4.程序跳转到irq的入口地址,按照启动代码执行操作。比如Keil中会跳转到VicVectAddr地址,即向量中断的入口地址,之后交给向量中断控制器来进行操作。

三.FIQ

image

Fiq异常基本跟irq异常的流程一致,除了仅仅会将CPSR中的irq和fiq使能位都清零,即不能再响应irq和fiq中断了,并且跳入到fiq的入口地址。当然按照Keil中的启动代码这里是一个死循环,即若不修改启动代码是不能使用fiq中断的。不过对于fiq这种快速中断机制,若我们能手动实现中断嵌套完全可以不用fiq中断,全部利用我们自己的代码来实现。比如uCOS-II中,所有中断都是irq中断,不需要fiq中断。

四.SWI(软件中断)

image

软件中断不同于其他的中断或异常,这是需要在程序中自己编程调用软件中断命令来触发的。调用后会将CPSR置为SVC(supervisor)管理员模式,存入PC到R14_swi,禁止irq和fiq中断,并且跳转到swi异常入口。这种方式的特点就是进入了一个没有权限限制的SVC模式,这样就可以进行对CPSR的读写操作了。这种方式带给我们很多遐想,我们可以用软件中断进行模式切换,进而进行寄存器的保存操作即保存中断现场,从而可以实现中断嵌套。

【@.2 中断嵌套的方法探究】

中断嵌套的核心思想是,保存当前CPU寄存器到堆栈中,即保存中断现场,并且打开中断使能位允许中断再次响应。但是由于CPU不同模式的权限区分导致这一想法不能简单的实现。比如,很多启动代码中在进入CPU前会进入没有权限的User模式,但是User模式是没办法对CPSR进行读写操作的,也就是说没办法直接在User模式中将CPSR压入到堆栈,同时不能通过向CPSR的模式位写入模式代码切换到其他的模式。

image

仅仅考虑irq中断,我们来回忆一下整个中断响应的流程。首先中断有输入,CPSR模式置位为irq模式,将当前PC值保存到irq模式的R14中,并且清除CPSR的irq标志位使得不能再次响应irq中断,最后跳转到irq中断入口地址。进过启动代码和我们的程序配置,最终会进入到我们编写中断服务程序中,当这个程序结束时会读取之前保存在R14_irq中的地址值给PC,程序回到原来中断处继续运行。在此基础上我们考虑集中方法实现中断嵌套。(以下假设主程序在User mode下运行)

image

方法一:

中断产生时会进入irq模式,所以当然有权限操作CPSR,因此如果我们仅仅清除CPSR的中断使能位使之能够在此响应中断的话看看有什么结果。图中进入中断的红色部分就是我们手动添加的代码。当IRQ1响应时,我们进入中断服务程序之前手动打开CPSR的irq中断使能位,那么如果当运行到一定时间新的中断IRQ2响应时,也会做同样的操作。而其中将PC存入到R14_irq这一步硬件帮我们做的操作就会出问题。因为这两个中断都是进入了irq模式,所以他们的R14_irq是同一个寄存器,中断2响应时会将原本中断1响应时保存在R14中的返回地址值修改,变成中断2响应之前的地址值,而这个值正是中断1的服务程序运行到被中断2打断的地方。当中断2结束返回时读取R14_irq的值,返回到中断1的被打断出,中断1继续运行,当返回时又读取R14_irq的值,这时候的值却是被中断2打断时的地址值,所以中断1会进入一个死循环。

所以,仅仅打开中断使能位而不进行现场保护操作是绝对不行的。

 image

方法二:

在中断操作进入中断服务之前手动打开CPSR中断使能位,保存所有寄存器到堆栈,中断返回之前手动恢复堆栈中保存的寄存器。但是这种方法实际上并不可行,如果仅仅有IRQ1时是OK的,但是若有IRQ2,打断IRQ1,当IRQ2返回时此时硬件已经进入User Mode,而CPSR中保存的是之前IRQ1时的CPSR,其中mode位是irq。这就产生了冲突,能不能继续运行下都是个问题。其实可以这样理解,当IRQ2返回时已经进入User Mode模式,而若想返回到刚才的IRQ1,相当于要从User Mode跳到Irq模式执行IRQ1的剩余部分,而User Mode是无法自发跳转到其他模式的,除非调用软件中断,这其实就涉及到下面的方法:

image

方法三:

每次中断返回时调用软件中断指令,进入swi软件中断模式,这时其实已经进入SVC模式,所以有权限对CPSR进行操作,所以这种方法可以实现中断嵌套,而且实际上这也是很多OS在特定CPU上实现中断现场保护的方法。不过回过头想,所有这一切其实都是因为User Mode没有权限对CPSR进行操作所造成的,那么我们换一种思维,直接让主程序运行在有权限操作CPSR的SVC管理员模式不就好了吗?

image

方法四:

可以通过修改启动代码,放弃对User模式的使用,使进入main函数之前处于SVC模式,这样一来整个程序从头到尾都是处于SVC模式,具有全部权限进行寄存器的操作,这样一来,在中断返回时也不用像方法三一样,特意进入swi的异常入口进入SVC模式,并且需要保存进入SVC模式的现场。方法四中断返回时直接就是主程序运行的SVC模式,不用新进入另一个模式进行恢复现场操作,这样中断恢复时的时间也会快一些。实际上,这也是uCOS-II在ARM7系列上移植的推荐模式,很多移植的实例也是采用全程SVC模式的方式进行中断嵌套操作的。当然你也可以自己写程序用方法三的软件中断进行现场保护,是可以实现的,只是机器周期上需要多几步软件中断本身的模式切换操作。

【@.3 中断嵌套对于CPU硬件的反思】

最后我们可以分析,之所以ARM7要花这么大代价实现中断嵌套,完全是因为CPU内核的模式与特权造成的。所以如果CPU的内核没有那么多的限制,或者说CPU内核本身就支持简单的中断嵌套,我们的工作也就会好做很多了。我们可以看看Cortex M3系列的STM32F10x内核,模式和特权上就简单很多了:

 image

Cortex的中断机制也跟ARM7截然不同。

 image

可以看到这种内核模式与中断机制上简化了许多,很适合与OS在其上面的移植。

@.[FIN]      @.date->Mar 27, 2013      @.author->apollius

posted on 2013-03-27 17:26  apollius  阅读(3786)  评论(1编辑  收藏  举报

导航