ARMLinux中断源码分析(2)——中断处理流程_第1页
ARMLinux中断源码分析(2)——中断处理流程_第2页
ARMLinux中断源码分析(2)——中断处理流程_第3页
ARMLinux中断源码分析(2)——中断处理流程_第4页
ARMLinux中断源码分析(2)——中断处理流程_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

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

文档简介

1、ARM Linux中断源码分析(2)中断处理流程ARM支持7类异常中断,所以中断向量表设8个条目,每个条目4字节,共32字节。 异常名称中断向量异常中断模式优先级复位0x0特权模式1未定义的指令0x4未定义指令中止模式6软件中断0x8特权模式6指令预取中止0x0c中止模式5数据访问中止0x10中止模式2保留0x14  外部中断请求IRQ0x18IRQ模式4快速中断请求FIQ0x1cFIQ模式3 回顾第一节所讲的内容,当一个异常或中断发生时,处理器会将PC设置为特定地址,从而跳转到已经初始化好的异常向量表。因此,要理清中断处理流程,先从异常向量表开始。对于

2、ARM Linux而言,异常向量表和异常处理程序都存在arch/arm/kernel/entry_armv.S汇编文件中。vector异常向量表点击(此处)折叠或打开1. .globl    _vectors_start2. _vectors_start:3.     swi    SYS_ERROR04.     b    vector_und + stubs_offset5

3、.     ldr    pc, .LCvswi + stubs_offset6.     b    vector_pabt + stubs_offset7.     b    vector_dabt + stubs_offset8.     b&#

4、160;   vector_addrexcptn + stubs_offset9.     b    vector_irq + stubs_offset 中断入口,vector_irq10.     b    vector_fiq + stubs_offset11.12.     .globl &#

5、160;  _vectors_end13. _vectors_end:vector_irq+stubs_offset为中断的入口点,此处之所以要加上stubs_offset,是为了实现位置无关编程。首先分析一下stubs_offset(宏)是如何计算的:.equ stubs_offset, _vectors_start + 0x200 - _stubs_start在第3节中已经提到,内核启动时会将异常向量表拷贝到 0xFFFF_0000,将异常向量处理程序的 stub 拷贝到 0xFFFF_0200。图5-1描述了异常向量表和异常处理程序搬移前后的内存布局。图5-

6、1 异常向量表和异常处理程序搬移前后对比当汇编器看到B指令后会把要跳转的标签转化为相对于当前PC的偏移量(±32M)写入指令码。由于内核启动时中断向量表和stubs都发生了代码搬移,所以如果中断向量表中仍然写成b vector_irq,那么实际执行的时候就无法跳转到搬移后的vector_irq处,因为指令码里写的是原来的偏移量,所以需要把指令码中的偏移量写成搬移后的。设搬移后的偏移量为offset,如图5-1所示,offset = L1+L2     = 0x200 - (irq_PC_X - _vectors_start_

7、X) + (vector_irq_X - _stubs_start_X)     = 0x200 - (irq_PC - _vectors_start) + (vector_irq - _stubs_start)     = 0x200 - irq_PC + _vectors_start + vector_irq - _stubs_start     = vector_irq + (_vectors_start + 0x200 - _stubs_

8、start) - irq_PC令stubs_offset = _vectors_start + 0x200 - _stubs_start则offset = vector_irq + stubs_offset - irq_PC,所以中断入口点为“b       vector_irq + stubs_offset”,其中减去irq_PC是由汇编器在编译时完成的。vector_irq处理函数在分析vector_irq处理函数之前,先了解一下当一个异常或中断导致处理器模式改变时,ARM处理器内核的处理流程如下图所示:  &

9、#160;     中断刚发生时,处理器处于irq模式。在_stubs_start和_stubs_end之间找到vector_irq处理函数的定义vector_stub irq, IRQ_MODE, 4,其中vector_stub是一个宏(在arch/arm/kernel/entry_armv.S中定义),为了分析更直观,我们将vector_stub宏展开如下:1. /*2.  * Interrupt dispatcher3.  */4.     vector_irq:5.   

