1. ;************************************************************************
  2. ;*
  3. ;* FUNCTION
  4. ;*
  5. ;* INT_IRQ
  6. ;*
  7. ;* DESCRIPTION
  8. ;*
  9. ;* This routine is the board-specific section for
  10. ;* level 1 interrupt handling
  11. ;*
  12. ;* CALLED BY
  13. ;*
  14. ;* None
  15. ;*
  16. ;* CALLS
  17. ;*
  18. ;* TMT_Timer_Interrupt
  19. ;*
  20. ;* INPUTS
  21. ;*
  22. ;* None
  23. ;*
  24. ;*
  25. ;* OUTPUTS
  26. ;*
  27. ;* None
  28. ;*
  29. ;* HISTORY
  30. ;*
  31. ;* NAME DATE REMARKS
  32. ;*
  33. ;* B. Ronquillo 05-10-00 Created initial version 1.0
  34. ;*
  35. ;************************************************************************
  36. .def _INT_IRQ
  37. _INT_IRQ
  38. ; ARM Core Check                                                                 //确认CPSR,这里应该是确认是否在IRQ模式下
  39. STMDB {r1}
  40. MRS r1, SPSR
  41. TST r1, #IRQ_BIT
  42. LDMIA {r1}
  43. SUBNES pc,lr,#4
  44. STMDB sp!,{r0-r4} ; Save r0-r4 on temporary IRQ stack                         //sp=sp-4 保存R0~R4到栈
  45. SUB lr,lr,#4 ; Adjust IRQ return address                                      //lr=lr-4就是把lr下移了一格
  46. ;********************************
  47. ;* Begin Hardware Specific Code *                                                 //开始硬件特性代码?
  48. ;********************************
  49. LDR r3, INT_CNTRL_BASE_1 ; load Interrupt Control Base                        //装载中断控制器基地址
  50. LDR r4, [r3,#INT_CNTRL_MIR] ; Get enable register value                       //获取enable register的值,INT_CNTRL_MIR的值
  51. ;******************************
  52. ;* End Hardware Specific Code *
  53. ;******************************
  54. STMDB sp!,{r4} ; Put the enable register value on the IRQ stack               //把r4压入栈,r4是enable register的值
  55. MVN r4,#0 ; Start with 0xFFFFFFFF to allow nesting of interrupts              //全部置1
  56. ;********************************
  57. ;* Begin Hardware Specific Code *
  58. ;********************************
  59. LDR r2, [r3,#INT_CNTRL_ITR] ; Read Pending reg                                 //这次读取了INT_CNTRL_ITR的值
  60. ;******************************
  61. ;* End Hardware Specific Code *
  62. ;******************************
  63. LDR r3, IRQ_Priority ; Get the Priority table address                          //获取IRQ优先级表的地址
  64. IRQ_VECTOR_LOOP
  65. LDR r0, [r3,#0] ; Load first vector to be checked from priority table
  66. MOV r1, #1 ; Build mask
  67. MOV r1, r1, LSL r0 ; Use vector number to set mask to correct bit position            //逻辑左移优先级个数,不会溢出吗
  68. TST r1, r2 ; Test if pending bit is set                                               //判断
  69. BNE IRQ_VECTOR_FOUND ; If bit is set, branch to found section...                      //找到IRQ_VECTOR
  70. BIC r4,r4,r1 ; Clear mask bit to keep higher priority ints active                     //如果没找到查下一个向量表?
  71. ADD r3, r3, #4 ; Move to next word in the priority table
  72. ADR r0, Priority_End ; Load the end address for the priority table
  73. CMP r0, r3 ; Make sure not at the end of the table (shouldn't happen!)
  74. BNE     IRQ_VECTOR_LOOP                 ; Continue to loop if not at the end of the table





        ; No bits in pending register set, restore registers and exit interrupt servicing                         //恢复上下文

        ADD     sp,sp,#4                        ; Adjust sp above IRQ enable value

        LDMIA   sp!,{r0-r4}                     ; Restore r0-r4

        STMDB   sp!,{lr}                        ; Put return address for IRQ on stack

        LDMIA   sp!,{pc}^                       ; return to the point of the exception and restore SPSR

     

    IRQ_VECTOR_FOUND





    ;********************************

    ;* Begin Hardware Specific Code *

    ;********************************





        LDR     r3, INT_CNTRL_BASE_1            ; load Interrupt Control Base                              //获取INT_CNTRL_BASE



      

        MVN     r2, r1                          ; Get the inverse of the interrupt vector                  //之前r1和r2应该是一样的,取了反

        STR     r2, [r3,#INT_CNTRL_ITR]         ; Write a zero to the interrupt being handled              //写一个0到中断处理中





        LDR     r2, [r3,#INT_CNTRL_MIR]         ; Read the Mask reg

        ORR     r4, r2, r4                      ; Turn off lower priority pending bits and currently masked bits

        STR     r4, [r3,#INT_CNTRL_MIR]         ; Disable(Mask) all lower priority interrupts and currently masked interrupts





        MOV     r1, #1                          ; Clear the pending interrupt                              //清除pending中断位

        STR     r1, [r3,#INT_CNTRL_CONTROL_REG] ; by writing a 1 to the Control Reg                        //写入1清除





    ;******************************

    ;* End Hardware Specific Code *

    ;******************************





        LDR     r3, IRQ_Vectors                 ; Get IRQ vector table address

        MOV     r2, r0, LSL #2                  ; Multiply vector by 4 to get offset into table

        ADD     r3, r3, r2                      ; Adjust vector table address to correct offset

        LDR     r2, [r3,#0]                     ; Load branch address from vector table





        MOV     PC, r2                          ; Jump to correct branch location based on vector table          //跳转到中断向量表,这个跳转应该是找到对应的处理程序?





    ; END: INT_IRQ


中断向量表:

  1. ; Define vector table used by INT_IRQ to branch to necessary ISR
  2. INT_IRQ_Vectors:
  3. .word _INT_IRQ_2 ; Vector 0
  4. .word INT_Interrupt_Shell ; Vector 1
  5. .word INT_Interrupt_Shell ; Vector 2
  6. .word INT_Interrupt_Shell ; Vector 3
  7. .word INT_Interrupt_Shell ; Vector 4
  8. .word INT_Interrupt_Shell ; Vector 5
  9. .word INT_Interrupt_Shell ; Vector 6
  10. .word INT_Interrupt_Shell ; Vector 7
  11. .word INT_Interrupt_Shell ; Vector 8
  12. .word INT_Interrupt_Shell ; Vector 9
  13. .word INT_Interrupt_Shell ; Vector 10
  14. .word INT_Interrupt_Shell ; Vector 11
  15. .word INT_Interrupt_Shell ; Vector 12
  16. .word INT_Interrupt_Shell ; Vector 13
  17. .word INT_Interrupt_Shell ; Vector 14
  18. .word INT_Interrupt_Shell ; Vector 15
  19. .word INT_Interrupt_Shell ; Vector 16
  20. .word INT_Interrupt_Shell ; Vector 17
  21. .word INT_Interrupt_Shell ; Vector 18
  22. .word INT_Interrupt_Shell ; Vector 19
  23. .word INT_Interrupt_Shell ; Vector 20
  24. .word INT_Interrupt_Shell ; Vector 21
  25. .word INT_Interrupt_Shell ; Vector 22
  26. .word INT_Interrupt_Shell ; Vector 23
  27. .word INT_Interrupt_Shell ; Vector 24
  28. .word INT_Interrupt_Shell ; Vector 25
  29. .word INT_Interrupt_Shell ; Vector 26
  30. .word INT_Interrupt_Shell ; Vector 27
  31. .word INT_Interrupt_Shell ; Vector 28
  32. .word INT_Interrupt_Shell ; Vector 29
  33. .word INT_Timer_Interrupt ; Vector 30
  34. .word INT_Interrupt_Shell ; Vector 31
  35. 。。。。。。。。。。。。。。。

INT_Interruopt_Shell(感觉只是跳转到_TCT_Interrupt_Context_Save):

  1. ;************************************************************************
  2. ;*
  3. ;* FUNCTION
  4. ;*
  5. ;* INT_Interrupt_Shell
  6. ;*
  7. ;* DESCRIPTION
  8. ;*
  9. ;* Handles all interrupts which use NU_Register_LISR.
  10. ;*
  11. ;*
  12. ;* CALLED BY
  13. ;*
  14. ;* INT_IRQ
  15. ;*
  16. ;* CALLS
  17. ;*
  18. ;* TCT_Dispatch_LISR
  19. ;* TCT_Interrupt_Context_Restore
  20. ;*
  21. ;* INPUTS
  22. ;*
  23. ;* vector (register r0)
  24. ;*
  25. ;* OUTPUTS
  26. ;*
  27. ;* None
  28. ;************************************************************************
  29. .def INT_Interrupt_Shell
  30. INT_Interrupt_Shell
  31. MOV r4,lr ; Put IRQ return address into r4                                                   //这里r4是PC的值
  32. BL _TCT_Interrupt_Context_Save                                                               //什么直接跳转了?
  33. BL _TCC_Dispatch_LISR                                                                        //怎么两个跳转?LISR?
  34. MRS r1,CPSR ; Pickup current CPSR                                                            //清除了中断,关了位
  35. BIC r1,r1,#MODE_MASK ; Clear the mode bits
  36. ORR r1,r1,#(IRQ_MODE_OR_LOCKOUT) ; Set the IRQ mode bits and Lockout interrupts
  37. MSR CPSR,r1 ; Lockout interrupts/change to IRQ mode
  38. ;********************************
  39. ;* Begin Hardware Specific Code *
  40. ;********************************
  41. LDMIA sp!,{r1} ; Get IRQ enable value off IRQ stack                                              //提取栈中的值到sp
  42. LDR r2, INT_CNTRL_BASE_1 ; Get IRQ0 base register address                                        //获取IRQ0基地址
  43. STR r1,[r2,#INT_CNTRL_MIR] ; Re-enable all lower priority interrupts                             //重新开启低优先级中断
  44. ;******************************
  45. ;* End Hardware Specific Code *
  46. ;******************************
  47. MRS r1,CPSR ; Pickup current CPSR
  48. BIC r1,r1,#MODE_MASK ; Clear the mode bits
  49. ORR r1,r1,#SUP_MODE ; Set the SVC mode bits
  50. MSR CPSR,r1 ; Change to SVC mode                                                                 //切换成svc模式
  51. B _TCT_Interrupt_Context_Restore

既然跳转到_TCT_Interrupt_Context_Save那就继续学习吧:

  1. ;************************************************************************
  2. ;*
  3. ;* FUNCTION
  4. ;*
  5. ;* TCT_Interrupt_Context_Save
  6. ;*
  7. ;* DESCRIPTION
  8. ;*
  9. ;* This function saves the interrupted thread's context. Nested
  10. ;* interrupts are also supported. If a task or HISR thread was
  11. ;* interrupted, the stack pointer is switched to the system stack
  12. ;* after the context is saved.
  13. ;*
  14. ;* CALLED BY
  15. ;*
  16. ;* Application ISRs Assembly language ISRs
  17. ;* INT_Interrupt_Shell Interrupt handler shell
  18. ;*
  19. ;* CALLS
  20. ;*
  21. ;* None
  22. ;*
  23. ;* INPUTS
  24. ;*
  25. ;* vector Interrupt's vector number
  26. ;*
  27. ;* OUTPUTS
  28. ;*
  29. ;* None
  30. ;*
  31. ;* HISTORY
  32. ;*
  33. ;* NAME DATE REMARKS
  34. ;*
  35. ;* W. Lamie 02-15-1994 Created initial version 1.0
  36. ;* D. Lamie 02-15-1994 Verified version 1.0
  37. ;* D. Driscoll 01-04-2002 Released version 1.13.3.
  38. ;* Updated to handle nested /
  39. ;* prioritized IRQs
  40. ;************************************************************************
  41. ;VOID TCT_Interrupt_Context_Save(INT vector)
  42. ;{
  43. .def $TCT_Interrupt_Context_Save
  44. $TCT_Interrupt_Context_Save ; Dual-state interworking veneer
  45. .state16
  46. BX r15
  47. NOP
  48. .state32
  49. B _TCT_Interrupt_Context_Save
  50. .def _TCT_Interrupt_Context_Save
  51. _TCT_Interrupt_Context_Save
  52. ; Determine if this is a nested interrupt.                                                          //确定是不是嵌套中断
  53. LDR r1,Int_Count ; Pickup address of interrupt count                                                //Int_Count是中断计数
  54. LDR r2,[r1, #0] ; Pickup interrupt counter
  55. ADD r2,r2,#1 ; Add 1 to interrupt counter
  56. STR r2,[r1, #0] ; Store new interrupt counter value                                                 //更新中断计数
  57. CMP r2,#1 ; Is it nested?
  58. BEQ TCT_Not_Nested_Save ; No                                                                        //如果不是嵌套就跳转
  59. ; Nested interrupt. Save complete context on the current stack.
  60. TCT_Nested_Save
  61. ; 1. Save another register on the exception stack so we have enough to work with                            //保存另一个寄存器(r5)到异常栈,腾出空间来。r13是sp指针
  62. STMDB r13!,{r5}
  63. ; 2. Save the necessary exception registers into r1-r3                                                      //保存必要的异常寄存器到r1-r3
  64. MOV r1,r13 ; Put the exception r13 into r1
  65. MOV r2,r14 ; Move the return address for the caller
  66. ; of this function into r2
  67. MRS r3,spsr ; Put the exception spsr into r3
  68. ; 3. Adjust the exception stack pointer for future exceptions                                               //调整异常栈指针为之后的异常
  69. ADD r13,r13,#24 ; r13 will point to enable reg value when done
  70. ; 4. Switch CPU modes to save context on system stack                                                       //转换CPU模式到system stack(之前初始化过的)
  71. MRS r5,CPSR ; Pickup the current CPSR
  72. BIC r5,r5,#MODE_MASK ; Clear the mode bits
  73. ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVD)
  74. MSR CPSR,r5 ; Switch modes (IRQ->SVC)
  75. ; 5. Store the SVC r13 into r5 so the r13 can be saved as is.                                               //这里明明是把r5放进r13(sp)
  76. MOV r5,r13
  77. ; 6. Save the exception return address on the stack (r15).                                                  //保存r4进栈
  78. STMDB r5!,{r4}
  79. ; 7. Save r6-r14 on stack                                                                                   //保存r6-r14进栈
  80. STMDB r5!,{r6-r14}
  81. ; 8. Switch back to using r13 now that the original r13 has been saved.                                     //又把r13换回来了,回到sp回到原来的位置了
  82. MOV r13,r5
  83. ; 9. Get r5 and exception enable registers off of exception stack and                                       //
  84. ; save r5 (stored in r4) back to the system stack.                                                          //保存r5(存在r4中)到system stack中,好吧之前的mov都理解错了,mov 目的,源
  85. LDMIA r1!,{r4-r5}
  86. STMDB r13!,{r4}
  87. MOV r4,r5 ; Put exception enable value into r4
  88. ; 10. Get the rest of the registers off the exception stack and                                             //获取剩下的exception stack到system stack中
  89. ; save them onto the system stack.
  90. LDMIA r1!,{r5-r8,r11} ; Get r0-r4 off exception stack
  91. STMDB r13!,{r5-r8,r11} ; Put r0-r4 on system stack
  92. ; 11. Store the exception enable value back on the exception stack.
  93. STMDB r1,{r4}
  94. ; 12. Save the SPSR on the system stack (CPSR)
  95. STMDB r13!,{r3}
  96. ; 13. Re-enable interrupts                                                                                   //重新开启中断
  97. MRS r1,CPSR
  98. BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT)
  99. MSR CPSR,r1
  100. BX r2 ; Return to calling ISR
  101. ; }
  102. ; else
  103. ; {
  104. TCT_Not_Nested_Save
  105. ; Determine if a thread was interrupted.                                //判断是否进程产生了中断
  106. ; if (TCD_Current_Thread)                                               //如果TCD_Current_Thread是空,则在schedule中因为初始化线程是关中断的
  107. ; {
  108. LDR r1,Current_Thread ; Pickup current thread ptr address
  109. LDR r1,[r1, #0] ; Pickup the current thread pointer
  110. CMP r1,#0 ; Is it NU_NULL?
  111. BEQ TCT_Idle_Context_Save ; If no, no real save is necessary
  112. ; Yes, a thread was interrupted. Save complete context on the
  113. ; thread's stack.
  114. ; 1. Save another register on the exception stack so we have enough to work with
  115. STMDB r13!,{r5}
  116. ; 2. Save the necessary exception registers into r1-r3
  117. MOV r1,r13 ; Put the exception r13 into r1
  118. MOV r2,r14 ; Move the return address for the caller
  119. ; of this function into r2
  120. MRS r3,spsr ; Put the exception spsr into r3
  121. ; 3. Adjust the exception stack pointer for future exceptions
  122. ADD r13,r13,#24 ; r13 will point to enable reg value when done
  123. ; 4. Switch CPU modes to save context on system stack
  124. MRS r5,CPSR ; Pickup the current CPSR
  125. BIC r5,r5,#MODE_MASK ; Clear the mode bits
  126. ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVD)
  127. MSR CPSR,r5 ; Switch modes (IRQ->SVC)
  128. ; 5. Store the SVC r13 into r5 so the r13 can be saved as is.
  129. MOV r5,r13
  130. ; 6. Save the exception return address on the stack (r15).
  131. STMDB r5!,{r4}
  132. ; 7. Save r6-r14 on stack
  133. STMDB r5!,{r6-r14}
  134. ; 8. Switch back to using r13 now that the original r13 has been saved.
  135. MOV r13,r5
  136. ; 9. Get r5 and exception enable registers off of exception stack and
  137. ; save r5 (stored in r4) back to the system stack.
  138. LDMIA r1!,{r4-r5}
  139. STMDB r13!,{r4}
  140. MOV r4,r5 ; Put exception enable value into r4
  141. ; 10. Get the rest of the registers off the exception stack and
  142. ; save them onto the system stack.
  143. LDMIA r1!,{r5-r8,r11} ; Get r0-r4 off exception stack
  144. STMDB r13!,{r5-r8,r11} ; Put r0-r4 on system stack
  145. ; 11. Store the exception enable value back on the exception stack.
  146. STMDB r1,{r4}
  147. ; 12. Save the SPSR on the system stack (CPSR)
  148. STMDB r13!,{r3}
  149. ; 13. Save stack type to the task stack (1=interrupt stack)
  150. MOV r1,#1 ; Interrupt stack type
  151. STMDB r13!,{r1}
  152. ; Save the thread's stack pointer in the control block.
  153. ; REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread
  154. ; REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr
  155. LDR r1,Current_Thread ; Pickup current thread ptr address
  156. LDR r3,[r1, #0] ; Pickup current thread pointer
  157. STR r13,[r3, #TC_STACK_POINTER] ; Save stack pointer
  158. ; Switch to the system stack.
  159. ; REG_Stack_Ptr = TCD_System_Stack
  160. LDR r1,System_Stack ; Pickup address of stack pointer
  161. LDR r3,System_Limit ; Pickup address of stack limit ptr
  162. LDR r13,[r1, #0] ; Switch to system stack
  163. LDR r10,[r3, #0] ; Setup system stack limit
  164. ; Re-enable interrupts
  165. MRS r1,CPSR
  166. BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT)
  167. MSR CPSR,r1
  168. ; Return to caller ISR.
  169. BX r2 ; Return to caller ISR
  170. ; }
  171. TCT_Idle_Context_Save
  172. MOV r2,r14 ; Save r14 in r2
  173. LDR r3,[r13] ; Get exception enable value from stack
  174. ADD r13,r13,#20 ; Adjust exception r13 for future interrupts
  175. STR r3,[r13] ; Put exception enable value back on stack
  176. MRS r1,CPSR ; Pickup current CPSR
  177. BIC r1,r1,#MODE_MASK ; Clear the current mode
  178. BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) ; Re-enable interrupts
  179. ORR r1,r1,#SUP_MODE ; Prepare to switch to supervisor
  180. ; mode (SVC)
  181. MSR CPSR,r1 ; Switch to supervisor mode (SVC)
  182. BX r2 ; Return to caller ISR
  183. ; }
  184. ;}
NU对于中断上下文的保存具体操作如下:
(1)在中断发生后执行的入口函数INT_IRQ()中,将r0-r4保存至irq的栈中
(2)查找到对应的interrupt_shell(),clear中断源,更新全局的中断计数器,然后进行interrupt_contex_save
(3)首先利用r1,r2,r3保存irq模式下的sp,lr,spsr,这里sp是用来切换至系统栈后拷贝lr和spsr的,这里保存lr和spsr是目的是task被抢占后,当再次schedule时可以返回task之前的状态。
(4)切换至SVC模式,如果是非嵌套的中断则保存上下文至task stack中,将irq模式下的lr作为顶端PC的返回值入栈,将SVC模式下的r6-r14入栈,将irq模式下的sp保存至r4中入栈,最后将保存在irq_stack中的r0-r4入栈
(5)如果是嵌套中断,中断的嵌套发生在LISR中,在执行LISR时已经切换至system stack,因此嵌套中断要将中断的上下文保存至system stack中,与task stack中interrupt stack相比只是少了栈顶用来标记嵌套的标志(1 not nested)
(6)有一个分支判断,就是如果当前线程是空,即TCD_Current_Thread == NULL,表明当前是schedule中,因为初始化线程是关中断的,这样就不为schedule线程建立栈帧,因为schedule不需要保存上下文,在restore中断上下文时直接跳转至schedule。

中断上下文的恢复
全局的中断计数器INT_Count是否为0来判定当前出栈的信息,如果是嵌套则返回LISR中,否则切换至system stack执行schedule
05-24 05:47