nucleus 学习 中断

  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. ;******************************
  62. ;* End Hardware Specific Code *
  63. ;******************************

  64.     LDR r3, IRQ_Priority ; Get the Priority table address                          //获取IRQ优先级表的地址

  65. IRQ_VECTOR_LOOP
  66.     LDR r0, [r3,#0] ; Load first vector to be checked from priority table
  67.     MOV r1, #1 ; Build mask
  68.     MOV r1, r1, LSL r0 ; Use vector number to set mask to correct bit position            //逻辑左移优先级个数,不会溢出吗
  69.     TST r1, r2 ; Test if pending bit is set                                               //判断
  70.     BNE IRQ_VECTOR_FOUND ; If bit is set, branch to found section...                      //找到IRQ_VECTOR

  71.     BIC r4,r4,r1 ; Clear mask bit to keep higher priority ints active                     //如果没找到查下一个向量表?
  72.     ADD r3, r3, #4 ; Move to next word in the priority table
  73.     ADR r0, Priority_End ; Load the end address for the priority table
  74.     CMP r0, r3 ; Make sure not at the end of the table (shouldn't happen!)
  75.     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.     
  48.     MRS r1,CPSR ; Pickup current CPSR
  49.     BIC r1,r1,#MODE_MASK ; Clear the mode bits
  50.     ORR r1,r1,#SUP_MODE ; Set the SVC mode bits
  51.     MSR CPSR,r1 ; Change to SVC mode                                                                 //切换成svc模式

  52.     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.         
  74.         ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVD)
  75.         
  76.         MSR CPSR,r5 ; Switch modes (IRQ->SVC)

  77. ; 5. Store the SVC r13 into r5 so the r13 can be saved as is.                                               //这里明明是把r5放进r13(sp)
  78.         MOV r5,r13

  79. ; 6. Save the exception return address on the stack (r15).                                                  //保存r4进栈
  80.         STMDB r5!,{r4}

  81. ; 7. Save r6-r14 on stack                                                                                   //保存r6-r14进栈
  82.         STMDB r5!,{r6-r14}

  83. ; 8. Switch back to using r13 now that the original r13 has been saved.                                     //又把r13换回来了,回到sp回到原来的位置了
  84.         MOV r13,r5

  85. ; 9. Get r5 and exception enable registers off of exception stack and                                       //
  86. ; save r5 (stored in r4) back to the system stack.                                                          //保存r5(存在r4中)到system stack中,好吧之前的mov都理解错了,mov 目的,源
  87.         LDMIA r1!,{r4-r5}
  88.         STMDB r13!,{r4}
  89.         MOV r4,r5 ; Put exception enable value into r4

  90. ; 10. Get the rest of the registers off the exception stack and                                             //获取剩下的exception stack到system stack中
  91. ; save them onto the system stack.
  92.         LDMIA r1!,{r5-r8,r11} ; Get r0-r4 off exception stack
  93.         STMDB r13!,{r5-r8,r11} ; Put r0-r4 on system stack

  94. ; 11. Store the exception enable value back on the exception stack.
  95.         STMDB r1,{r4}

  96. ; 12. Save the SPSR on the system stack (CPSR)
  97.         STMDB r13!,{r3}

  98. ; 13. Re-enable interrupts                                                                                   //重新开启中断
  99.         MRS r1,CPSR
  100.         BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT)
  101.         MSR CPSR,r1

  102.         BX r2 ; Return to calling ISR
  103. ; }
  104. ; else
  105. ; {
  106. TCT_Not_Nested_Save

  107.         ; Determine if a thread was interrupted.                                //判断是否进程产生了中断
  108. ; if (TCD_Current_Thread)                                               //如果TCD_Current_Thread是空,则在schedule中因为初始化线程是关中断的
  109. ; {

  110.         LDR r1,Current_Thread ; Pickup current thread ptr address
  111.         LDR r1,[r1, #0] ; Pickup the current thread pointer
  112.         CMP r1,#0 ; Is it NU_NULL?
  113.         BEQ TCT_Idle_Context_Save ; If no, no real save is necessary


  114.         ; Yes, a thread was interrupted. Save complete context on the
  115.         ; thread's stack.

  116. ; 1. Save another register on the exception stack so we have enough to work with
  117.         STMDB r13!,{r5}

  118. ; 2. Save the necessary exception registers into r1-r3
  119.         MOV r1,r13 ; Put the exception r13 into r1
  120.         MOV r2,r14 ; Move the return address for the caller
  121.                                             ; of this function into r2
  122.         MRS r3,spsr ; Put the exception spsr into r3

  123. ; 3. Adjust the exception stack pointer for future exceptions
  124.         ADD r13,r13,#24 ; r13 will point to enable reg value when done

  125. ; 4. Switch CPU modes to save context on system stack
  126.         MRS r5,CPSR ; Pickup the current CPSR
  127.         BIC r5,r5,#MODE_MASK ; Clear the mode bits
  128.         
  129.         ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVD)
  130.         
  131.         MSR CPSR,r5 ; Switch modes (IRQ->SVC)

  132. ; 5. Store the SVC r13 into r5 so the r13 can be saved as is.
  133.         MOV r5,r13

  134. ; 6. Save the exception return address on the stack (r15).
  135.         STMDB r5!,{r4}

  136. ; 7. Save r6-r14 on stack
  137.         STMDB r5!,{r6-r14}

  138. ; 8. Switch back to using r13 now that the original r13 has been saved.
  139.         MOV r13,r5

  140. ; 9. Get r5 and exception enable registers off of exception stack and
  141. ; save r5 (stored in r4) back to the system stack.
  142.         LDMIA r1!,{r4-r5}
  143.         STMDB r13!,{r4}
  144.         MOV r4,r5 ; Put exception enable value into r4

  145. ; 10. Get the rest of the registers off the exception stack and
  146. ; save them onto the system stack.
  147.         LDMIA r1!,{r5-r8,r11} ; Get r0-r4 off exception stack
  148.         STMDB r13!,{r5-r8,r11} ; Put r0-r4 on system stack

  149. ; 11. Store the exception enable value back on the exception stack.
  150.         STMDB r1,{r4}

  151. ; 12. Save the SPSR on the system stack (CPSR)
  152.         STMDB r13!,{r3}

  153. ; 13. Save stack type to the task stack (1=interrupt stack)
  154.         MOV r1,#1 ; Interrupt stack type
  155.         STMDB r13!,{r1}

  156.         ; Save the thread's stack pointer in the control block.
  157. ; REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread
  158. ; REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr

  159.         LDR r1,Current_Thread ; Pickup current thread ptr address
  160.         LDR r3,[r1, #0] ; Pickup current thread pointer
  161.         STR r13,[r3, #TC_STACK_POINTER] ; Save stack pointer

  162.         ; Switch to the system stack.
  163. ; REG_Stack_Ptr = TCD_System_Stack

  164.         LDR r1,System_Stack ; Pickup address of stack pointer
  165.         LDR r3,System_Limit ; Pickup address of stack limit ptr
  166.         LDR r13,[r1, #0] ; Switch to system stack
  167.         LDR r10,[r3, #0] ; Setup system stack limit

  168.         ; Re-enable interrupts
  169.         MRS r1,CPSR
  170.         BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT)
  171.         MSR CPSR,r1
  172.  
  173. ; Return to caller ISR.

  174.         BX r2 ; Return to caller ISR

  175. ; }

  176. TCT_Idle_Context_Save

  177.         MOV r2,r14 ; Save r14 in r2
  178.         LDR r3,[r13] ; Get exception enable value from stack
  179.         ADD r13,r13,#20 ; Adjust exception r13 for future interrupts
  180.         STR r3,[r13] ; Put exception enable value back on stack

  181.         MRS r1,CPSR ; Pickup current CPSR
  182.         BIC r1,r1,#MODE_MASK ; Clear the current mode
  183.         BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) ; Re-enable interrupts
  184.         
  185.         ORR r1,r1,#SUP_MODE ; Prepare to switch to supervisor
  186.                                             ; mode (SVC)
  187.         MSR CPSR,r1 ; Switch to supervisor mode (SVC)

  188.         BX r2 ; Return to caller ISR

  189. ; }
  190. ;}
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
  



无欲速,无见小利。欲速,则不达;见小利,则大事不成。
原文地址:https://www.cnblogs.com/ch122633/p/7363280.html