10、60; .if 46.     sub    lr, lr, #4 在中断发生时,lr指向最后执行的指令地址加上8。只有在当前指令执行完毕后,才进入中断处理,所以返回地址应指向下一条指令,即(lr-4)处。7.     .endif8.9. 10.      Save r0, lr_<exception> (parent PC) and 

11、;spsr_<exception>11.      (parent CPSR)12.     13.     stmia    sp, r0, lr         保存r0, lr到irq模式下的栈中14.     mrs   

12、0;lr, spsr15.     str    lr, sp, #8        保存spsr到irq模式下的栈中16.17.     18.      Prepare for SVC32 mode. IRQs remain disabled.19.    

13、0;20.     mrs    r0, cpsr 21.     eor    r0, r0, #( IRQ_MODE SVC_MODE) 设置成SVC模式,但未切换22.     msr    spsr_cxsf, r0 保存到spsr_irq中23.24.   &

14、#160; 25.      the branch table must immediately follow this code26.     27.     and    lr, lr, #0x0f lr存储着上一个处理器模式的cpsr值,lr = lr & 0x0f取出用于判断发生中断前是用户态还是核心态的信息,该值用于下面跳转表的索引。28. 

15、0;   mov    r0, sp 将irq模式下的sp保存到r0,作为参数传递给即将调用的_irq_usr或_irq_svc29.     ldr    lr, pc, lr, lsl #2 pc指向当前执行指令地址加8,即跳转表的基址。lr作为索引,由于是4字节对齐,所以lr = lr << 2.30.   &

16、#160; movs    pc, lr branch to handler in SVC mode31.                   当mov指令后加“s”且目标寄存器为pc时,当前模式下的spsr会被复制到cpsr,从而完成模式切换(从irq模式切换到svc模式)并且跳转到pc指向的指令继续执行32. ENDPROC(vect

17、or_irq)33.34.     .long    _irq_usr             0 (USR_26 / USR_32)35.     .long    _irq_invalid          

18、;   1 (FIQ_26 / FIQ_32)36.     .long    _irq_invalid             2 (IRQ_26 / IRQ_32)37.     .long    _irq_svc     &

19、#160;       3 (SVC_26 / SVC_32)38.     .long    _irq_invalid             439.     .long    _irq_invalid   

20、0;         540.     .long    _irq_invalid             641.     .long    _irq_invalid      

21、       742.     .long    _irq_invalid             843.     .long    _irq_invalid        &#

22、160;    944.     .long    _irq_invalid             a45.     .long    _irq_invalid          

23、0;  b46.     .long    _irq_invalid             c47.     .long    _irq_invalid             d48.

24、    .long    _irq_invalid             e49.     .long    _irq_invalid             f_irq_usr如果发生中断前处于用

25、户态则进入_irq_usr,其定义如下(arch/arm/kernel/entry_armv.S): 1. .align    52. _irq_usr:3.     usr_entry 保存中断上下文,稍后分析4.     kuser_cmpxchg_check5. #ifdef CONFIG_TRACE_IRQFLAGS6.     bl    trace_hardirqs_off7

26、. #endif8.     get_thread_info tsk 获取当前进程的进程描述符中的成员变量thread_info的地址,并将该地址保存到寄存器tsk(r9)(在entry-header.S中定义)9. #ifdef CONFIG_PREEMPT 如果定义了抢占,增加抢占数值10.     ldr    r8, tsk, #TI_PREEMPT         获

27、取preempt计数器值11.     add    r7, r8, #1             preempt加1,标识禁止抢占12.     str    r7, tsk, #TI_PREEMPT 将加1后的结果写入进程内核栈的变量中13. #endif14. &

28、#160;   irq_handler 调用中断处理程序,稍后分析15. #ifdef CONFIG_PREEMPT16.     ldr    r0, tsk, #TI_PREEMPT 获取preempt计数器值17.     str    r8, tsk, #TI_PREEMPT 将preempt恢复到中断前的值18.   

