12749|50

79

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

关于ARM中断处理的问题----《ARM嵌入式系统开发-软件设计与优化》第九章中疑问 [复制链接]

各位过年好哦~
呵呵,小弟这里有点疑惑相同大家讨论讨论~,这个问题是《ARM嵌入式系统开发-软件设计与优化》一书中的见下:

第九章-中断处理
9.3.2嵌套中断
在这一节中,描述了如何处理嵌套式的中断(不能单纯的在IRQ模式下打开中断允许位),作者介绍是从IRQ模式切换到SVC模式中去处理中断,并且一如了Stack Frame的用法,书中也有相关的一点代码,对这段代码有点疑问:


  1. Maskmd EQU 0x1f ; processor mode mask
  2. SVC32md EQU 0x13 ; SVC mode
  3. I_Bit EQU 0x80 ; IRQ bit

  4. FRAME_R0 EQU 0x00
  5. FRAME_R1 EQU FRAME_R0+4
  6. FRAME_R2 EQU FRAME_R1+4
  7. FRAME_R3 EQU FRAME_R2+4
  8. FRAME_R4 EQU FRAME_R3+4
  9. FRAME_R5 EQU FRAME_R4+4
  10. FRAME_R6 EQU FRAME_R5+4
  11. FRAME_R7 EQU FRAME_R6+4
  12. FRAME_R8 EQU FRAME_R7+4
  13. FRAME_R9 EQU FRAME_R8+4
  14. FRAME_R10 EQU FRAME_R9+4
  15. FRAME_R11 EQU FRAME_R10+4
  16. FRAME_R12 EQU FRAME_R11+4
  17. FRAME_PSR EQU FRAME_R12+4
  18. FRAME_LR EQU FRAME_PSR+4
  19. FRAME_PC EQU FRAME_LR+4
  20. FRAME_SIZE EQU FRAME_PC+4

  21. IRQ_Entry ; instruction state : comment
  22. SUB r14,r14,#4 ; 2 :
  23. STMDB r13!,{r0-r3,r12,r14} ; 2 : save context
  24.    
  25. BL read_RescheduleFlag ; 3 : more processing
  26. CMP r0,#0 ; 3 : if processing?
  27. LDMNEIA r13!,{r0-r3,r12,pc}? ; 4 : else return
  28. MRS r2,spsr ; 5 : copy spsr_irq
  29. MOV r0,r13 ; 5 : copy r13_irq
  30. ADD r13,r13,#6*4 ; 5 : reset stack
  31. MRS r1,cpsr ; 6 : copy cpsr
  32. BIC r1,r1,#Maskmd ; 6 :
  33. ORR r1,r1,#SVC32md ; 6 :
  34. MSR cpsr_c,r1 ; 6 : change to SVC
  35. SUB r13,r13,#FRAME_SIZE-FRAME_R4 ; 7 : make space
  36. STMIA r13,{r4-r11} ; 7 : save r4-r11
  37. LDMIA r0,{r4-r9} ; 7 : restore r4-r9
  38. BIC r1,r1,#I_Bit ; 8 :
  39. MSR cpsr_c,r1 ; 8 : enable IRA
  40. STMDB r13!,{r4-r7} ; 9 : save r4-r7 SVC
  41. STR r2,[r13,#FRAME_PSR] ; 9 : save PSR
  42. STR r8,[r13,#FRAME_R12] ; 9 : save r12
  43. STR r9,[r13,#FRAME_PC] ; 9 : save pc
  44. STR r14,[r13,#FRAME_LR] ; 9 : save lr

  45. LDMIA r13!,{r0-r12,r14} ; 11 : restore context
  46. MSR spsr_cxsf,r14 ; 11 : restore spsr
  47. LDMIA r13!,{r14,pc}? ; 11 : return
复制代码


为什么要在Frame Stack未创建完成时打开中断呢?此时r4-r7,r2,r8,r9,r14都还没保存,如果有中断发生,岂不是会覆盖这么寄存器(重要的是会覆盖r9)导致中断服务程序不能正常返回。

各位有何高见~
此帖出自ARM技术论坛

最新回复

好东西 值得品味啊   详情 回复 发表于 2010-4-22 16:06
点赞 关注
 

回复
举报

87

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
哎,没有人回答?
我先顶,洗个澡,看书再回。
此帖出自ARM技术论坛
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
引用楼主 friendfish 的帖子:
为什么要在Frame Stack未创建完成时打开中断呢?


哪里打开了?

我刚才看了一下,没有发现什么问题啊。对于这个章节,我只看过一点点。

看来有空好好看看,
留到看wince内核的时候吧。
此帖出自ARM技术论坛
 
 
 

回复

70

帖子

0

TA的资源

一粒金砂(初级)

4
 
引用 2 楼 gooogleman 的回复:
哪里打开了?

    MSR cpsr_c,r1 ; 8 : enable IRA
这里打开了,上面说的Frame Stack为创建成功,是因为,打开中断后才进行对r4-r7,r2,r8,r9,r14的保存

  1.     STMDB  r13!,  {r4-r7}            ; 9 : save r4-r7 SVC
  2.     STR    r2,    [r13,#FRAME_PSR]   ; 9 : save PSR
  3.     STR    r8,    [r13,#FRAME_R12]   ; 9 : save r12
  4.     STR    r9,    [r13,#FRAME_PC]    ; 9 : save pc
  5.     STR    r14,   [r13,#FRAME_LR]    ; 9 : save lr
复制代码
此帖出自ARM技术论坛
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

5
 
学习下。底层中断的实现真的还没有仔细研究过。都飘在上层做东西。。。
此帖出自ARM技术论坛
 
 
 

回复

108

帖子

0

TA的资源

一粒金砂(中级)

6
 
引用 3 楼 friendfish 的回复:
引用 2 楼 gooogleman 的回复:
哪里打开了?

    MSR cpsr_c,r1 ; 8 : enable IRA

对于这句,我觉得仅仅是使能了cpsr的IRQ的中断,但是如果ARM的中断寄存器没有使能也是不能产生实际的中断的,
以前我也没有考虑这个问题,通常这个东西都是wince自己弄好了,我们只是设置了ARM的寄存器而已,等搞完手头上的活儿,我回去好好看看
大伙儿有什么意见发表一下啊。

这里打开了,上面说的Frame Stack为创建成功,是因为,打开中断后才进行对r4-r7,r2,r8,r9,r14的保存

Assembly code
    STMDB  r13!,  {r4-r7}            ; 9 : save r4-r7 SVC
    STR    r2,    [r13,#FRAME_PSR]   ; 9 : save PSR
    STR    r8,    [r13,#FRAME_R12]   ; 9 : save r12
    STR    r9,    [r13,#FRAME_PC]  …
此帖出自ARM技术论坛
 
 
 

回复

85

帖子

0

TA的资源

一粒金砂(初级)

7
 
引用 5 楼 gooogleman 的回复:
对于这句,我觉得仅仅是使能了cpsr的IRQ的中断,但是如果ARM的中断寄存器没有使能也是不能产生实际的中断的,


是这样的,书中讲的是如何处理中断,对于这一节中嵌套中断的处理,时能CPSR的IRQ位即是打开中断,为什么要使用栈帧,原因是这样的,ARM在IRQ中断引发时,并不进行压栈动作,只是简单的将PC值赋为中断向量位置地址,将返回值赋值给R14,注意此时返回地址并没有压栈,只是在R14中,如果在中断处理程序中使用BL指令,那么R14的值将会被覆盖,这样中断返回的地址变为BL指令调用函数的返回地址,这就会导致中断程序不能正确返回(因为中断返回地址被破坏了),所以要使用嵌套中断不能简单的在IRQ模式中将CPSR的IRQ位打开,而要使用Stack Frame,并且切换到SVC(系统模式)模式,因为此时使用的R14是系统模式下的R14(R14_SVC)。

现在的问题就出在,在将模式切换到系统模式并且将原来IRQ堆栈中的内容保存到系统模式的堆栈上,在打开中断钱前,并没有将原来IRQ堆栈中的重要寄存器保存(r4_svc-r7_svc,r2_svc,r8_svc,r9_svc,r14_svc,),如果此时有中断产生,那么r4_svc-r7_svc,r2_svc,r8_svc,r9_svc,r14_svc(r9_svc对应的是IRQ堆栈中保存中断返回地址的R14_irq,),这些寄存器的值将被覆盖,这样,中断又不能正常返回了。
此帖出自ARM技术论坛
 
 
 

回复

71

帖子

0

TA的资源

一粒金砂(初级)

8
 
对于这个问题,我今晚我再回去看看,我刚才看有些书是说 不必备份和恢复,这个我也纳闷
此帖出自ARM技术论坛
 
 
 

回复

85

帖子

0

TA的资源

一粒金砂(初级)

9
 
引用 7 楼 gooogleman 的回复:
对于这个问题,我今晚我再回去看看,我刚才看有些书是说 不必备份和恢复,这个我也纳闷


应该不会吧,ARM没有自动压栈的操作啊,用BL调用函数时都没有压栈,要在汇编里使用函数嵌套调用的话,必须自己建立栈帧(Stack Frame)否则不能正常返回。
此帖出自ARM技术论坛
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

10
 
学习
此帖出自ARM技术论坛
 
 
 

回复

66

帖子

0

TA的资源

一粒金砂(初级)

11
 
引用 4 楼 xumercury 的回复:
学习下。底层中断的实现真的还没有仔细研究过。都飘在上层做东西
DDDDDDDD
此帖出自ARM技术论坛
 
 
 

回复

67

帖子

0

TA的资源

一粒金砂(初级)

12
 
jf
此帖出自ARM技术论坛
 
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

13
 
mark
此帖出自ARM技术论坛
 
 
 

回复

83

帖子

0

TA的资源

一粒金砂(初级)

14
 
mark
此帖出自ARM技术论坛
 
 
 

回复

64

帖子

0

TA的资源

一粒金砂(初级)

15
 
楼主
看来你对ARM的结构还不是很了解
ARM的寄存器有一些是专门在中断下使用的
貌似会自动备份其他寄存器的内容。
等中断返回时再回复。
这样你根本不需要压栈就行。
具体的要仔细看书
我很久没弄ARM的东西了
不能很肯定。
此帖出自ARM技术论坛
 
 
 

回复

67

帖子

0

TA的资源

一粒金砂(初级)

16
 
我同意楼上观点,在某些中断模式是不用备份和恢复的,可以实现快速中断,记得FIQ就是这样的。
此帖出自ARM技术论坛
 
 
 

回复

63

帖子

0

TA的资源

一粒金砂(初级)

17
 
UP
此帖出自ARM技术论坛
 
 
 

回复

61

帖子

0

TA的资源

一粒金砂(初级)

18
 
DING
此帖出自ARM技术论坛
 
 
 

回复

79

帖子

0

TA的资源

一粒金砂(初级)

19
 
引用 14 楼 ubiquitious 的回复:
楼主
看来你对ARM的结构还不是很了解
ARM的寄存器有一些是专门在中断下使用的
貌似会自动备份其他寄存器的内容。
等中断返回时再回复。
这样你根本不需要压栈就行。
具体的要仔细看书
我很久没弄ARM的东西了
不能很肯定。

了解不了解ARM的结构,恩,我们先来做个测试~
这里我们将使用IA32体系结构和ARM结构做比较,目的是做CISC(IA32,虽然IA32不是纯粹的CISC)结构和RISC(ARM)结构的比较。
问题1.--->子程序的调用指令在IA32中和ARM中有什么区别?
注:IA32中子程序调用指令是CALL,ARM中为BL。
答案区(反选可见):

IA32中子程序调用指令CALL的描述为
Saves procedure linking information on the stack and branches to the called procedure specofoed using the target operand.(参见Intel 64 and IA32 Architectures Software Developer's Manual-Volume 2A: Instruction set Reference, A-M page3-86)
即先将返回地址存入堆栈,然后跳转到指定标号地址处。


ARM中子程序调用指令BL:
跳转到指定的标号,并且将返回地址保存到R14中。(此处参考ARM Architecture Reference Manual-page110)

比较上述两条指令
相同处:都保存了返回地址.
不同处:
    执行的动作不一样,CALL指令有三个动作:
    1.改变堆栈指针;
    2.返回地址压栈;
    3.修改PC值;
   
    BL指令指令只有两个动作:
    1.保存返回地址到R14(此处应对应R14_USR,在USER模式下执行);
    2.修改PC值;



问题2.--->子程序的返回指令在IA32中和ARM中有什么区别?
注:IA32中子程序返回指令是RET,ARM中没有与之对应的指令。
答案区(反选可见):

IA32中子程序返回指令RET的描述
Transfers program control to a return address located on the top of the stack.The address is usually placed on the stack bu a CALL instruction, and the return is made to the instruction that follows the CALL instruction.(参见Intel 64 and IA32 Architectures Software Developer's Manual-Volume 2B: Instruction set Reference, N-Z page4-253)

ARM中子程序返回的描述:
ARM中没有相应的返回指令,要实现从子程序返回,要手动进行对PC的修改。


现在我们引入一个问题,恩,一个小问题,关于子程序嵌套的问题,(不知各位在上面的描述中看出什么杀机没有),现在分开说:
1.IA32中子程序嵌套
很简单,不需有过多的考虑,在子程序中要直接利用CALL指令调用即可,唯一的限制就是堆栈的大小,因为每次调用都会有压栈动作,一般来说堆栈很大,但也不排除由于子程序嵌套调用而引发的堆栈溢出问题,这一点要在设计之初要考虑到。

2.ARM中子程序嵌套
恩,这个么,有点棘手,首先我们来看看如果向IA32中的方法一样来处理子程序嵌套的问题,那么会怎样呢?
举个例子:

  1. ADR  
  2.         entry;        program entry
  3. 0x0000        
  4. 0x***X        BL PROC1;      调用子程序1
  5. 0x***X+4      MOV R0,R1;    一条位于子程序调用后的指令
  6. 0x***X+8      
  7.       
  8.         PROC1;        子程序1
  9. 0x***Y        
  10. 0x***Z        BL PROC2;       调用子程序2
  11. 0x***Z+4      MOV R0,R1;     一条位于子程序调用后的指令
  12. 0x***Z+8      ;    包含了返回的操作


  13.         PROC2;        子程序1
  14. 0x***A        
  15. 0x***B        BL PROC2;       调用子程序2
  16. 0x***C+4      MOV R0,R1;     一条位于子程序调用后的指令
  17. 0x***C+8       ;   包含了返回的操作
复制代码

上面的代码能正确的返回么?能返回到地址“0x***X+8”处么?
很明显不能,为什么呢,大家应该看得出来,原因很简单因为第二次的BL调用破坏了第一次BL调用的返回地址。那么为了处理这个问题,Frame Stack栈帧就被引入了,所以我们用C语言对ARM进行开发的时候不用去关心这些问题,编译器应经帮我们做了。换句话说,引入栈帧就是为了保存返回地址等重要的信息,怎么保存,当然是在堆栈里保存了,由于ARM没有自动的堆栈操作,所以编译器帮我们做了。


好,现在我们说回来,说说本帖要讨论的问题-在ARM中如何处理嵌套式
注:我们在这里仅考虑IRQ中断
在ARM中,中断一旦被相应,则CPSR中的相应的中断禁止位就被置起来了,此时不能相应中断,为了提高系统的性能,我们可能需要处理嵌套式的中断,也就是说我们需要在处理一个中断的同时需要让系统响应中断。
该怎么做?
在中断中开启CPSR的中断禁止位(清零)?

ARM在相应中断后,自动的动作有:(假设是在USER模式中相应IRQ中断)
1.将返回地址保存到R14_irq;
2.保存CPSR到SPSR_irq;
3.切换到IRQ模式;
4.禁止IRQ中断

注意了哦,此时只是将返回地址保存到R14_irq,而没有压栈保存哦~
如果我们为了处理嵌套中断,只是简单的在IRQ模式中打开中断,那么,很可怕哦,原因是如果打开中断,在处理第一个中断的时候如果有第二个中断被相应,那么,此时的R14_irq将被破坏,导致程序崩溃。
为什么会崩溃,举个例子:(此例是没有保存R14_irq的例子)

  1. ADR
  2.             IRQ entry;        IRQ中断处理入口
  3. 0x***X      ;      一些代码,不包含保存R14_irq的处理,最后一条指令是开中断
  4. 0x***Y      MOV R0,R1;        打开中断后的一条指令
  5. 0x***Y+4    MOV R2,R0;        打开中断后的二条指令
  6. 0x***Y+8    ;      一些代码,最后一条指令是返回LDR PC,R14^,将会返回到USER模式

复制代码

上面的代码,如果中断发生在打开中断后,执行返回指令前,假设发生在执行“0x***Y”处的代码,那么由于此时CPU位于IRQ模式,IRQ中断又被打开了,那么R14_irq的值将被破坏为“0x***Y+4”,在第二个中断执行到返回指令时,将会返回到“0x***Y+4”这样,继续执行下去,到返回指令处,继续返回“0x***Y+4”不能正常返回。

这样,我们引入了第一个问题,在处理中断时,压栈是要考虑的,在进入IRQ中断的时候,第一个就是要压栈保存重要寄存器。
下来我们在进一步,如果代码变成这个样子会怎么样:

  1. ADR
  2.             IRQ entry;        IRQ中断处理入口
  3. 0x***X      ;      一些代码,包含保存R14_irq等的处理,最后一条指令是开中断
  4. 0x***Y      BL PROC1;         调用子程序1
  5. 0x***Y+4    MOV R2,R0;       打开中断后的二条指令
  6. 0x***Y+8    ;      一些代码,最后一条指令是返回LDR PC,R14^,将会返回到USER模式、

  7.         PROC1;        子程序1
  8. 0x***Z        
  9. 0x***C        MOV R2,R0;     
  10. 0x***C+4      MOV R0,R1;     一条位于子程序调用后的指令
  11. 0x***C+8      ;    包含了返回的操作

复制代码

我们假设此时有中断发生(我们称第一次中断),那么程序将跳转到IRQ entry处处理,然后再IRQ模式中打开中断,然后调用子程序动作发生,程序跳转到“0x***Z”处,R14_irq变为“0x***Y+4”。假设中断(我们称第二次中断)发生在“0x***C”处代码执行完后,由于此时位于IRQ模式,R14_irq变为“0x***C+4”在第二次中断完成返回后,程序返回到“0x***Y+4”处,接着子程序1的处理,直到子程序返回指令执行,这时程序又返回到“0x***Y+4”这样,子程序不能正确返回。

为什么会发生这样的情况?是因为子程序的返回地址被异步的中断破坏了,即使我们在子程序中考虑建立栈帧(在子程序里建立栈帧我们上面讨论过,是为了解决函数嵌套调用),也不能保证R14_irq不被破坏,因为中断可能发生在栈帧为建立好之前。
为了解决这个问题,有两种方法:
1.在中断处理中不使用BL
2.切换模式

1.在中断处理中不使用BL
原因很简单,不想因为子程序的引入而破坏系统的稳定,但是这样未免有点严格。

2.切换模式
切换模式,恩,是个好方法,不过有点复杂,基本思想就是在打开中断之前,将CPU模式切换至其他模式我们以SVC模式为例。
在带开中断之前,切换到SVC模式,此时的R14变为R14_svc,由于中断的处理在SVC模式里了,那么原来IRQ模式下保存的内容也要转移到SVC模式,那么这里再次引入栈帧,将原来IRQ模式下的内容保存到SVC模式下。
这样,及时在开中断后有BL的调用,并且中断发生在BL调用后,也不会影响正确的返回地址,因为BL的返回地址保存在R14_svc中,而中断的响应会将返回地址保存至R14_irq中,这样,一切都正常了~~



现在回顾下我的问题,也是这篇帖子的主题,在1楼的代码中,切换至SVC模式后,在栈帧没有创建完的情况下,中断被打开了,所以我产生了疑惑,特来跟大家讨论~

写了这么多,承蒙大家的支持,希望能把这个问题解决掉,早日结贴~~
呵呵~拜大家~

此帖出自ARM技术论坛
 
 
 

回复

71

帖子

0

TA的资源

一粒金砂(初级)

20
 
不要过早下结论,书写的未必是对的,运行起来的才是对的。

我在wince 的内核的ARM汇编部分看了,这些保护都有。

ARM汇编调用C语言程序使用了CALL

至于为什么不用BL,我想估计是参数传递的问题。

BL仅仅是有LR保存现场,CALL估计使用了R0~R3传递参数,并使用栈保存了现场。

至于具体原因,等我搞定了我的串口再分析。
此帖出自ARM技术论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表