ARM的异常处理过程分析_第1页
ARM的异常处理过程分析_第2页
ARM的异常处理过程分析_第3页
ARM的异常处理过程分析_第4页
ARM的异常处理过程分析_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、uC/OS-II官网给出来的ARM7-ARM9移植手册(AN-104),分析了在ARM中移植的问题,想想从来没有认真的学习过ARM的汇编,趁着这个机会复习复习吧。其实底层的东西才是创造力的心脏。其中的移植代码中存在的很多问题比如中断的关闭和开启,任务级别的情景切换,中断到任务的情景切换都是我们在平时移植中讲到,我也不在此强调了。在官网中提供的移植过程中存在异常处理机制,这个本不是在移植过程中考虑的,但是文档中确实提供了一个比较好的处理方式。我在此对这一段时间的学习做一个总结。首先需要了解ARM的异常处理机制,异常是每一种处理器都必须考虑的问题之一,关键在于如何让处理,返回地址在什么位置都是需要

2、考虑的,ARM中支持7种异常,其中包括复位、未定义指令异常、软中断异常、预取指令中止、数据中止、IRQ、IFQ。每一种异常运行在特定的处理器模式下。我在此逐一的分析。一般异常发生后,CPU都会进行一系列的操作,这些操作有一部分是CPU自动完成,有一部分是需要我们程序员完成。首先说明CPU会自动完成的部分,用ARM结构手册中的代码描述如下:R14_<exception_mode> = return link               

3、 /这个可以参看寄存器的说明,两个作用SPSR_< exception_mode > = CPSRCPSR4:0 = exception mode numberCPSR5 = 0                       /AEM指令If <exception_mode>=Reset or Fiq then  &

4、#160; /只有在复位和FIQ模式下才会关闭FIQ中断CPSR6 = 1 CPSR7 = 1                              /任何异常模式下都会关闭IRQ中断PC = exception vector address从上面的代码中我们可以发现CPU自

5、动处理的过程包括如下:1、  拷贝CPSR到SPSR_<mode>2、  设置适当的CPSR位: 改变处理器状态进入ARM状态;改变处理器模式进入相应的异常模式;设置中断禁止位禁止相应中断。3、  更新LR_<mode>,这个寄存器中保存的是异常返回时的链接地址4、  设置PC到相应的异常向量以上的操作都是CPU自动完成,异常的向量表如下:返回地址问题异常的返回地址也是需要我们注意的地方,不同的异常模式返回地址也是存在差异的,这主要是因为各种异常产生的机理存在差别所导致的。这样我们

6、的需要在异常进入处理函数之前或者在返回时调整返回地址,一般采用进入异常处理函数前进行手动调整。下面每一种异常R14保存的值都给了出来,其中也包含了CPU自动处理的部分,根据保存的R14就可以知道怎样实现地址的返回。复位异常:可以看出该模式下的先对来说返回地址也比较简单,不需要做太多的描述。未定义的指令异常:返回的方式也比较简单:       MOVS  PC, R14软中断异常:返回的方式也比较简单:       MOVS &

7、#160;PC, R14预取指令中止异常:返回需要做下面的调整:SUBS      PC, R14, #4数据中止返回地址需要做下面的调整:如果需要重新访问数据则:SUBS      PC, R14, #8如果不需要重新访问数据则:SUBS      PC, R14, #4IRQ中断的处理过程:返回地址需要做下面的调整:       SUBS PC

8、,R14,#4IFQ中断:返回地址需要做下面的调整:       SUBS  PC, R14 ,#4从上面的代码可以知道,对于每一种异常,保存的返回地址都是不一样的,一般都需要我们手动的跳转,当然调整的时机也需要我们选择,是在进入处理前跳转还是返回时调整都是需要我们程序员控制的。在ARM Developer Suite Developer Guide中对ARM处理器的异常处理操作提供能更加详细的解释,每一种异常下的处理方式如下文描述:异常返回时另一个非常重要的问题是返回地址的确定,在前面曾提到进入异常时处

9、理器会有一个保存LR 的动作,但是该保存值并不一定是正确的返回地址,下面以一个简单的指令执行流水状态图来对此加以说明。我们知道在ARM 架构里,PC值指向当前执行指令的地址加8处,也就是说, 当执行指令A(地址0x8000)时,PC 等于指令C 的地址(0x8008)。假如指令A 是“BL”指令,则当执行该指令时,会把PC(=0x8008)保存到LR 寄存器里面,但是接下去处理器会马上对LR 进行一个自动的调整动作:LR=LR-0x4。这样,最终保存在 LR 里面的是 B 指