29、  teq    r0, r7 比较中断前后preempt是否相等19.     strne    r0, r0, -r0 如果不等,则产生异常(向地址0写入数据)?20. #endif21. #ifdef CONFIG_TRACE_IRQFLAGS22.     bl    trace_hardirqs_on23. #endif24.

30、    mov    why, #0 r8=025.     b    ret_to_user 中断处理完成,恢复中断上下文并返回中断产生的位置,稍后分析26.  UNWIND(.fnend        )27. ENDPROC(_irq_usr)宏定义usr_entry(保护上下文到栈)上面代码中的usr_entry是一个宏定义,主要

31、用于保护上下文到栈中:1. .macro    usr_entry2.  UNWIND(.fnstart    )3.  UNWIND(.cantunwind    )     dont unwind the user space4.     sub    sp, sp, #S_FRAME_SIZE ATPCS中,堆栈

32、被定义为递减式满堆栈,所以首先让sp向下移动#S_FRAME_SIZE(pt_regs结构体size),准备向栈中存放数据。此处的sp是svc模式下的栈指针。5.     stmib    sp, r1 - r126.7.     ldmia    r0, r1 - r38.     add    

33、r0, sp, #S_PC         here for interlock avoidance9.     mov    r4, #-1             "" "" "&quo

34、t; ""10.11.     str    r1, sp         save the "real" r0 copied12.                    

35、;  from the exception stack13.14.     15.      We are now ready to fill in the remaining blanks on the stack:16.     17.      r2 - lr_<exception>, already fixed up for correc

36、t return/restart18.      r3 - spsr_<exception>19.      r4 - orig_r0 (see pt_regs definition in ptrace.h)20.     21.      Also, separately save sp_usr and lr_usr22.

37、    23.     stmia    r0, r2 - r424.     stmdb    r0, sp, lr 将user模式下的sp和lr保存到svc模式的栈中25.26.     27.      Enable the alignment trap 

38、;while in kernel mode28.     29.     alignment_trap r030.31.     32.      Clear FP to mark the first stack frame33.     34.     zero_fp35.     .endm上面

39、的这段代码主要是在填充结构体pt_regs ,在include/asm/ptrace.h中定义:1. struct pt_regs 2.     long uregs18;3. ;4.5. #define ARM_cpsr    uregs166. #define ARM_pc        uregs157. #define ARM_lr       &#

40、160;uregs148. #define ARM_sp        uregs139. #define ARM_ip        uregs1210. #define ARM_fp        uregs1111. #define ARM_r10        uregs

41、1012. #define ARM_r9        uregs913. #define ARM_r8        uregs814. #define ARM_r7        uregs715. #define ARM_r6        uregs616. #defin

42、e ARM_r5        uregs517. #define ARM_r4        uregs418. #define ARM_r3        uregs319. #define ARM_r2        uregs220. #define ARM_r1

43、0;       uregs121. #define ARM_r0        uregs022. #define ARM_ORIG_r0    uregs17usr_entry宏填充pt_regs结构体的过程如图5-2所示,先将r1r12保存到ARM_r1ARM_ip(绿色部分),然后将产生中断时的r0寄存器内容保存到ARM_r0(蓝色部分),接下来将产生中断时的下一条指令地址lr_irq、spsr_i

44、rq和r4保存到ARM_pc、ARM_cpsr和ARM_ORIG_r0(红色部分),最后将用户模式下的sp和lr保存到ARM_sp 和ARM_lr 中。图5-2 usr_entry宏填充pt_regs结构体_irq_svc如果发生中断前处于核心态则进入_irq_svc,其定义如下(arch/arm/kernel/entry_armv.S):1. .align    52. _irq_svc:3.     svc_entry 保存中断上下文4.5. #ifdef CONFIG_TRACE_IRQF

45、LAGS6.     bl    trace_hardirqs_off7. #endif8. #ifdef CONFIG_PREEMPT9.     get_thread_info tsk10.     ldr    r8, tsk, #TI_PREEMPT         获取preempt计数器

