当前位置: 首页 > article >正文

FreeRtos 任务切换深入分析

一、背景知识:

1、任务切换包含三个基本流程:保护现场、更新TCB、恢复现场并跳转

2、freertos的任务切换是在xPortPendSVHandler 中断函数中完成的

3、中断函数在调用之前,硬件已经保存了r0,r1,r2,r3,r12,r14(LR),r15(pc),恢复现场的时候由硬件自动恢复r0,r1,r2,r3,r12,r14(LR),r15(pc),即r0~r3在中断服务函数中是可以随便使用的,剩下的r4~r11需要在中断函数中手动保存。

4、ARM中的栈有两个,msp和psp,主程序和中断中用msp,线程中是psp

5、ARM一般是满减栈

二、xPortPendSVHandler源代码:

void xPortPendSVHandler( void )
{
    /* This is a naked function. */

    __asm volatile
        (
         "	mrs r0, psp							\n"
         "	isb									\n"
         "										\n"
         "	ldr	r3, pxCurrentTCBConst			\n" /* Get the location of the current TCB. */
         "	ldr	r2, [r3]						\n"
         "										\n"
         "	tst r14, #0x10						\n" /* Is the task using the FPU context?  If so, push high vfp registers. */
         "	it eq								\n"
         "	vstmdbeq r0!, {s16-s31}				\n"
         "										\n"
         "	stmdb r0!, {r4-r11, r14}			\n" /* Save the core registers. */
         "	str r0, [r2]						\n" /* Save the new top of stack into the first member of the TCB. */
         "										\n"
         "	stmdb sp!, {r0, r3}					\n"
         "	mov r0, %0 							\n"
         "	cpsid i								\n" /* Errata workaround. */
         "	msr basepri, r0						\n"
         "	dsb									\n"
         "	isb									\n"
         "	cpsie i								\n" /* Errata workaround. */
         "	bl vTaskSwitchContext				\n"
         "	mov r0, #0							\n"
         "	msr basepri, r0						\n"
         "	ldmia sp!, {r0, r3}					\n"
         "										\n"
         "	ldr r1, [r3]						\n" /* The first item in pxCurrentTCB is the task top of stack. */
         "	ldr r0, [r1]						\n"
         "										\n"
         "	ldmia r0!, {r4-r11, r14}			\n" /* Pop the core registers. */
         "										\n"
         "	tst r14, #0x10						\n" /* Is the task using the FPU context?  If so, pop the high vfp registers too. */
         "	it eq								\n"
         "	vldmiaeq r0!, {s16-s31}				\n"
         "										\n"
         "	msr psp, r0							\n"
         "	isb									\n"
         "										\n"
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata workaround. */
#if WORKAROUND_PMU_CM001 == 1
         "			push { r14 }				\n"
         "			pop { pc }					\n"
#endif
#endif
         "										\n"
         "	bx r14								\n"
         "										\n"
         "	.align 4							\n"
         "pxCurrentTCBConst: .word pxCurrentTCB	\n"
         ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
         );
}

三、xPortPendSVHandler分析:

1、先在xPortPendSVHandler中把pxCurrentTCB打印出来:

2、 

将psp给r0 

3、 

这两行,将r3保存了pxCurrentTCB,r2指向了上一个task的栈顶位置:pxTopOfStack

4、

 这是对FPU寄存器的判断,可以先不看

5、

将r4-r11,r14保存到任务栈psp中。并将栈顶位置写入到r2中,即 pxTopOfStack这个变量

6、

此时的sp为msp,即将r3、r0保存到msp中。

至此,现场保护已经完成。

7、


跳转到vTaskSwitchContext这个C函数中执行,这个函数中就将下一个要执行的任务的TCP更新到pxCurrentTCB中,主要代码如下:

这里要时刻注意,不要迷糊,更新pxCurrentTCB的同时,r3也会指向这个新的pxCurrentTCB。

8、

将r3和r0从msp中恢复出来,注意:此时的r3中的pxCurrentTCB已经是更新之后的了。

9、

 这两句,将新的pxCurrentTCB中的pxTopOfStack给了r0,即r0中记录了新task的栈顶位置

10、

从新task中恢复现场即恢复r4~r11,r14 

11、

恢复FPU相关寄存器

12、

 将栈顶的位置给psp

至此,恢复现场已经全部完成

13、

 

r14即LR中记录了中断返回的地址,跳转执行


http://www.kler.cn/a/132209.html

相关文章:

  • leetcode - 串联所有单词的子串 - 最小覆盖子串 - x 的平方根
  • CCNA课程实验-14-Final_Lab
  • 小程序授权获取头像
  • 代码随想录算法训练营第10天|● 20. 有效的括号 ● 1047. 删除字符串中的所有相邻重复项 ● 150. 逆波兰表达式求值
  • py代码-python异步执行代码
  • HTML5学习系列之项目实战1
  • 国科大数据挖掘期末复习——聚类分析
  • ES6模块导入与导出的方式
  • 接口测试vs功能测试
  • 验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
  • syslog-ng 发送metric 到 Prometheus + Grafana
  • 美术作品的著作权
  • SQL Server如何建表
  • upload-labs关卡9(基于win特性data流绕过)通关思路
  • lua中的正则表达式
  • Linux C/C++全栈开发知识图谱(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全)
  • [C/C++]数据结构 链表(单向链表,双向链表)
  • 从0到0.01入门 Webpack| 001.精选 Webpack面试题
  • web3资讯及远程工作
  • CTFhub-RCE-综合过滤练习