uTank-木头
每一个你不满意的现在,都有一个你没有努力的曾经。

 

 1 /*-----------------------------------------------------------*/
 2 // 当进入PendSVC Handler时,
 3 // 上一个任务运行的环境即xPSR、PC(任务入口地址)、r14/r12/r3/r2/r1/r0寄存器的值
 4 // 会自动存储到任务的栈中,剩下的r4~r11需要手动保存
 5 __asm void xPortPendSVHandler( void )
 6 {
 7     extern uxCriticalNesting;
 8     extern pxCurrentTCB;
 9     extern vTaskSwitchContext;
10 
11 /* *INDENT-OFF* */
12     PRESERVE8
13     /* PendSV用于上下文的切换,进入PendSV时,处于上文环境 */
14     /* 进入xPortPendSVHandler时,r0~r3已经自动入栈了,此时可以任意使用r0~r3的值而不会破坏上下文环境 */
15     /* 此时psp仍然是"上文"任务的堆栈指针 */
16     /* 保存psp到r0的目的是为了后面通过stmdb指令保存"上文"任务的r4~r11 */
17     /* 把xPSR、PC、LR、r12、r3、r2、r1、r0、r11、r10、r9、r8、r7、r6、r5、r4都入栈了,才算是完整保存"上文"环境 */
18     mrs r0, psp     /* 将PSP的值存储到r0中 */
19     isb
20     /* Get the location of the current TCB. */
21     /* 此时pxCurrentTCB还是指向被切换的任务,可以认为是"上文"任务 */
22     /* 加载pxCurrentTCB地址到r3 */
23     ldr r3, =pxCurrentTCB
24     /* 加载r3指向的内容到r2,即r2等于pxCurrentTCB */
25     /* 用于最后保存"上文"环境时,更新栈顶指针到"上文"任务TCB的pxTopOfStack中 */
26     ldr r2, [ r3 ]
27 
28     /* Is the task using the FPU context?  If so, push high vfp registers. */
29     tst r14, #0x10
30     it eq
31     vstmdbeq r0!, {s16-s31}
32 
33     /* Save the core registers. */
34     /* 以r0作为基地址(即前面保存的psp),将CPU寄存器r4~r11的值存储到任务堆栈中,同时更新r0的值 */
35     /* 最后r0指向"上文"任务的栈顶 */
36     stmdb r0!, {r4-r11, r14}
37 
38     /* Save the new top of stack into the first member of the TCB. */
39     /* 经过stmdb指令的操作,"上文"任务的栈顶指针已经更新了 */
40     /* 因此需要更新到"上文"任务TCB的pxTopOfStack中 */
41     str r0, [ r2 ]
42     /* 至此,上下文切换的"上文"环境保存完成 */
43 
44 
45     /* 临时保存r0和r3,此时进栈是MSP的栈 */
46     stmdb sp!, {r0, r3}
47     /* 关中断 */
48     mov r0, # configMAX_SYSCALL_INTERRUPT_PRIORITY
49     msr basepri, r0
50     dsb
51     isb
52     /* 选择优先级最高的"下文"任务,然后更新pxCurrentTCB */
53     bl vTaskSwitchContext
54     /* 开中断 */
55     mov r0, # 0
56     msr basepri, r0
57     /* 临时恢复r0和r3,此时出栈是MSP的栈 */
58     ldmia sp!, {r0, r3}
59 
60     /* 以下为上下文切换的"下文"环境切换 */
61     
62     /* 经过vTaskSwitchContext,pxCurrentTCB的值已经更新,pxCurrentTCB已经指向了"下文"任务 */
63     /* r3仍然保存着pxCurrentTCB的地址值 */
64     /* 加载r3指向的内容到r1,r3存放的是pxCurrentTCB的地址值,即r1等于pxCurrentTCB */
65     /* r1指向了下一个将要运行的任务的TCB */
66     /* The first item in pxCurrentTCB is the task top of stack. */
67     ldr r1, [ r3 ]
68     /* 加载r1指向的内容到r0,即下一个要运行的任务的栈顶指针 */
69     ldr r0, [ r1 ]
70 
71     /* Pop the core registers. */
72     /* 以r0作为基地址,将下一个要运行的任务的任务堆栈内容加载到CPU寄存器r4~r11(手动加载) */
73     ldmia r0!, {r4-r11, r14}
74 
75     /* Is the task using the FPU context?  If so, pop the high vfp registers
76      * too. */
77     tst r14, # 0x10
78     it eq
79     vldmiaeq r0!, {s16-s31}
80 
81     /* 更新psp的值,等PendSV退出时,会以psp作为基地址,将任务栈中剩下的内容自动加载到CPU寄存器 */
82     /* 剩下的内容包括: xPSR、PC、LR、r12、r3、r2、r1、r0 */
83     msr psp, r0
84     
85     isb
86     #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
87         #if WORKAROUND_PMU_CM001 == 1
88             push { r14 }
89             pop { pc }
90             nop
91         #endif
92     #endif
93     /* 异常发生时,r14中保存异常返回标志,包括返回后进入任务模式还是处理器模式,使用psp栈指针还是msp栈指针 */
94     bx r14
95 /* *INDENT-ON* */
96 }

 

posted on 2022-12-15 18:00  uTank  阅读(630)  评论(0编辑  收藏  举报