46、值11.     add    r7, r8, #1             preempt加1,标识禁止抢占12.     str    r7, tsk, #TI_PREEMPT 将加1后的结果写入进程内核栈的变量中13. #endif14.15.  

47、60;  irq_handler 调用中断处理程序,稍后分析16. #ifdef CONFIG_PREEMPT17.     str    r8, tsk, #TI_PREEMPT         恢复中断前的preempt计数器18.     ldr    r0, tsk, #TI_FLAGS&#

48、160;        获取flags19.     teq    r8, #0                 判断preempt是否等于020.     movne    r0, #0&

49、#160;                如果preempt不等于0,r0=021.     tst    r0, #_TIF_NEED_RESCHED 将r0与#_TIF_NEED_RESCHED做“与操作”22.     blne    svc_preempt 如果不等于0,

50、说明发生内核抢占,需要重新调度。23. #endif24.25.     ldr    r0, sp, #S_PSR         irqs are already disabled26.     msr    spsr_cxsf, r027. #ifdef CONFIG_TRACE_IRQFLAGS28.  

51、60;  tst    r0, #PSR_I_BIT29.     bleq    trace_hardirqs_on30. #endif31.     svc_exit r4     恢复中断上下文,稍后分析。32.  UNWIND(.fnend        )33. END

52、PROC(_irq_svc)宏定义svc_entry(保护中断上下文到栈)其中svc_entry是一个宏定义,主要用于保护中断上下文到栈中。svc_entry主要是在当前堆栈上分配一个pt_regs结构,把r0-r15以及cpsr等保存到这个结构中,在进入irq_handler时,sp指向pt_regs底端:1. .macro    svc_entry, stack_hole=02.  UNWIND(.fnstart        )3.  UN

53、WIND(.save r0 - pc        )4.     sub    sp, sp, #(S_FRAME_SIZE + stack_hole)5.  SPFIX(    tst    sp, #4      