10、令的地址,所以当从 BL 返回时,LR里面正好是正确的返回地址。同样的调整机制在所有LR自动保存操作中都存在,比如进入中断响应时,处理器所做的LR 保存中,也进行了一次自动调整,并且调整动作都是LR=LR-0x4。下面,我们对不同类型的异常的返回地址依次进行说明:假设在指令A 处(地址0x8000)发生了异常,进入异常响应后,LR 上经过调整保存的地址值应该是B 的地址0x8004。1、 如果发生的是软件中断,即A 是“SWI”指令异常是由指令本身引起的,从 SWI 中断返回后下一条执行指令就是

11、B,正好是LR 寄存器保存的地址, 所以只要直接把LR 恢复给PC。MOVS pc, lr2、 发生的是Undefined instruction异常异常是由指令本身引起的,从异常返回后下一条执行指令就是B,正好是LR 寄存器保存的地址, 所以只要直接把LR 恢复给PC。MOVS pc, lr3、 发生的是IRQ或FIQ中断因为指令不可能被中断打断,所以A指令执行完以后才能响应中断,此时PC已更新,指向指令D的地址(地址0x800C),LR 上经过调整保存的地址值是C 的地址0x8008。中断返

12、回后应该执行B指令,所以返回操作是:SUBS pc, lr, #44、 发生的是Prefetch Abort异常该异常并不是处理器试图从一个非法地址取指令时触发,取出的指令只是被标记为非法,按正常处理流程放在流水线上,在执行阶段触发Prefetch Abort异常,此时LR 上经过调整保存的地址值是B 的地址0x8004。异常返回应该返回到A指令,尝试重新取指令,所以返回操作是:SUBS pc, lr, #45、 发生的是“Data Abort”CPU访问存储器时触发该异常,此时PC指向指令D的地址(地址0x800C),LR 上经过调整保存的地

13、址值是C 的地址0x8008。异常返回后,应回到指令A,尝试重新操作存储器,所以返回操作是:SUBS pc, lr, #8以上就是ARM异常的CPU操作部分,接下来就是程序员应该完成的操作。1.         由于CPU会自动跳转到对应的异常向量中,因此只需要在在各个异常向量中存放对应的操作,最简单的都是存放一个B指令跳转到对应的异常处理函数的操作即可。但由于B指令的跳转返回只有+-32M,而异常处理函数的地址可能会超过+-32M,因此可以采用另一种方式实现方式:在异常向量中保存一条指令LDR

14、 PC addr,其中的addr中就保存了异常处理函数的地址,当然addr的相对地址要小于+-32M。这样也就解决了跳转范围的问题。2.         接下来就是异常处理函数对应的操作,可以在进入异常处理之前就进行返回地址的调整,这样后面就不用进行处理啦,当然也可以在返回过程中再调整。一般都是在这个过程中进行调整。进行压栈操作,保存对应的环境变量。调用实际的处理过程等。3.         出栈,恢复CPU的状态和

15、寄存器的值。由于第一步中已经调整好返回地址,这一步不需要再次调整。当然如果之前没有调整,这里则需要进行相应的调整。在uC/OS-II的官网移植中采用通用异常处理函数的方式实现异常的处理,下面我们来分析其中的部分代码:首先是处理器部分的移植,包括异常向量、异常的ID号,存储异常处理函数地址的地址等:/*ARM的异常ID号,支持7种类型的异常,每一种异常都存在一个ID号*/#define  OS_CPU_ARM_EXCEPT_RESET        0x00#define  O

16、S_CPU_ARM_EXCEPT_UNDEF_INSTR 0x01#define  OS_CPU_ARM_EXCEPT_SWI          0x02#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT 0x03#define  OS_CPU_ARM_EXCEPT_DATA_ABORT     0x04#define  OS_CPU_

17、ARM_EXCEPT_ADDR_ABORT     0x05#define  OS_CPU_ARM_EXCEPT_IRQ               0x06#define  OS_CPU_ARM_EXCEPT_FIQ            

18、;   0x07#define  OS_CPU_ARM_EXCEPT_NBR              0x08/*异常向量地址*/#define  OS_CPU_ARM_EXCEPT_RESET_VECT_ADDR              (OS

19、_CPU_ARM_EXCEPT_RESET          * 0x04 + 0x00)           /0x00#define  OS_CPU_ARM_EXCEPT_UNDEF_INSTR_VECT_ADDR        (OS_CPU_ARM_EXCEPT_UNDEF_INS

