自学内容网 自学内容网

ThreadX源码:Cortex-A7的tx_thread_context_restore.S(线程上下文恢复)汇编代码分析

0 参考资料

Cortex M3权威指南(中文).pdf(可以参考ARM指令集用法)

1 前言

tx_thread_context_restore.S是用来实现Cortex-A7下线程上下文恢复的函数所在汇编文件。

2 源码分析

2.1 概述

_tx_thread_context_restore函数用于在线程被中断打断之后恢复上下文,根据打断点所处的位置分为2种情况:
(1)非嵌套中断(首次触发中断,也就是从线程切换到IRQ模式)
(2)嵌套中断
非嵌套中断又分为几种情况:
(1)如果中断期间未发生诸如发送信号量等需要引起线程调度的操作,则将返回原来的被中断线程处继续执行
(2)如果中断期间发生诸如发送信号量等需要引起线程调度的操作,则跳转/返回到线程调度,以最快的速度保证最高优先级线程得到响应
(3)中断期间线程未运行(正在执行线程调度操作),则无需恢复现场

2.2 源码逐行分析

源码如下:

1.    .global _tx_thread_context_restore
2.    .type   _tx_thread_context_restore,function
3._tx_thread_context_restore:

4.    /* Lockout interrupts.  */

5.#ifdef TX_ENABLE_FIQ_SUPPORT
6.    CPSID   if                              // Disable IRQ and FIQ interrupts
7.#else
8.    CPSID   i                               // Disable IRQ interrupts
9.#endif

10.#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
11.    /* Call the ISR exit function to indicate an ISR is complete.  */
12.    BL      _tx_execution_isr_exit          // Call the ISR exit function
13.#endif

14.    /* Determine if interrupts are nested.  */

15.    LDR     r3, =_tx_thread_system_state    // Pickup address of system state variable
16.    LDR     r2, [r3]                        // Pickup system state
17.    SUB     r2, r2, #1                      // Decrement the counter
18.    STR     r2, [r3]                        // Store the counter
19.    CMP     r2, #0                          // Was this the first interrupt?
20.    BEQ     __tx_thread_not_nested_restore  // If so, not a nested restore

21.    /* Interrupts are nested.  */

22.    /* Just recover the saved registers and return to the point of
23.       interrupt.  */

24.    POP     {r0, r10, r12, lr}              // Recover SPSR, POI, and scratch regs
25.    MSR     SPSR_cxsf, r0                   // Put SPSR back
26.    POP     {r0-r3}                         // Recover r0-r3
27.    MOVS    pc, lr                          // Return to point of interrupt

28.__tx_thread_not_nested_restore:

29.    /* Determine if a thread was interrupted and no preemption is required.  */

30.    LDR     r1, =_tx_thread_current_ptr     // Pickup address of current thread ptr
31.    LDR     r0, [r1]                        // Pickup actual current thread pointer
32.    CMP     r0, #0                          // Is it NULL?
33.    BEQ     __tx_thread_idle_system_restore // Yes, idle system was interrupted

34.    LDR     r3, =_tx_thread_preempt_disable // Pickup preempt disable address
35.    LDR     r2, [r3]                        // Pickup actual preempt disable flag
36.    CMP     r2, #0                          // Is it set?
37.    BNE     __tx_thread_no_preempt_restore  // Yes, don't preempt this thread
38.    LDR     r3, =_tx_thread_execute_ptr     // Pickup address of execute thread ptr
39.    LDR     r2, [r3]                        // Pickup actual execute thread pointer
40.    CMP     r0, r2                          // Is the same thread highest priority?
41.    BNE     __tx_thread_preempt_restore     // No, preemption needs to happen


42.__tx_thread_no_preempt_restore:

43.   /* Recover the saved context and return to the point of interrupt.  */

44.   /* Pickup the saved stack pointer.  */

45.   /* Recover the saved context and return to the point of interrupt.  */
46.    POP     {r0, r10, r12, lr}              // Recover SPSR, POI, and scratch regs
47.    MSR     SPSR_cxsf, r0                   // Put SPSR back
48.    POP     {r0-r3}                         // Recover r0-r3
49.    MOVS    pc, lr                          // Return to point of interrupt