54、  )6.  SPFIX(    bicne    sp, sp, #4    )7.     stmib    sp, r1 - r128.9.     ldmia    r0, r1 - r310. 

55、60;   add    r5, sp, #S_SP         here for interlock avoidance11.     mov    r4, #-1            

56、60;"" "" "" ""12.     add    r0, sp, #(S_FRAME_SIZE + stack_hole)13.  SPFIX(    addne    r0, r0, #4    )14. &#

57、160;   str    r1, sp         save the "real" r0 copied15.                      from the exception st

58、ack16.17.     mov    r1, lr18.19.     20.      We are now ready to fill in the remaining blanks on the stack:21.     22.      r0 - sp_svc23.   &#

59、160;  r1 - lr_svc24.      r2 - lr_<exception>, already fixed up for correct return/restart25.      r3 - spsr_<exception>26.      r4 - orig_r0 (see pt_regs definiti

60、on in ptrace.h)27.     28.     stmia    r5, r0 - r429.     .endmsvc_entry宏填充pt_regs结构体的过程如图5-2所示,先将r1r12保存到ARM_r1ARM_ip(绿色部分),然后将产生中断时的r0寄存器内容保存到ARM_r0(蓝色部分),由于是在svc模式下产生的中断,所以最后将sp_svc、lr_svc、lr

61、_irq、spsr_irq和r4保存到ARM_sp、ARM_lr、ARM_pc、ARM_cpsr和ARM_ORIG_r0(红色部分)。图5-3 svc_entry宏填充pt_regs结构体上述的中断上下文保存过程共涉及了3种栈指针,分别是:用户空间栈指针sp_usr,内核空间栈指针sp_svc和irq模式下的栈栈指针sp_irq。sp_usr指向在setup_arg_pages函数中创建的用户空间栈。sp_svc指向在alloc_thread_info函数中创建的内核空间栈。sp_irq在cpu_init函数中被赋值,指向全局变量stacks.irq0。附录1,arm体系下pt_regs结构s

62、truct pt_regs long uregs18;uregs0 - uregs17分别对应,r0 - r15,cpsr,ORIG_r0附录1,irq中断时堆栈的变化-spsr-lr ,中断返回地址,修正后的-r0- <-进入irq_svc之前,sp的值,也是r0的值pt_regs- <-进入svc_entry后,sp的值irq_handler(中断处理程序)保存中断上下文后则进入中断处理程序irq_handler,定义在arch/arm/kernel/entry_armv.S文件中:1. .macro    irq_handle

63、r2.     get_irqnr_preamble r5, lr 3. 1:    get_irqnr_and_base r0, r6, r5, lr 获取中断号,存到r0中,稍后分析4.     movne    r1, sp 如果中断号不等于0,将r1=sp,即pt_regs结构体首地址5.     6.   &

64、#160;  routine called with r0 = irq number, r1 = struct pt_regs *7.     8.     adrne    lr, 1b 如果r0(中断号)不等于0, lr(返回地址)等于标号1处,即get_irqnr_and_base r0, r6, r5, lr的那行,即循环处理所有的中断。9. 

65、60;   bne    asm_do_IRQ 进入中断处理,稍后分析。10. 11.     .endmget_irqnr_and_base用于判断当前发生的中断号(与CPU紧密相关),此处不再分析。如果获取的中断号不等于0,则将中断号存入r0寄存器作为第一个参数,pt_regs结构体地址存入r1寄存器作为第二个参数,跳转到c语言函数asm_do_IRQ做进一步处理。为了不让大家在汇编语言和C语言之间来回切换,还是先把最后一点汇编语言代码(中断返回汇编代码)分析了再去分析asm_do

66、_IRQ吧。回看_irq_usr和_irq_svc标号处的代码,在完成了irq_handler中断处理函数后,要完成从中断异常处理程序返回到中断点的工作。ret_to_user如果中断产生于用户空间,则调用ret_to_user来恢复中断现场并返回用户空间继续运行:1. arch/arm/kernel/entry_armv.S2. ENTRY(ret_to_user)3. ret_slow_syscall:4.     disable_irq     disable interrupts,此处不明白,disable

67、_irq应该接受irq中断号作为参数,来禁止指定的irq号中断线。但是此处调用disable_irq之前并没有将irq中断号存入r0寄存器,这是为什么?5.     ldr    r1, tsk, #TI_FLAGS 获取thread_info->flags6.     tst    r1, #_TIF_WORK_MASK 判断是否有待处理的work7.    

68、 bne    work_pending 如果有,则进入work_pending进一步处理,主要是完成用户进程抢占相关处理。8. no_work_pending: 如果没有work待处理,则准备恢复中断现场,返回用户空间。9.     /* perform architecture specific actions before user return */10.     arch_ret_to_user r1, lr 调用体

69、系结构相关的代码11.12.     restore_user_regs fast = 0, offset = 0 调用restore_user_regs13. ENDPROC(ret_to_user)14.15. 以下是恢复中断现场寄存器的宏,就是将发生中断时保存在内核空间堆栈上的寄存器还原,可以对照图5-2所示的内核空间堆栈保存的内容来理解下面代码:16. .macro    restore_user_regs, fast = 0,

70、 offset = 017.     ldr    r1, sp, #offset + S_PSR     从内核栈中获取发生中断时的cpsr值18.     ldr    lr, sp, #offset + S_PC!     从内核栈中获取发生中

71、断时的下一条指令地址19.     msr    spsr_cxsf, r1             将r1保存到spsr_svc20. #if defined(CONFIG_CPU_32v6K)21.     clrex          

72、;           clear the exclusive monitor22. #elif defined (CONFIG_CPU_V6)23.     strex    r1, r2, sp             clear the exclusive mon

73、itor24. #endif25.     .if    fast26.     ldmdb    sp, r1 - lr     get calling r1 - lr27.     .else28.     ldmdb    

74、sp, r0 - lr 存在,所以将内核栈保存的内容恢复到用户空间的r0lr寄存器29.     .endif30.     add    sp, sp, #S_FRAME_SIZE - S_PC 31.     movs    pc, lr    将发生中断时的下一条

75、指令地址存入pc,从而返回中断点继续执行,并且将发生中断时的cpsr内容恢复到cpsr寄存器中(开启中断)。32.     .endmsvc_exit如果中断产生于内核空间,则调用svc_exit来恢复中断现场:1. arch/arm/kernel/ entry-header.S2. .macro    svc_exit, rpsr3.     msr    spsr_cxsf, rpsr4. #if de

76、fined(CONFIG_CPU_32v6K)5.     clrex                     clear the exclusive monitor6.     ldmia    sp, r0 - pc  

77、60;          load r0 - pc, cpsr7. #elif defined (CONFIG_CPU_V6)8.     ldr    r0, sp9.     strex    r1, r2, sp     &

78、#160;       clear the exclusive monitor10.     ldmib    sp, r1 - pc             load r1 - pc, cpsr11. #else12.     ldmia

79、    sp, r0 - pc             返回内核空间时,恢复中断现场比较简单,就是将r0-pc以及cpsr恢复即可,同时中断也被开启。13. #endif14.     .endmasm_do_IRQ函数ok,分析完所有与中断相关的汇编语言代码后,下面开始分析C语言代码:在arch/arm/kernel/irq.c文件中找到asm_do_IRQ函数定义

80、:1. asmlinkage void _exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)2. 3.     /*保存新的寄存器集合指针到全局cpu变量,方便后续处理程序访问寄存器集合。*/4.     struct pt_regs *old_regs = set_irq_regs(regs); 5.6.    &#