20、TR    * 0x04 + 0x00)         /0x04#define  OS_CPU_ARM_EXCEPT_SWI_VECT_ADDR                (OS_CPU_ARM_EXCEPT_SWI     

21、60;      * 0x04 + 0x00)             /0x08#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_VECT_ADDR     (OS_CPU_ARM_EXCEPT_PREFETCH_ABORT * 0x04 + 0x00)    &

22、#160;    /0x0c#define  OS_CPU_ARM_EXCEPT_DATA_ABORT_VECT_ADDR         (OS_CPU_ARM_EXCEPT_DATA_ABORT     * 0x04 + 0x00)             

23、0;              /0x10/*这个异常是ARM中不支持的异常*/#define  OS_CPU_ARM_EXCEPT_ADDR_ABORT_VECT_ADDR         (OS_CPU_ARM_EXCEPT_ADDR_ABORT     * 0x04 + 0x00) 

24、                           /0x14#define  OS_CPU_ARM_EXCEPT_IRQ_VECT_ADDR              

25、;  (OS_CPU_ARM_EXCEPT_IRQ            * 0x04 + 0x00)                           /0x18#define 

26、; OS_CPU_ARM_EXCEPT_FIQ_VECT_ADDR             (OS_CPU_ARM_EXCEPT_FIQ            * 0x04 + 0x00)            

27、0;          /0x1c/*存储异常处理函数地址的地址*/* ARM exception handlers addresses                   */#define  OS_CPU_ARM_EXCEPT_RESET_HANDLER_ADDR  

28、;         (OS_CPU_ARM_EXCEPT_RESET          * 0x04 + 0x20)                        

29、60;   /0x20#define  OS_CPU_ARM_EXCEPT_UNDEF_INSTR_HANDLER_ADDR     (OS_CPU_ARM_EXCEPT_UNDEF_INSTR    * 0x04 + 0x20)           /0x24#define  OS_CPU_ARM_EXCEPT_SWI_HAN

30、DLER_ADDR             (OS_CPU_ARM_EXCEPT_SWI            * 0x04 + 0x20)        /0x28#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_

31、HANDLER_ADDR  (OS_CPU_ARM_EXCEPT_PREFETCH_ABORT * 0x04 + 0x20)     /0x2c#define  OS_CPU_ARM_EXCEPT_DATA_ABORT_HANDLER_ADDR      (OS_CPU_ARM_EXCEPT_DATA_ABORT     * 0x04 + 0x20)    

32、        /0x30#define  OS_CPU_ARM_EXCEPT_ADDR_ABORT_HANDLER_ADDR      (OS_CPU_ARM_EXCEPT_ADDR_ABORT     * 0x04 + 0x20)           /0x34#define

33、  OS_CPU_ARM_EXCEPT_IRQ_HANDLER_ADDR             (OS_CPU_ARM_EXCEPT_IRQ            * 0x04 + 0x20)           /0

34、x38#define  OS_CPU_ARM_EXCEPT_FIQ_HANDLER_ADDR             (OS_CPU_ARM_EXCEPT_FIQ            * 0x04 + 0x20)         

35、0; /0x3c/*存储在异常向量中的内容,实质上是LDR PC,PC,#0x18的机器码*/#define  OS_CPU_ARM_INSTR_JUMP_TO_SELF              0xEAFFFFFE/* ARM "Jump To Exception Handler" asm instruction    */#define  O

36、S_CPU_ARM_INSTR_JUMP_TO_HANDLER         0xE59FF018异常的初始化函数,首先,完成了在异常向量中存储指令的操作,采用机器码的形式就能避免直接访问寄存器什么的,其次,完成在固定的地址处存放对应异常处理函数的地址。其中采用了赋值的形式也是需要注意的,采用的强制类型转换和指针相结合的形式。保证了是修改地址处的内容。而不是修改地址。/*初始化异常中断向量*/void  OS_CPU_InitExceptVect (void)  

37、       /*                   OS_CPU_ARM_EXCEPT_UNDEF_INSTR_VECT_ADDR是对应中断向量表的地址               &#

38、160;   OS_CPU_ARM_INSTR_JUMP_TO_HANDLER是保存了对应的OS_CPU_ARM_INSTR_JUMP_TO_HANDLER(实质上是一个指令)                   实质上就是在异常向量中存放了:LDR PC PC, #0x18,也就是让PC指向对应的异常处理地址中的内容,     

39、;              也就是实现到实际处理函数的跳转。                   异常处理地址中存储了实际的异常处理函数的地址          

40、60;                          其他的异常也有相同的操作,OS_CPU_ARM_INSTR_JUMP_TO_HANDLER是一个指令的机器码形式         */    (*(IN

41、T32U *)OS_CPU_ARM_EXCEPT_UNDEF_INSTR_VECT_ADDR)       =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_UNDEF_INSTR_HANDLER_ADDR)    = (INT32U)OS_CPU_ARM

