arm_exc_interrupt 函数的执行流程解析(RTEMS)

 

arm_exc_interrupt 函数的执行流程解析(RTEMS)

作者:zhousm    2015.12.09

 

处理器:S3C2440A  ARM9

操作系统:RTEMS-4.10.2

源码路径:rtems-4.10.2/cpukit/scorte/cpu/arm/arm_exc_interrupt.s

当发生IRQ中断时,直接跳转到arm_exc_interrupt处开始执行,下面将对其指令执行流程注解。本人为RTEMS初学者,错误的地方请多多指教,联系方式见个人资料。

  1 .globl arm_exc_interrupt                                      /* 当发生IRQ中断时,跳转到此函数开始执行 */
  2 arm_exc_interrupt:
3 4 /* Save exchange registers to exchange area */ 5 stmdb sp, EXCHANGE_LIST /* [sp] <- r4,r5,r6,r7 | 将R4,R5,R6,R7存入IRQ堆栈,接下来R4-R7将被作为交换区 */ 6 7 /* Set exchange registers */ 8 mov EXCHANGE_LR, lr /* EXCHANGE_LR = r4 <- lr | 将 LR_irq 备份到 R4 寄存器中 */ 9 mrs EXCHANGE_SPSR, spsr /* EXCHANGE_SPSR = r5 <- spsr | 将 CPSR_irq 备份到 R5 寄存器,R4和R5即将要入栈备份 */ 10 mrs EXCHANGE_CPSR, cpsr /* EXCHANGE_CPSR = r6 <- cpsr | 将 CPSR 读到 R6 ,准备切换到SVC模式 */ 11 sub EXCHANGE_INT_SP, sp, #EXCHANGE_SIZE /* EXCHANGE_SP = r7 <- SP_irq - 16 | 因为第5行入栈了四个寄存器,SP的值未变,R7为此时的栈顶 */ 12 13 /* Switch to SVC mode */ 14 orr EXCHANGE_CPSR, EXCHANGE_CPSR, #0x1 /* IRQ mode -> SVC mode | 从IRQ模式切换到SVC模式,后续的操作都是在SVC模式完成 */ 15 msr cpsr, EXCHANGE_CPSR 16 17 /* 18 * Save context. We save the LR separately because it has to be 19 * restored in SVC mode. The other registers can be restored in INT 20 * mode. 21 */ 22 stmdb sp!, CONTEXT_LIST /* [sp!] <- r0,r1,r2,r3,LR_irq,SPSR_irq,r12 | 将R0,R1,R2,R3,LR_irq,SPSR_irq,R12存入SP_svc堆栈中 */ 23 stmdb sp!, {lr} /* [sp!] <- LR_svc | 将LR_svc存入SP_svc堆栈中,将这些寄存器入栈以后,就可以调用C函数了 */ 24 25 /* Remember INT stack pointer */ 26 mov r1, EXCHANGE_INT_SP /* r1 <- r7 = SP_irq-16 | 现在要将存储在SP_irq堆栈中的R4-R7寄存器值恢复到R4-R7寄存器中 */ 27 28 /* Restore exchange registers from exchange area */ 29 ldmia r1, EXCHANGE_LIST /* 从SP_irq堆栈中恢复R4-R7寄存器的值,与第5行对应,至此R0-R3已经备份过了,可以替代R4-R7作为交换区 */ 30 31 /* Get interrupt nest level */ 32 ldr r0, =_ISR_Nest_level /* 读取中断嵌套层级 */ 33 ldr r2, [r0] 34 35 /* Switch stack if necessary and save original stack pointer */ 36 mov r3, sp 37 cmp r2, #0 38 moveq sp, r1 /* R1 = SP_irq-16,使用 SP_irq 的堆栈空间,给下面的 bsp_interrupt_dispatch 函数用 */ 39 stmdb sp!, {r3} /* 将 SP 入栈到 SP_irq 堆栈空间中备份,接下来将是在 SVC 模式下使用 IRQ 模式的堆栈空间 */ 40 41 /* Switch to THUMB instructions if necessary */ 42 SWITCH_FROM_ARM_TO_THUMB r1 43 44 /* Increment interrupt nest and thread dispatch disable level */ 45 ldr r1, =_Thread_Dispatch_disable_level /* 禁止任务调度器,嵌套层数加1 */ 46 ldr r3, [r1] 47 add r2, #1 48 add r3, #1 49 str r2, [r0] 50 str r3, [r1] 51 52 /* Call BSP dependent interrupt dispatcher */ 53 bl bsp_interrupt_dispatch /* 调用 bsp_interrupt_dispatch 函数,该函数运行在 SVC 模式下,但使用 IRQ 的堆栈空间 */
/* 该函数根据 INTOFFSET 寄存器分支到 32 个中断源各自的 ISR 去执行,执行后返回 */
54 55 /* Decrement interrupt nest and thread dispatch disable level */ 56 ldr r0, =_ISR_Nest_level /* _ISR_Nest_level 和 _Thread_Dispatch_disable_level 各自减1 */ 57 ldr r1, =_Thread_Dispatch_disable_level 58 ldr r2, [r0] 59 ldr r3, [r1] 60 sub r2, #1 61 sub r3, #1 62 str r2, [r0] 63 str r3, [r1] 64 65 /* Restore stack pointer */ 66 SWITCH_FROM_THUMB_TO_ARM 67 68 ldr sp, [sp] /* bsp_interrupt_dispatch 函数执行结束,换回到 SVC 堆栈,继续使用 */ 69 70 SWITCH_FROM_ARM_TO_THUMB r0 71 72 /* Check thread dispatch disable level */ 73 cmp r3, #0 /* 如果_Thread_Dispatch_disable_level的值为0,则判断下面是否需要执行上下文切换 */ 74 bne thread_dispatch_done 75 76 /* Check context switch necessary */ 77 ldr r0, =_Context_Switch_necessary
78 ldrb r1, [r0] 79 ldr r0, =_ISR_Signals_to_thread_executing /* _ISR_Signals_to_thread_executing 表示中断ISR向当前正在执行的任务发送了一个异步信号 */ 80 cmp r1, #0 81 bne do_thread_dispatch /* 如果_Context_Switch_necessary不为0,则跳转到do_thread_dispatch执行任务切换 */ 82 83 /* Check ISR signals to thread executing */ 84 ldrb r1, [r0] 85 cmp r1, #0 86 beq thread_dispatch_done /* 如果_ISR_Signals_to_thread_executing不等于0,也需要执行上下文切换 */ 87 88 /* This aligns thread_dispatch_done on a 4 byte boundary */ 89 #ifdef __thumb__ 90 nop 91 #endif /* __thumb__ */ 92 93 do_thread_dispatch: 94 95 /* Clear ISR signals to thread executing */ 96 strb r3, [r0] /* 在执行任务调度前将 _ISR_Signals_to_thread_executing 赋值为0 */ 97 98 /* Thread dispatch */ 99 bl _Thread_Dispatch 100 101 thread_dispatch_done: /* 从此处开始就是结束中断的代码了 */ 102 103 /* Switch to ARM instructions if necessary */ 104 SWITCH_FROM_THUMB_TO_ARM 105 106 /* Restore link register */ 107 ldmia sp!, {lr} /* 从SP_svc堆栈中恢复LR_svc寄存器的值,与第23行相对应 */ 108 109 /* 110 * XXX: Remember and restore stack pointer. The data on the stack is 111 * still in use. So the stack is now in an inconsistent state. The 112 * FIQ handler implementation must not use this area. 113 */ 114 mov r0, sp /* r0 <- sp | 将寄存器SP_svc的值读到R0中备份,等下在切换到IRQ模式后要用它读七个寄存器的值 */ 115 add sp, #CONTEXT_SIZE /* sp=sp+28,R0,R1,R2,R3,R4,R5,R12共7个寄存器等下要出栈,在切换到IRQ模式前先改SP的值 */ 116 117 /* Get INT mode program status register */ 118 mrs r1, cpsr /* r1 <- cpsr */ 119 bic r1, r1, #0x1 120 121 /* Switch to INT mode */ 122 msr cpsr, r1 /* IRQ_mode <- SVC_mode | 下面要从SVC模式切换到IRQ模式了,与第15行对应 */ 123 124 /* Save EXCHANGE_LR and EXCHANGE_SPSR registers to exchange area */ 125 stmdb sp!, {EXCHANGE_LR, EXCHANGE_SPSR} /* [SP_irq!] <- R4,R5 | 将R4,R5压入SP_irq栈中,备份,因为下面要用到它俩 */ 126 127 /* Restore context */ 128 ldmia r0, CONTEXT_LIST /* 从SP_svc栈中恢复R0,R1,R2,R3,R4,R5,R12七个寄存器的值,与第22行对应,R0中存储的是SP_svc的值 */ 129 130 /* Set return address and program status */ 131 mov lr, EXCHANGE_LR /* LR_irq <- R4 */ 132 msr spsr, EXCHANGE_SPSR /* SPSR_irq <- R5 | 与第8、9行对应 */ 133 134 /* Restore EXCHANGE_LR and EXCHANGE_SPSR registers from exchange area */ 135 ldmia sp!, {EXCHANGE_LR, EXCHANGE_SPSR} /* R4,R5 <- [SP_irq!] | 与第125行对应 */ 136 137 /* Return from interrupt */ 138 subs pc, lr, #4 /* 从中断返回,同时从SPSR中恢复CPSR的值,因为指令中带有 s 标志,且目标寄存器是PC */ 139

 

posted @ 2015-12-09 21:38  zhousm  阅读(742)  评论(0编辑  收藏  举报