0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Freertos棧檢測

嵌入式USB開發(fā) ? 來源:嵌入式USB開發(fā) ? 作者:嵌入式USB開發(fā) ? 2023-09-19 14:03 ? 次閱讀

本文轉(zhuǎn)自公眾號,歡迎關(guān)注
https://mp.weixin.qq.com/s/uzaGLFTDBAn8wyR84yaiIw

1. 前言

RTOS的環(huán)境開發(fā)中,棧的溢出檢測是一個重要的工作。棧溢出檢測我們可以借助硬件的MPU等實(shí)現(xiàn),也可以使用軟件檢測。這里分享Freertos中的實(shí)現(xiàn)。這里基于Cortex-M4硬件平臺,一些具體的代碼就未貼出了,順便介紹了一下Cortex-M4棧相關(guān)的基礎(chǔ)知識。

2. 棧初始化

2.1任務(wù)啟動前棧

復(fù)位后匯編代碼

IMPORT  __main


LDR     R0, =SystemInit


BLX     R0


LDR     R0, =__main


BX      R0


ENDP

會進(jìn)入__main將棧內(nèi)容寫為0。該部分由編譯器產(chǎn)生代碼實(shí)現(xiàn)。

棧的位置是鏈接腳本中指定。

2.2任務(wù)棧

xTaskCreate -> prvInitialiseNewTask將任務(wù)棧填充為tskSTACK_FILL_BYTE = ( 0xa5U )

然后調(diào)用pxPortInitialiseStack初始化任務(wù)棧上下文

任務(wù)初始化時
高地址
->任務(wù)切出時棧指針
低地址
任務(wù)運(yùn)行一段時間后
高地址
已使用部分
->任務(wù)切出時棧指針
未使用部分
低地址

對應(yīng)實(shí)際中斷后的棧如下:

3.任務(wù)切換

vPortSVCHandler函數(shù)模擬中斷返回

__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即指向任務(wù)棧表中R4位置

ldmia r0!, {r4-r11, r14}是恢復(fù)R4-R11和portINITIAL_EXC_RETURN

msr psp, r0,更新棧指針,指向指向任務(wù)棧表中R0位置

bx r14模擬中斷返回 恢復(fù)R0-R3 R12 PC xPSR(硬件實(shí)現(xiàn))。

由于R14=portINITIAL_EXC_RETURN=0xfffffffd

根據(jù)手冊描述

圖片

返回時使用PSP棧,返回后使用PSP棧。與初始化對應(yīng)。

4.任務(wù)return

棧初始化時LR = prvTaskExitError 進(jìn)入子函數(shù)時LR會入棧,退出子函數(shù)時LR出棧。

所以如果任務(wù)不是while(1)形式而是在最后return則最終會進(jìn)入

prvTaskExitError執(zhí)行。一般rtos的任務(wù)都是while(1)結(jié)構(gòu) 不return。

5.棧指針

復(fù)位后使用MSP,任務(wù)根據(jù)返回時的LR值portINITIAL_EXC_RETURN使用PSP見“2.任務(wù)切換”。

中斷中固定使用MSP。

圖片

6.棧使用

中斷函數(shù)和mian使用中斷向量第一個字指向的棧區(qū)域。

任務(wù)使用任務(wù)棧。

在os啟動前默認(rèn)時使用msp,根據(jù)中斷向量的第一個字加載msp

硬件實(shí)現(xiàn),或者bootloader跳轉(zhuǎn)到應(yīng)用時配置。

啟動os時prvStartFirstTask,又重新將中斷向量第一個字加載到msp。

今后中斷就使用msp對應(yīng)的棧,即os啟動前main使用的棧。

因?yàn)閙ain一去不復(fù)返,所以這里覆蓋使用main時的棧,這樣可以節(jié)約內(nèi)存。