42、_ExceptUndefInstrHndlr;     (*(INT32U *)OS_CPU_ARM_EXCEPT_SWI_VECT_ADDR)               =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (

43、*(INT32U *)OS_CPU_ARM_EXCEPT_SWI_HANDLER_ADDR)            = (INT32U)OS_CPU_ARM_ExceptSwiHndlr;     (*(INT32U *)OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_VECT_ADDR)    =      

44、   OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_HANDLER_ADDR) = (INT32U)OS_CPU_ARM_ExceptPrefetchAbortHndlr;     (*(INT32U *)OS_CPU_ARM_EXCEPT_DATA_ABORT_VECT_ADDR)      

45、60; =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_DATA_ABORT_HANDLER_ADDR)     = (INT32U)OS_CPU_ARM_ExceptDataAbortHndlr;     (*(INT32U *)OS_CPU_ARM_

46、EXCEPT_ADDR_ABORT_VECT_ADDR)        =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_ADDR_ABORT_HANDLER_ADDR)     = (INT32U)OS_CPU_ARM_ExceptA

47、ddrAbortHndlr;     (*(INT32U *)OS_CPU_ARM_EXCEPT_IRQ_VECT_ADDR)               =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U

48、*)OS_CPU_ARM_EXCEPT_IRQ_HANDLER_ADDR)            = (INT32U)OS_CPU_ARM_ExceptIrqHndlr;          /*在异常向量中存储对应的操作,实质上就是将PC值调转*/    (*(INT32U *)OS_CPU_ARM_EXCEPT_FIQ_VECT_ADD

49、R)               =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_FIQ_HANDLER_ADDR)        &

50、#160;   = (INT32U)OS_CPU_ARM_ExceptFiqHndlr; 异常类型Mode异常向量内容IRQ异常IRQ0x00000018LDR PC,PC,#0x18或者0xE59FF018IFQ异常IFQ0x0000001CLDR PC,PC,#0x180xE59FF018  0x00000038Address of OS_CPU_ARM_ExceptIrqHndlr()  0x0000003CAddress of OS_CPU_ARM_ExceptFiqHndlr()有必要的讨论一下,为什么在

51、向量中存储的是指令: LDR PC,PC,#0x18,我们从上面的地址可以知道,IRQ异常处理函数地址被存储到了0x00000038中,异常向量与该地址之间的差值是0x20,那么为什么在其中存储的值只是0x18呢?这还要讨论ARM的流水线结构,当前执行的命令相比PC指向的地址差0x08。也就是当前执行的指令的地址是PC-0x08.当PC指向异常向量以后(取值),还需要等待一个时钟(译码)之后才会被执行(真正意义上的执行操作),而这时PC值已经被更新了。指向了Vector+0x8的位置,因此我们可以知道,当执行向量中的代码时,这时PC=Vector+0x8,而这时相对于固定的0x20-0x08=

52、0x18,这也就是为什么是LDR PC,PC,#0x18,而不是LDR PC,PC,#0x20.采用上面的例子说明IRQ的向量为0x00000018,而设定好的固定地址用来存储对应异常处理函数地址的地址是0x00000038,当CPU执行完PC = 0x00000018以后,还需要译码、才能被执行,这时候PC值已经更新为PC = 0x00000018 + 0x08;这时候固定地址距离PC的相对位置位0x00000038 PC = 0x18,而该地址中保存了IRQ中断的通用处理函数OS_CPU_ARM_ExceptIrqHndlr()的地址,LDR PC,PC,#0x18这条指令是指将PC+0x18地址处的内容加载到PC中,实质上也就完成跳转到异常处理函数的操作。这样处理的好处是因为LDR的加载范围是一个固定值+-32M,我们不能保证异常处理程序的地址刚好在+-32M左右,采用这种LDR PC, ADDR(固定地址)的形式就能实现大范围的跳转操作。       我们仅仅以FIQ中断处理的形式进行讨论,其他的异常有一定的相似性,只是在返回地址上存在差别。这段代码主要是完成寄存器

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论