0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Freertos栈检测

嵌入式USB开发 来源:嵌入式USB开发 作者:嵌入式USB开发 2023-09-19 14:03 次阅读

本文转自公众号,欢迎关注
https://mp.weixin.qq.com/s/uzaGLFTDBAn8wyR84yaiIw

1. 前言

RTOS的环境开发中,栈的溢出检测是一个重要的工作。栈溢出检测我们可以借助硬件的MPU等实现,也可以使用软件检测。这里分享Freertos中的实现。这里基于Cortex-M4硬件平台,一些具体的代码就未贴出了,顺便介绍了一下Cortex-M4栈相关的基础知识。

2. 栈初始化

2.1任务启动前栈

复位后汇编代码

IMPORT  __main


LDR     R0, =SystemInit


BLX     R0


LDR     R0, =__main


BX      R0


ENDP

会进入__main将栈内容写为0。该部分由编译器产生代码实现。

栈的位置是链接脚本中指定。

2.2任务栈

xTaskCreate -> prvInitialiseNewTask将任务栈填充为tskSTACK_FILL_BYTE = ( 0xa5U )

然后调用pxPortInitialiseStack初始化任务栈上下文

任务初始化时
高地址
->任务切出时栈指针
低地址
任务运行一段时间后
高地址
已使用部分
->任务切出时栈指针
未使用部分
低地址

对应实际中断后的栈如下:

3.任务切换

vPortSVCHandler函数模拟中断返回

__asm void vPortSVCHandler( void )


{


PRESERVE8


/* Get the location of the current TCB. */


ldr r3, =pxCurrentTCB


ldr r1, [r3]


ldr r0, [r1]


/* Pop the core registers. */


ldmia r0!, {r4-r11, r14}


msr psp, r0


isb


mov r0, #0


msr basepri, r0


bx r14


}

其中

ldr r3, =pxCurrentTCB


ldr r1, [r3]


ldr r0, [r1]

是获取栈指针r0即指向任务栈表中R4位置

ldmia r0!, {r4-r11, r14}是恢复R4-R11和portINITIAL_EXC_RETURN

msr psp, r0,更新栈指针,指向指向任务栈表中R0位置

bx r14模拟中断返回 恢复R0-R3 R12 PC xPSR(硬件实现)。

由于R14=portINITIAL_EXC_RETURN=0xfffffffd

根据手册描述

图片

返回时使用PSP栈,返回后使用PSP栈。与初始化对应。

4.任务return

栈初始化时LR = prvTaskExitError 进入子函数时LR会入栈,退出子函数时LR出栈。

所以如果任务不是while(1)形式而是在最后return则最终会进入

prvTaskExitError执行。一般rtos的任务都是while(1)结构 不return。

5.栈指针

复位后使用MSP,任务根据返回时的LR值portINITIAL_EXC_RETURN使用PSP见“2.任务切换”。

中断中固定使用MSP。

图片

6.栈使用

中断函数和mian使用中断向量第一个字指向的栈区域。

任务使用任务栈。

在os启动前默认时使用msp,根据中断向量的第一个字加载msp

硬件实现,或者bootloader跳转到应用时配置。

启动os时prvStartFirstTask,又重新将中断向量第一个字加载到msp。

今后中断就使用msp对应的栈,即os启动前main使用的栈。

因为main一去不复返,所以这里覆盖使用main时的栈,这样可以节约内存。

/* Use the NVIC offset register to locate the stack. */


ldr r0, =0xE000ED08


ldr r0, [r0]


ldr r0, [r0]


/* Set the msp back to the start of the stack. */


msr msp, r0

7栈检测

7.1任务栈检测

栈初始化时全部初始化为0xA5,运行一段时间后栈顶部分使用变为其他值。

检查栈底有多少连续的0xA5即可知道栈剩余多少。

图片

Freertos提供接口函数uxTaskGetSystemState获取栈信息

Shell中输入ps查看(具体代码未贴出)。

图片

7.2中断栈/main函数栈检测

根据4.和5.的分析,中断和main函数栈使用中断向量第一个字对应的栈区域。