/* 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任務(wù)棧檢測

棧初始化時全部初始化為0xA5,運(yùn)行一段時間后棧頂部分使用變?yōu)槠渌怠?/p>

檢查棧底有多少連續(xù)的0xA5即可知道棧剩余多少。

圖片

Freertos提供接口函數(shù)uxTaskGetSystemState獲取棧信息

Shell中輸入ps查看(具體代碼未貼出)。

圖片

7.2中斷棧/main函數(shù)棧檢測

根據(jù)4.和5.的分析,中斷和main函數(shù)棧使用中斷向量第一個字對應(yīng)的棧區(qū)域。

由于__main.c會將棧內(nèi)容清除為0.所以在啟動第一個任務(wù)前將棧重新填充為0xa5。

有__main.c之前將棧填充為0xa5又會被清除為0,將填充代碼放在了任務(wù)啟動前prvStartFirstTask函數(shù)中。這樣main函數(shù)到prvStartFirstTask之前的棧使用大小不可監(jiān)控。

只能監(jiān)控后續(xù)中斷使用的棧大小。如果要檢測main函數(shù)棧使用則要將填充代碼放在main函數(shù)執(zhí)行的第一條代碼后,需要嵌入?yún)R編影響代碼閱讀和可移植性,所以不按這種方式。

實(shí)際上main函數(shù)棧溢出也沒關(guān)系 ,但是編程必須要求提供手動初始化變量的代碼,而不是依賴于編譯器的初始化。

比如有一個變量static int i =0;

編譯器提供代碼在__main中會對該變量初始化,如果main函數(shù)棧溢出覆蓋了這個變量的值。

那么在任務(wù)函數(shù)執(zhí)行時提供 void mode_init(void)函數(shù)

手動再次初始化該變量i=0.

就可以避免問題。

建議在模塊任務(wù)啟動時對屬于模塊的全局變量再次提供”構(gòu)造函數(shù)”手動初始化。

修改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需要根據(jù)實(shí)際設(shè)置的棧大小修改。0xE000ED08為中斷向量表地址。

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


* fn          uint32_t bsp_sys_getstack(void)


* brief       獲取棧大小.


* note        .


* return      剩余棧字節(jié)數(shù)


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


*/


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. 總結(jié)

簡單來說軟件實(shí)現(xiàn)棧檢測,就是將棧初始化為固定值。如果棧有使用則初始化值會變化,軟件從棧底開始查找看剩余多少內(nèi)容沒有被改寫就是剩余多少棧未使用。軟件檢測不是可靠的,因?yàn)橐绯隹赡苁翘S的,即棧底一部分實(shí)際未用指針直接跳到了更后面的溢出位置,軟件檢測還存在延遲,所以軟件檢測一般可用于評估棧使用大小。使用硬件MPU更可靠,設(shè)置只有本任務(wù)只能訪問本任務(wù)棧對應(yīng)的空間,一旦訪問其他空間就可以觸發(fā)MPU中斷這樣更及時可靠檢測。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5059

    文章

    18973

    瀏覽量

    302033
  • MPU
    MPU
    +關(guān)注

    關(guān)注

    0

    文章

    340

    瀏覽量

    48699
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4277

    瀏覽量

    62323
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68231
  • FreeRTOS
    +關(guān)注

    關(guān)注

    12

    文章

    483

    瀏覽量

    61915