50.__tx_thread_preempt_restore:

51.    POP     {r3, r10, r12, lr}              // Recover temporarily saved registers
52.    MOV     r1, lr                          // Save lr (point of interrupt)
53.    CPS     #SVC_MODE                       // Enter SVC mode
54.    STR     r1, [sp, #-4]!                  // Save point of interrupt
55.    PUSH    {r4-r12, lr}                    // Save upper half of registers
56.    MOV     r4, r3                          // Save SPSR in r4
57.    CPS     #IRQ_MODE                       // Enter IRQ mode
58.    POP     {r0-r3}                         // Recover r0-r3
59.    CPS     #SVC_MODE                       // Enter SVC mode
60.    PUSH    {r0-r3}                         // Save r0-r3 on thread's stack

61.    LDR     r1, =_tx_thread_current_ptr     // Pickup address of current thread ptr
62.    LDR     r0, [r1]                        // Pickup current thread pointer

63.#ifdef TX_ENABLE_VFP_SUPPORT
64.    LDR     r2, [r0, #144]                  // Pickup the VFP enabled flag
65.    CMP     r2, #0                          // Is the VFP enabled?
66.    BEQ     _tx_skip_irq_vfp_save           // No, skip VFP IRQ save
67.    VMRS    r2, FPSCR                       // Pickup the FPSCR
68.    STR     r2, [sp, #-4]!                  // Save FPSCR
69.    VSTMDB  sp!, {D16-D31}                  // Save D16-D31
70.    VSTMDB  sp!, {D0-D15}                   // Save D0-D15
71._tx_skip_irq_vfp_save:
72.#endif

73.    MOV     r3, #1                          // Build interrupt stack type
74.    PUSH    {r3, r4}                        // Save interrupt stack type and SPSR
75.    STR     sp, [r0, #8]                    // Save stack pointer in thread control
76.                                            //   block

77.    /* Save the remaining time-slice and disable it.  */
78.    LDR     r3, =_tx_timer_time_slice       // Pickup time-slice variable address
79.    LDR     r2, [r3]                        // Pickup time-slice
80.    CMP     r2, #0                          // Is it active?
81.    BEQ     __tx_thread_dont_save_ts        // No, don't save it
82.    STR     r2, [r0, #24]                   // Save thread's time-slice
83.    MOV     r2, #0                          // Clear value
84.    STR     r2, [r3]                        // Disable global time-slice flag

85.__tx_thread_dont_save_ts:

86.    /* Clear the current task pointer.  */
87.    MOV     r0, #0                          // NULL value
88.    STR     r0, [r1]                        // Clear current thread pointer

89.    /* Return to the scheduler.  */
90.    B       _tx_thread_schedule             // Return to scheduler

91.__tx_thread_idle_system_restore:

92.    /* Just return back to the scheduler!  */
93.    CPS     #SVC_MODE                       // Enter SVC mode
94.    B       _tx_thread_schedule             // Return to scheduler

2.2.1 _tx_thread_context_restore函数主干

1.    .global _tx_thread_context_restore
2.    .type   _tx_thread_context_restore,function
3._tx_thread_context_restore:

4.    /* Lockout interrupts.  */

5.#ifdef TX_ENABLE_FIQ_SUPPORT
6.    CPSID   if                              // Disable IRQ and FIQ interrupts
7.#else
8.    CPSID   i                               // Disable IRQ interrupts
9.#endif

10.#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
11.    /* Call the ISR exit function to indicate an ISR is complete.  */
12.    BL      _tx_execution_isr_exit          // Call the ISR exit function
13.#endif

功能:
将IRQ失能,如果定义了TX_ENABLE_EXECUTION_CHANGE_NOTIFY或TX_EXECUTION_PROFILE_ENABLE宏则将执行_tx_execution_isr_exit函数,告知内核退出了中断服务函数。

14.    /* Determine if interrupts are nested.  */

15.    LDR     r3, =_tx_thread_system_state    // Pickup address of system state variable
16.    LDR     r2, [r3]                        // Pickup system state
17.    SUB     r2, r2, #1                      // Decrement the counter
18.    STR     r2, [r3]                        // Store the counter
19.    CMP     r2, #0                          // Was this the first interrupt?
20.    BEQ     __tx_thread_not_nested_restore  // If so, not a nested restore

功能:
根据变量_tx_thread_system_state的值判断当前是否属于非嵌套中断,如果属于非嵌套中断则跳转到__tx_thread_not_nested_restore执行。

21.    /* Interrupts are nested.  */

22.    /* Just recover the saved registers and return to the point of
23.       interrupt.  */

24.    POP     {r0, r10, r12, lr}              // Recover SPSR, POI, and scratch regs
25.    MSR     SPSR_cxsf, r0                   // Put SPSR back
26.    POP     {r0-r3}                         // Recover r0-r3
27.    MOVS    pc, lr                          // Return to point of interrupt

功能:
如果是嵌套中断则会执行上述语句,也就是将中断上下文恢复,跳转到被嵌套中断打断前的位置。
SPSR_cxsf表示影响的位为c、x、s、f,含义如下:
c - control field mask byte(xPSR[7:0])
x - extension field mask byte(xPSR[15:8])
s - status field mask byte(xPSR[23:16)
f - flags field mask byte(xPSR[31:24]).

2.2.1 _tx_thread_context_restore函数分支__tx_thread_not_nested_restore非嵌套中断上下文恢复

28.__tx_thread_not_nested_restore:

29.    /* Determine if a thread was interrupted and no preemption is required.  */

30.    LDR     r1, =_tx_thread_current_ptr     // Pickup address of current thread ptr
31.    LDR     r0, [r1]                        // Pickup actual current thread pointer
32.    CMP     r0, #0                          // Is it NULL?
33.    BEQ     __tx_thread_idle_system_restore // Yes, idle system was interrupted

34.    LDR     r3, =_tx_thread_preempt_disable // Pickup preempt disable address
35.    LDR     r2, [r3]                        // Pickup actual preempt disable flag
36.    CMP     r2, #0                          // Is it set?
37.    BNE     __tx_thread_no_preempt_restore  // Yes, don't preempt this thread
38.    LDR     r3, =_tx_thread_execute_ptr     // Pickup address of execute thread ptr
39.    LDR     r2, [r3]                        // Pickup actual execute thread pointer
40.    CMP     r0, r2                          // Is the same thread highest priority?
41.    BNE     __tx_thread_preempt_restore     // No, preemption needs to happen

功能:
如果中断打断点属于非嵌套中断,表明需要执行的中断已经尽数处理完,执行最后的工作恢复中断打断前的现场。被中断打断的现场又分为3种情况:
(1)如果中断期间未发生诸如发送信号量等需要引起线程调度的操作,则将返回原来的被中断线程处继续执行,执行函数__tx_thread_no_preempt_restore
(2)如果中断期间发生诸如发送信号量等需要引起线程调度的操作,则跳转/返回到线程调度,以最快的速度保证最高优先级线程得到响应,执行函数__tx_thread_preempt_restore
(3)中断期间线程未运行(正在执行线程调度操作),则无需恢复现场,执行函数__tx_thread_idle_system_restore

2.2.1.1 _tx_thread_context_restore函数分支__tx_thread_not_nested_restore非嵌套中断上下文恢复分支__tx_thread_no_preempt_restore无高优先级线程需要调度
42.__tx_thread_no_preempt_restore:

43.   /* Recover the saved context and return to the point of interrupt.  */

44.   /* Pickup the saved stack pointer.  */

45.   /* Recover the saved context and return to the point of interrupt.  */
46.    POP     {r0, r10, r12, lr}              // Recover SPSR, POI, and scratch regs
47.    MSR     SPSR_cxsf, r0                   // Put SPSR back
48.    POP     {r0-r3}                         // Recover r0-r3
49.    MOVS    pc, lr                          // Return to point of interrupt

功能:
如果中断之后没有高优先级线程需要调度,则将中断打断前的现场恢复即可。

2.2.1.2 _tx_thread_context_restore函数分支__tx_thread_not_nested_restore非嵌套中断上下文恢复分支__tx_thread_preempt_restore有高优先级线程需要调度
50.__tx_thread_preempt_restore:

51.    POP     {r3, r10, r12, lr}              // Recover temporarily saved registers
52.    MOV     r1, lr                          // Save lr (point of interrupt)
53.    CPS     #SVC_MODE                       // Enter SVC mode
54.    STR     r1, [sp, #-4]!                  // Save point of interrupt
55.    PUSH    {r4-r12, lr}                    // Save upper half of registers
56.    MOV     r4, r3                          // Save SPSR in r4
57.    CPS     #IRQ_MODE                       // Enter IRQ mode
58.    POP     {r0-r3}                         // Recover r0-r3
59.    CPS     #SVC_MODE                       // Enter SVC mode
60.    PUSH    {r0-r3}                         // Save r0-r3 on thread's stack

61.    LDR     r1, =_tx_thread_current_ptr     // Pickup address of current thread ptr
62.    LDR     r0, [r1]                        // Pickup current thread pointer

63.#ifdef TX_ENABLE_VFP_SUPPORT
64.    LDR     r2, [r0, #144]                  // Pickup the VFP enabled flag
65.    CMP     r2, #0                          // Is the VFP enabled?
66.    BEQ     _tx_skip_irq_vfp_save           // No, skip VFP IRQ save
67.    VMRS    r2, FPSCR                       // Pickup the FPSCR
68.    STR     r2, [sp, #-4]!                  // Save FPSCR
69.    VSTMDB  sp!, {D16-D31}                  // Save D16-D31
70.    VSTMDB  sp!, {D0-D15}                   // Save D0-D15
71._tx_skip_irq_vfp_save:
72.#endif

73.    MOV     r3, #1                          // Build interrupt stack type
74.    PUSH    {r3, r4}                        // Save interrupt stack type and SPSR
75.    STR     sp, [r0, #8]                    // Save stack pointer in thread control
76.                                            //   block

77.    /* Save the remaining time-slice and disable it.  */
78.    LDR     r3, =_tx_timer_time_slice       // Pickup time-slice variable address
79.    LDR     r2, [r3]                        // Pickup time-slice
80.    CMP     r2, #0                          // Is it active?
81.    BEQ     __tx_thread_dont_save_ts        // No, don't save it
82.    STR     r2, [r0, #24]                   // Save thread's time-slice
83.    MOV     r2, #0                          // Clear value
84.    STR     r2, [r3]                        // Disable global time-slice flag

85.__tx_thread_dont_save_ts:

86.    /* Clear the current task pointer.  */
87.    MOV     r0, #0                          // NULL value
88.    STR     r0, [r1]                        // Clear current thread pointer

89.    /* Return to the scheduler.  */
90.    B       _tx_thread_schedule             // Return to scheduler

功能:
如果中断执行之后有高优先级中断需要执行,则需要执行__tx_thread_preempt_restore函数,然后执行_tx_thread_schedule函数,执行线程调度

2.2.1.3 _tx_thread_context_restore函数分支__tx_thread_not_nested_restore非嵌套中断上下文恢复分支__tx_thread_idle_system_restore中断前无线程运行现场恢复
91.__tx_thread_idle_system_restore:

92.    /* Just return back to the scheduler!  */
93.    CPS     #SVC_MODE                       // Enter SVC mode
94.    B       _tx_thread_schedule             // Return to scheduler

功能:
如果中断前线程未在运行(如处于线程调度期间),则跳转到_tx_thread_schedule函数,执行线程调度

3 总结

_tx_thread_context_restore函数主要功能就是根据中断打断位置的不同来恢复现场,根据中断打断位置分为非嵌套中断和嵌套中断。非嵌套中断下还涉及到高优先级线程调度问题(如中断期间发送了信号量等操作,需要执行线程调度),嵌套中断下则只需要恢复中断上下文即可。


原文地址:https://blog.csdn.net/kevin1499/article/details/142018219

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!