81、160;irq_enter();7.8.     /*9.      * Some hardware gives randomly wrong interrupts. Rather10.      * than crashing, do something sensible.11.      */12.     if 

82、(unlikely(irq >= NR_IRQS)  /判断中断号13.         if (printk_ratelimit()14.             printk(KERN_WARNING "Bad IRQ%un", irq);15.      &

83、#160;  ack_bad_irq(irq);16.      else 17.         generic_handle_irq(irq); /调用中断处理函数18.     19.20.     /* AT91 specific workaround */21.     irq_

84、finish(irq);22.23.     irq_exit();24.     set_irq_regs(old_regs);25. asm_do_IRQ是中断处理的C入口函数,主要负责调用request_irq注册的中断处理函数,其流程如图5-4所示:图5-4 asm_do_IRQ流程1、old_regs = set_irq_regs(regs)其中,set_irq_regs将指向寄存器结构体的指针保存在一个全局的CPU变量中,后续的程序可以通过该变量访问寄存器结构体。所以在进入中断处理前

85、,先将全局CPU变量中保存的旧指针保留下来,等到中断处理结束后再将其恢复。2、irq_enterirq_enter负责更新一些统计量:1. <kernel/softirq.c>2. void irq_enter(void)3. 4.     int cpu = smp_processor_id();5.6.     rcu_irq_enter();7.     if (idle_cpu(cpu) &&

86、; !in_interrupt() 8.         _irq_enter();9.         tick_check_idle(cpu);10.      else11.         _irq_enter();12. 如果系统开启动态时钟特性且很长时间没有产生时钟中断,则调用

87、tick_check_idle更新全局变量jiffies(关于动态时钟特性,在后续的总结中再进行分析)。宏_irq_enter()定义如下:1. #define _irq_enter()                    2.     do         

88、0;               3.         account_system_vtime(current);        4.         add_preempt_count(HARDIRQ_OF

89、FSET);    5.         trace_hardirq_enter();            6.      while (0)add_preempt_count(HARDIRQ_OFFSET)使表示中断处理程序嵌套层次的计数器加1。计数器保存在当前进程thread_info结构的p

90、reempt_count字段中:图5-5 preempt_count结构内核将preempt_count分成5部分:bit07与PREEMPT相关,bit815用作软中断计数器,bit1625用作硬中断计数器,bit26用作不可屏蔽中断计数器,bit28用作PREEMPT_ACTIVE标志。3、generic_handle_irqgeneric_handle_irq是体系结构无关函数,用来调用desc->handle_irq,该函数指针在中断初始化时指向了电流处理函数(handle_level_irq或handle_edge_irq),针对不同的中断触发类型(边沿触发或电平触发)做相应的

91、处理。然后调用handle_IRQ_event遍历action链表从而调用该中断号对应的一个或多个中断处理程序action->handler,而action->handler就是通过request_irq初始化的。handle_level_irq首先分析一下handle_level_irq函数:1. <kernel/irq/chip.c>2. void handle_level_irq(unsigned int irq, struct irq_desc *desc)3. 4.     str

92、uct irqaction *action;5.     irqreturn_t action_ret;6.7.     spin_lock(&desc->lock); /*访问desc内容之前先加自旋锁*/8.     mask_ack_irq(desc, irq); /*屏蔽与irq号对应的中断线 */9.10. /* 在多处理器系统上,为了避免多cpu同时处理同一中断。11. *当desc->

93、;status包含IRQ_INPROGRESS标志时,说明该中断12. *正在另一个cpu上处理,因此当前cpu可以直接放弃处理。13. */14.     if (unlikely(desc->status & IRQ_INPROGRESS) 15.         goto out_unlock;16.     desc->status &= (

94、IRQ_REPLAY | IRQ_WAITING);17.     kstat_incr_irqs_this_cpu(irq, desc);18.19.     /*20.      *如果没有对该中断注册处理程序,即desc->action为NULL。21.      * 或者desc->status设置为IRQ_DISABLED,表示该中断是被禁止的。22. &

95、#160;    * 以上两种情况只要出现一种即可放弃处理。23. */24.     action = desc->action;25.     if (unlikely(!action | (desc->status & IRQ_DISABLED)26.         goto out_unl

96、ock;27.28.     desc->status |= IRQ_INPROGRESS; /*标识中断状态为正在处理*/29.     spin_unlock(&desc->lock); /*释放自旋锁*/30.31.     /*调用由request_irq注册的处理函数,稍后分析。*/32.     action_ret = handle_IRQ_e

97、vent(irq, action); 33.     if (!noirqdebug)34.         note_interrupt(irq, desc, action_ret);35.36.     spin_lock(&desc->lock); /*访问desc内容前加自旋锁*/37.     desc->s

98、tatus &= IRQ_INPROGRESS; /*清除“正在处理”的标识*/38.39. /*如果desc->status 包含IRQ_ONESHOT,40. *则将desc->status设置为IRQ_MASKED,使该中断仍处于被屏蔽状态。 */41.     if (unlikely(desc->status & IRQ_ONESHOT) 42.        &

99、#160;desc->status |= IRQ_MASKED;43. /*如果中断处理函数中未对desc->status 设置为IRQ_ DISABLED,44. *且desc->chip->unmask不为空,则desc->chip->unmask所指向的芯片相关函数,45. *解除对该中断的屏蔽。 46. */47.     else if (!(desc->status & IRQ_DISABLED) &&am

100、p; desc->chip->unmask)48.         desc->chip->unmask(irq);49. out_unlock:50.     spin_unlock(&desc->lock); /*释放自旋锁*/51. handle_edge_irq再来介绍一下handle_edge_irq函数,相对于handle_level_irq要复杂一点:1. <kernel/irq/chip.c>

101、;2. void handle_edge_irq(unsigned int irq, struct irq_desc *desc)3. 4.     spin_lock(&desc->lock);5.     desc->status &= (IRQ_REPLAY | IRQ_WAITING);6.     /*7.     &#

102、160;* 如果该中断正在被其他cpu处理,或者是该中断已被禁止,8.      * 则不处理该中断,但要将其标识为pending状态且屏蔽该中断以便后续处理9.      */10.     if (unlikely(desc->status & (IRQ_INPROGRESS | IRQ_DISABLED) |11.    

103、60;     !desc->action) 12.         desc->status |= (IRQ_PENDING | IRQ_MASKED);13.         mask_ack_irq(desc, irq);14.         goto

温馨提示

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

评论

0/150

提交评论