由于__main.c会将栈内容清除为0.所以在启动第一个任务前将栈重新填充为0xa5。

有__main.c之前将栈填充为0xa5又会被清除为0,将填充代码放在了任务启动前prvStartFirstTask函数中。这样main函数到prvStartFirstTask之前的栈使用大小不可监控。

只能监控后续中断使用的栈大小。如果要检测main函数栈使用则要将填充代码放在main函数执行的第一条代码后,需要嵌入汇编影响代码阅读和可移植性,所以不按这种方式。

实际上main函数栈溢出也没关系 ,但是编程必须要求提供手动初始化变量的代码,而不是依赖于编译器的初始化。

比如有一个变量static int i =0;

编译器提供代码在__main中会对该变量初始化,如果main函数栈溢出覆盖了这个变量的值。

那么在任务函数执行时提供 void mode_init(void)函数

手动再次初始化该变量i=0.

就可以避免问题。

建议在模块任务启动时对属于模块的全局变量再次提供”构造函数”手动初始化。

修改freertos底层移植代码

__asm void prvStartFirstTask( void )


{


PRESERVE8


/* Use the NVIC offset register to locate the stack. */


ldr r0, =0xE000ED08


ldr r0, [r0]


ldr r0, [r0]


/* Set the msp back to the start of the stack. */


msr msp, r0


//;初始化栈为0xA5A5A5A5  


MOV     R2,#0xA5A5A5A5


LDR     R0, =0x4000


MRS     R1, MSP


 SUBS    R1,R1,#4


LOOP STR R2,[R1,#0x00]


SUBS    R0,R0,#4


 SUBS    R1,R1,#4


CMP     R0,#0x00


BNE     LOOP

增加检测代码

其中0x4000需要根据实际设置的栈大小修改。0xE000ED08为中断向量表地址。

/*****************************************************************************


* fn          uint32_t bsp_sys_getstack(void)


* brief       获取栈大小.


* note        .


* return      剩余栈字节数


*****************************************************************************


*/


uint32_t bsp_sys_getstack(void)


{


uint32_t size = 0;


uint32_t* p = (uint32_t*)(*(uint32_t*)(*(uint32_t*)0xE000ED08) - 0x4000);


while(*p == (uint32_t)0xA5A5A5A5)


{


size += 4;


p++;


}


return size;


}

Shell中输入stack命令查看(具体代码未贴出)

图片

8. 总结

简单来说软件实现栈检测,就是将栈初始化为固定值。如果栈有使用则初始化值会变化,软件从栈底开始查找看剩余多少内容没有被改写就是剩余多少栈未使用。软件检测不是可靠的,因为溢出可能是跳跃的,即栈底一部分实际未用指针直接跳到了更后面的溢出位置,软件检测还存在延迟,所以软件检测一般可用于评估栈使用大小。使用硬件MPU更可靠,设置只有本任务只能访问本任务栈对应的空间,一旦访问其他空间就可以触发MPU中断这样更及时可靠检测。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5016

    文章

    18489

    浏览量

    293042
  • MPU
    MPU
    +关注

    关注

    0

    文章

    306

    浏览量

    48477
  • 函数
    +关注

    关注

    3

    文章

    4117

    浏览量

    61547
  • 代码
    +关注

    关注

    30

    文章

    4596

    浏览量

    67327
  • FreeRTOS
    +关注

    关注

    12

    文章

    474

    浏览量

    61516
收藏 人收藏

    评论

    相关推荐

    转:第11章 FreeRTOS任务大小确定及其溢出检测

    本章节为大家讲解FreeRTOS任务大小的确定方法以及溢出检测方法。给任务分配多大的空间,一直是初学者比较头疼的问题,本章就主要为大家
    发表于 08-28 15:21

    第10章 RL-TCPnet网络协议移植(FreeRTOS

    转最新教程本章教程为大家讲解RL-TCPnet网络协议FreeRTOS操作系统移植方式,学习了第6章讲解的底层驱动接口函数之后,移植就比较容易了,主要是添加库文件、配置文件和驱动文件即可。另外
    发表于 10-25 11:39

    freertos 堆栈问题

    公司有个项目,使用freertos系统,别人做的项目,我看他配置的系统只有1K,明显太小,但能够正常使用。使用系统时,只要任务够用就行,不用管系统大小吗?
    发表于 05-27 11:24

    请问在IAR中如何直接查看任务使用多少空间?

    在使用IAR调试freertos任务中,IAR自带了一个调试插件,启用这个插件会得到任务名、优先级、起始空间和顶位置,但是如何计算出每个任务具体使用了多少堆栈空间呢?还有就是在freert
    发表于 06-10 09:25

    FreeRTOS任务与系统的关系?

    在使用FreeRTOS时一直存在对设置的疑问,见以下三点疑问:1、Starup_stm32f40_41xxx.s中的“Stack_SizeEQU0x00001000”这里的设置的作用?2、在工程
    发表于 07-15 00:17

    freertos与STM32如何分配堆栈空间

    freertos与STM32分析、堆、全局区、常量区、代码区、RAM、ROM,及如何分配堆栈空间基于STM32分析、堆、全局区、常量区、代码区、RAM、ROM FreeRTOS任务
    发表于 08-03 06:36

    ThreadX任务大小的确定方法以及溢出检测方法

    第10章 ThreadX任务大小确定及其溢出检测本章节为大家讲解ThreadX任务大小的确定方法以及溢出检测方法。给任务分配多大的
    发表于 08-04 08:59

    讲解ThreadX任务大小的确定方法以及溢出检测方法

    第10章 ThreadX任务大小确定及其溢出检测本章节为大家讲解ThreadX任务大小的确定方法以及溢出检测方法。给任务分配多大的
    发表于 08-09 06:30

    RL-TCPnet网络协议FreeRTOS版本移植方式

    第8章 RL-TCPnet网络协议移植(FreeRTOS)本章教程为大家讲解RL-TCPnet网络协议FreeRTOS版本移植方式。目录第8章 RL-TCPnet网络协议
    发表于 08-11 08:25

    FreeRTOS中的任务堆栈溢出检测机制

    合理的任务堆栈大小,并实际运行程序进行测试,来确保系统运行过程中不会发生堆栈溢出。FreeRTOS中的任务堆栈溢出检测机制:在FreeRTOS中,也提供了一些API函数用来检测任务堆栈
    发表于 10-15 13:51

    怎样将LWIP协议移植到FreeRTOS上呢

    怎样将LWIP协议移植到FreeRTOS上呢?需要修改的文件有哪些呢?
    发表于 10-27 07:37

    SC0082 AT32在FreeRTOS上运行LwIP协议

    示例目的演示在FreeRTOS上运行LwIP协议,并搭建一个UDP echo server支持型号列表:支持型号AT32F407xxAT32F437xx主要使用外设列表:主要使用外设
    发表于 08-23 21:01

    从0到1学习FreeRTOSFreeRTOS 内核应用开发:(一)移植FreeRTOS到STM32第一部分

    从0到1学习FreeRTOSFreeRTOS 内核应用开发:(一)移植FreeRTOS到STM32第一部分
    发表于 12-04 12:51 22次下载
    从0到1学习<b class='flag-5'>FreeRTOS</b>:<b class='flag-5'>FreeRTOS</b> 内核应用开发:(一)移植<b class='flag-5'>FreeRTOS</b>到STM32第一部分

    初入FreeRTOS

    目录一、FreeRTOS介绍1、初识FreeRTOS,什么是 FreeRTOS2、FreeRTOS的特点二、FreeRTOS移植1、
    发表于 12-06 21:06 37次下载
    初入<b class='flag-5'>FreeRTOS</b>

    FreeRTOS系列第8篇---FreeRTOS内存管理

    本文介绍内存管理的基础知识,详细源码分析见《 FreeRTOS高级篇7---FreeRTOS内存管理分析》
    发表于 01-26 17:56 17次下载
    <b class='flag-5'>FreeRTOS</b>系列第8篇---<b class='flag-5'>FreeRTOS</b>内存管理