收藏 人收藏

    評論

    相關(guān)推薦

    轉(zhuǎn):第11章 FreeRTOS任務(wù)大小確定及其溢出檢測

    本章節(jié)為大家講解FreeRTOS任務(wù)大小的確定方法以及溢出檢測方法。給任務(wù)分配多大的空間,一直是初學(xué)者比較頭疼的問題,本章就主要為大家
    發(fā)表于 08-28 15:21

    第10章 RL-TCPnet網(wǎng)絡(luò)協(xié)議移植(FreeRTOS

    轉(zhuǎn)最新教程本章教程為大家講解RL-TCPnet網(wǎng)絡(luò)協(xié)議FreeRTOS操作系統(tǒng)移植方式,學(xué)習(xí)了第6章講解的底層驅(qū)動接口函數(shù)之后,移植就比較容易了,主要是添加庫文件、配置文件和驅(qū)動文件即可。另外
    發(fā)表于 10-25 11:39

    freertos 堆棧問題

    公司有個項(xiàng)目,使用freertos系統(tǒng),別人做的項(xiàng)目,我看他配置的系統(tǒng)只有1K,明顯太小,但能夠正常使用。使用系統(tǒng)時,只要任務(wù)夠用就行,不用管系統(tǒng)大小嗎?
    發(fā)表于 05-27 11:24

    FreeRTOS任務(wù)與系統(tǒng)的關(guān)系?

    在使用FreeRTOS時一直存在對設(shè)置的疑問,見以下三點(diǎn)疑問:1、Starup_stm32f40_41xxx.s中的“Stack_SizeEQU0x00001000”這里的設(shè)置的作用?2、在工程
    發(fā)表于 07-15 00:17

    freertos與STM32如何分配堆棧空間

    freertos與STM32分析、堆、全局區(qū)、常量區(qū)、代碼區(qū)、RAM、ROM,及如何分配堆??臻g基于STM32分析、堆、全局區(qū)、常量區(qū)、代碼區(qū)、RAM、ROM FreeRTOS任務(wù)
    發(fā)表于 08-03 06:36

    ThreadX任務(wù)大小的確定方法以及溢出檢測方法

    第10章 ThreadX任務(wù)大小確定及其溢出檢測本章節(jié)為大家講解ThreadX任務(wù)大小的確定方法以及溢出檢測方法。給任務(wù)分配多大的
    發(fā)表于 08-04 08:59

    講解ThreadX任務(wù)大小的確定方法以及溢出檢測方法

    第10章 ThreadX任務(wù)大小確定及其溢出檢測本章節(jié)為大家講解ThreadX任務(wù)大小的確定方法以及溢出檢測方法。給任務(wù)分配多大的
    發(fā)表于 08-09 06:30

    RL-TCPnet網(wǎng)絡(luò)協(xié)議FreeRTOS版本移植方式

    第8章 RL-TCPnet網(wǎng)絡(luò)協(xié)議移植(FreeRTOS)本章教程為大家講解RL-TCPnet網(wǎng)絡(luò)協(xié)議FreeRTOS版本移植方式。目錄第8章 RL-TCPnet網(wǎng)絡(luò)協(xié)議
    發(fā)表于 08-11 08:25

    FreeRTOS中的任務(wù)堆棧溢出檢測機(jī)制

    合理的任務(wù)堆棧大小,并實(shí)際運(yùn)行程序進(jìn)行測試,來確保系統(tǒng)運(yùn)行過程中不會發(fā)生堆棧溢出。FreeRTOS中的任務(wù)堆棧溢出檢測機(jī)制:在FreeRTOS中,也提供了一些API函數(shù)用來檢測任務(wù)堆棧
    發(fā)表于 10-15 13:51

    怎樣將LWIP協(xié)議移植到FreeRTOS上呢

    怎樣將LWIP協(xié)議移植到FreeRTOS上呢?需要修改的文件有哪些呢?
    發(fā)表于 10-27 07:37

    亞馬遜發(fā)布新版本FreeRTOS 1.3.2,修復(fù)了FreeRTOS中的漏洞

    Zimperium zLabs的安全研究員們分析了FreeRTOS的TCP/IP協(xié)議,及亞馬遜云服務(wù)(AWS)安全連接模塊,發(fā)現(xiàn)其中存在的十余個漏洞也對OpenRTOS與SafeRTOS有影響。
    的頭像 發(fā)表于 10-22 11:10 ?3766次閱讀

    使用FreeRTOS和以太網(wǎng)協(xié)議LwIP設(shè)計(jì)SNTP網(wǎng)絡(luò)對時的詳細(xì)說明

    闡述了基于TI公司Cortex-M3內(nèi)核的LM9D96和Maxim公司DS1302的實(shí)時時鐘硬件平臺,在輕量級開源FreeRTOS實(shí)時操作系統(tǒng)和以太網(wǎng)協(xié)議LwIP下的SNTP網(wǎng)絡(luò)對時設(shè)計(jì)方案。通過
    發(fā)表于 12-05 16:19 ?78次下載
    使用<b class='flag-5'>FreeRTOS</b>和以太網(wǎng)協(xié)議<b class='flag-5'>棧</b>LwIP設(shè)計(jì)SNTP網(wǎng)絡(luò)對時的詳細(xì)說明

    初入FreeRTOS

    目錄一、FreeRTOS介紹1、初識FreeRTOS,什么是 FreeRTOS2、FreeRTOS的特點(diǎn)二、FreeRTOS移植1、
    發(fā)表于 12-06 21:06 ?40次下載
    初入<b class='flag-5'>FreeRTOS</b>

    STM32 FreeRTOS里用(插上)USB就死機(jī)

    用STM32CubeMX生成的USB HID工程,不帶FreeRTOS沒問題,帶了后,插USB就死機(jī)實(shí)際的死機(jī)原因是USB任務(wù)溢出,這是庫自身的問題,醉了將128改大點(diǎn)就行了...
    發(fā)表于 12-09 09:06 ?17次下載
    STM32 <b class='flag-5'>FreeRTOS</b>里用(插上)USB就死機(jī)

    UCD3138器件上的溢出檢測

    電子發(fā)燒友網(wǎng)站提供《UCD3138器件上的溢出檢測.pdf》資料免費(fèi)下載
    發(fā)表于 09-02 09:58 ?0次下載
    UCD3138器件上的<b class='flag-5'>棧</b>溢出<b class='flag-5'>檢測</b>