如何實現(xiàn)FreeRTOS應(yīng)用到安全SAFERTOS的遷移
轉(zhuǎn)自 | 麥克泰技術(shù)
FreeRTOS是一個面向微控制器和小型微處理器的實時操作系統(tǒng),基于MIT license許可分發(fā),F(xiàn)reeRTOS的構(gòu)建強調(diào)可靠性和易用性。
汽車、醫(yī)療和工業(yè)等市場的安全規(guī)范意味著設(shè)計者需要一個相關(guān)行業(yè)標(biāo)準(zhǔn)認(rèn)證過的RTOS,但認(rèn)證RTOS在長期的安全項目初期將是一筆昂貴的開支。
SAFERTOS是一個安全關(guān)鍵RTOS,通過了IEC61508和ISO26262預(yù)認(rèn)證。SAFERTOS采用與FreeRTOS相同的功能模型,為安全而構(gòu)建。安全產(chǎn)品中,項目原型可以使用FreeRTOS內(nèi)核實現(xiàn),在正式開發(fā)階段再轉(zhuǎn)為SAFERTOS。
本文通過一個簡單的示例項目說明如何將一個FreeRTOS應(yīng)用遷移到SAFERTOS。
硬件平臺:NXP Freedom K64F開發(fā)板- FRDM K64F
開發(fā)環(huán)境:MCUXpresso IDE v11.1
示例項目可免費從
www.highintegritysystems.com/down-loads/下載。
項目包含3個工程:
1、FreeRTOS_Demo-基礎(chǔ)的FreeRTOS工程
2、RTOS_Demo-特權(quán)模式的SAFERTOS工程
3、RTOS_UnprvDemo-具有非特權(quán)任務(wù)的SAFERTOS項目
FreeRTOS和SAFERTOS主要區(qū)別
與FreeRTOS相比,SAFERTOS:
· API函數(shù)更少
· 函數(shù)中執(zhí)行了更多的錯誤檢查
· 大多數(shù)API調(diào)用會返回狀態(tài)碼,其它函數(shù)通過引用返回數(shù)據(jù)
· 需要應(yīng)用提供所有堆棧,任務(wù)控制塊和隊列緩沖區(qū)內(nèi)存
· 使用靜態(tài)分配機制,不提供heap函數(shù)
· 默認(rèn)使用處理器的MPU單元
· 完全重新設(shè)計,滿足安全關(guān)鍵軟件需求
因此,當(dāng)將FreeRTOS項目遷移到SAFERTOS時,需要做一些工作來完成內(nèi)核啟動和運行。
FreeRTOS內(nèi)部隱藏了許多常規(guī)內(nèi)存管理,在任務(wù)創(chuàng)建時動態(tài)分配堆棧,在內(nèi)核啟動時分配內(nèi)核緩沖區(qū)等。在Free RTOS中也可以配置靜態(tài)分配,由應(yīng)用程序提供內(nèi)存,但大多數(shù)人傾向于更簡單的方法,讓FreeRTOS實現(xiàn)。
FreeRTOS還提供了許多編譯選項,并通過hook宏機制,允許應(yīng)用程序設(shè)計者在內(nèi)核中插入額外的功能代碼,在任務(wù)切換時運行,例如,在任務(wù)刪除或創(chuàng)建時,運行額外的hook函數(shù)。
API區(qū)別
RTOS定義的類型名稱不同。使用FreeRTOS,應(yīng)用程序文件需要包含(#include)API(任務(wù),隊列,信號量)相應(yīng)的頭文件;SAFERTOS中,應(yīng)用程序文件只需要包含一個SafeRTOS_API.h頭文件。
靜態(tài)分配及MPU
SAFERTOS要求應(yīng)用任務(wù)和內(nèi)核對象所需的內(nèi)存靜態(tài)分配。安全嚴(yán)格系統(tǒng)推薦靜態(tài)分配機制,容易證明運行時有足夠的內(nèi)存空間。
絕大多數(shù)SAFERTOS移植中假定使用了MPU。MPU的使用意味著應(yīng)用程序設(shè)計人員需要監(jiān)督內(nèi)存結(jié)構(gòu)地址的確切位置,包括內(nèi)核任務(wù)和隊列緩沖區(qū)。此外,MPU還需滿足區(qū)域的對齊和大小限制,應(yīng)用程序工程師需要仔細(xì)安排空間,以避免空間浪費。
因此,使用FreeRTOS時,在調(diào)用xTaskCreate之前,需確保heap中足夠的空閑空間。使用SAFERTOS,需要預(yù)先分配并定位對齊的堆棧及任務(wù)TCB內(nèi)存,然后將指向這些結(jié)構(gòu)的指針傳遞到xTaskCreate的相應(yīng)參數(shù)。
任務(wù)特權(quán)模式及內(nèi)核函數(shù)封裝層
每個SAFERTOS任務(wù)被分配一個操作權(quán)限,特權(quán)(Privileged)任務(wù)與內(nèi)核代碼具有相同的權(quán)限,許多CPU支持特權(quán)(privileged)和非特權(quán)(unprivileged)模式,限制非特權(quán)模式的指令訪問,有限的軟件trap、異常和中斷等。
通常,應(yīng)用程序以非特權(quán)模式運行,每個任務(wù)都提供了一組MPU參數(shù),這些參數(shù)在任務(wù)切換時配置相應(yīng)的MPU域。
SAFERTOS任務(wù)創(chuàng)建時,增加了一個MPU域,定義用戶任務(wù)堆棧,確保任務(wù)只訪問自己的堆棧。
內(nèi)核API工作在特權(quán)模式,SAFERTOS的每個API有一個權(quán)限升級封裝(privilege-escalating wrapper)層,通過觸發(fā)異常(通常是系統(tǒng)調(diào)用)、同步中斷或CPU的trap實現(xiàn)。API的封裝層通過臨時提升任務(wù)權(quán)限,允許非特權(quán)任務(wù)執(zhí)行內(nèi)核API,執(zhí)行完成后降回任務(wù)原先的權(quán)限。因為實際的API函數(shù)與調(diào)用時的名稱不同,調(diào)試不方便。
盡管FreeRTOS也通過權(quán)限升級封裝類似的機制支持MPU功能,但僅提供了有限的MPU移植參考。在SAFERTOS中,我們假定應(yīng)用任務(wù)運行非特權(quán)模式。在FreeRTOS MPU移植中,任務(wù)通常被假定為運行特權(quán)模式,但是任務(wù)可以選擇創(chuàng)建為restricted,即非特權(quán)模式。
基于FreeRTOS的應(yīng)用
示例項目中包含一個向?qū)葾mazon FreeRTOS項目:FreeRTOS_Demo。
自動生成的鏈接文件
工程構(gòu)建后,將自動生成鏈接定位文件,由于SAFERTOS工程中,需修改鏈接文件,我們不希望自動生成的鏈接文件覆蓋已修改內(nèi)容,將生成的鏈接文件從Debug目錄遷移到單獨的目錄,并在工程選項中關(guān)閉自動生成linker文件,并指向新的鏈接文件目錄。
應(yīng)用代碼
應(yīng)用包含3個LED任務(wù)和一個控制任務(wù),控制任務(wù)更新每個LED的“目標(biāo)亮度”值的全局?jǐn)?shù)組,并使用互斥信號量監(jiān)視全局?jǐn)?shù)組的訪問。全局?jǐn)?shù)組不是任務(wù)之間通信的最佳方法,但我們的目標(biāo)是提供簡單的示例,說明從FreeRTOS如何轉(zhuǎn)換為SAFERTOS。
從FreeRTOS遷移到SAFERTOS
一,將工程升級為SAFERTOS,所有代碼運行在privileged模式
1、替換FreeRTOS內(nèi)核代碼為SAFERTOS
刪除工程amazon-freertos目錄中的代碼,替換為SAFERTOS庫及頭文件,修改工程options中的include path-C/C++ Build/Settings->Tool Settings->MCU C compiler->includes,
向?qū)ё詣由傻墓こ讨校€需修改C/C++ General->Paths and Symbols>includes路徑信息。
2、 編輯鏈接文件,導(dǎo)出SAFERTOS需要的符號
SAFERTOS需要使用鏈接文件中定義的段和變量符號,設(shè)置MPU區(qū)域保護(hù)內(nèi)核代碼和數(shù)據(jù)。需要的段和符號可查閱portmpu.h文件。
內(nèi)核函數(shù)段名為kernel_func,內(nèi)核數(shù)據(jù)段為kernel_data,GCC中,內(nèi)核函數(shù)和數(shù)據(jù)通過段屬性放到相應(yīng)段中。
內(nèi)核函數(shù)通常緊隨向量表放置。內(nèi)核數(shù)據(jù)被放置RAM中的某個位置,需符合MPU對齊需要。
鏈接文件還需導(dǎo)出段起始和結(jié)束符號,ROM及RAM的起始地址、結(jié)束地址及大小。
在portmpu.h中,需要下列符號
·lnkStartFlashAddress
· lnkEndFlashAddress
· lnkStartKernelFunc
· lnkEndKernelFunc
· lnkStartKernelData
· lnkEndKernelData
· lnkRAMEnd(RTOS_Demo_Debug_memory.ld)
· lnkRAMStart(RTOS_Demo_Debug_memory.ld)
3、安裝SAFERTOS需要的中斷和異常
K6xxF移植中需要SysTick,PendSV,SVC中斷,這些函數(shù)使用CMSIS定義的實現(xiàn)處理,相應(yīng)的處理入口位于默認(rèn)的向量表位置,RTOS可以命名自己的異常處理函數(shù)。
在SAFERTOSConfig.h中,通過#defining 實現(xiàn)SAFERTOS異常處理替代CMSIS定義,但SAFERTOS庫文件無法修改,可以重新定義startup文件向量表中的CMSIS名稱。
工程代碼中,向量表定義位于startup_mk64f12.c文件,在該文件中插入:
/* SAFERTOS system tick, SVC and PendSV handlers */
#define SysTick_Handler vTaskProcessSystemTickFromISR
#define SVC_Handler vSafeRTOSSVCHandler
#define PendSV_Handler vSafeRTOSPendSVHandler
與FreeRTOS不同,SAFERTOS在啟動時檢查向量表條目,如果它們不存在或不正確,則拒絕運行。
4、內(nèi)核hook函數(shù)
SAFERTOS提供了有限的hook函數(shù),其中最主要的是Error Hook函數(shù)。在系統(tǒng)檢測到不可恢復(fù)錯誤時,進(jìn)入安全的錯誤狀態(tài)。例如檢測到被破壞的TCB或堆棧溢出,將調(diào)用error hook。項目中,error hook是一個簡單的無限循環(huán)(位于HookFunctions.c文件)。
5、內(nèi)核任務(wù)、內(nèi)核配置及啟動
除hook函數(shù)的地址外,還需將堆棧及TCB的地址和大小傳給空閑任務(wù)和timer任務(wù)(可選),內(nèi)核任務(wù)還需MPU參數(shù),timer 命令隊列等信息。SAFERTOS通過一個專用結(jié)構(gòu)將參數(shù)傳給專用的API來配置內(nèi)核。應(yīng)用從FreeRTOS遷移到SAFERTOS最復(fù)雜的部分是配置并啟動調(diào)度器。
內(nèi)核配置(包含內(nèi)核任務(wù)堆棧和TCB)信息,放在單獨的SafeRTOSConfig.c文件中。
在內(nèi)核啟動的每個階段,當(dāng)配置結(jié)構(gòu)被傳遞到內(nèi)核配置函數(shù)后,內(nèi)核啟動,API將返回相應(yīng)的錯誤代碼。函數(shù)返回的錯誤代碼,可以在內(nèi)核include目錄的projdefs.h文件中查找含義。該文件列出了所有錯誤代碼信息。
對于示例應(yīng)用,還需使用一個“備用”MPU區(qū)域,建立一個全局MPU區(qū)域,以訪問板載LED的GPIO,這樣我們就不必提升相應(yīng)的任務(wù)權(quán)限以使用GPIO資源。在SafeRTOSConfig.c中,通過xMPUConfigureGlobal Region()調(diào)用設(shè)置了“全局”MPU區(qū)域,允許讀寫GPIO寄存器 (實際上,該區(qū)域包含所有的外設(shè)地址空間)。
6、應(yīng)用任務(wù)TCB和堆棧
為每個應(yīng)用任務(wù)設(shè)置堆棧和TCB,填充其它任務(wù)參數(shù)。
在FreeRTOS中,創(chuàng)建任務(wù)所需的6個參數(shù)直接傳遞給xTaskCreate()函數(shù),函數(shù)將返回新創(chuàng)建任務(wù)的句柄或pdFALL錯誤信息。在SAFERTOS中,任務(wù)參數(shù)更多,通過一個指向移植特定的xTaskParameters結(jié)構(gòu)參數(shù),傳遞給xTaskCreate(),第二個參數(shù)接收新創(chuàng)建任務(wù)的句柄,函數(shù)將返回pdPASS或錯誤碼。
在示例中可以看到,F(xiàn)reeRTOS與SAFERTOS的任務(wù)名稱和參數(shù)各不相同。SAFERTOS任務(wù)參數(shù)中還有每個任務(wù)的特權(quán)級別和MPU區(qū)域設(shè)置。第一步我們使所有任務(wù)都運行在特權(quán)級別,所以目前不需要額外的MPU參數(shù),這些參數(shù)設(shè)置為0/null。
7、更新調(diào)用的API
針對每個API調(diào)用,檢查并修改SAFERTOS對應(yīng)的函數(shù)名稱及返回值。
8、類型更新
除API函數(shù)名稱不同外,移植層定義的類型名也有區(qū)別??梢越柚鶬DE的search&replace功能替換。
二、修改應(yīng)用任務(wù)為非特權(quán)模式
我們已經(jīng)通過一個“全局MPU域”允許所有任務(wù)訪問使用的GPIO寄存器。任務(wù)被轉(zhuǎn)換為非特權(quán)模式后,還需要有哪些訪問權(quán)限?
將某個任務(wù)標(biāo)記為unprivileged,然后加載并運行應(yīng)用程序,如果應(yīng)用最終進(jìn)入MPU fault處理程序中。可以檢查調(diào)試器的寄存器以識別故障地址,可以嘗試使用調(diào)試器強制從處理程序返回,快速識別導(dǎo)致MPU故障的指令。
示例中,每個LED任務(wù)需要訪問共享的“brightness request”數(shù)組,處理訪問該數(shù)據(jù)的互斥量,互斥量buffer僅由內(nèi)核代碼訪問,任務(wù)如何實現(xiàn)訪問共享RAM region?
在鏈接文件中創(chuàng)建一個命名段,導(dǎo)出開始地址和大小符號,添加放置屬性來指定函數(shù)或變量的定位,在GCC中如下:
__attribute__ ( ( section ( “section_name”)))
最后,使用鏈接文件導(dǎo)出的段符號來定義MPU域,添加到任務(wù)MPU參數(shù)中,以獲得訪問權(quán)限。注意,導(dǎo)出的linker符號為地址,在聲明其為extern變量后,我們可以獲取符號的地址,或者將其聲明為數(shù)組類型,數(shù)組名將是其地址。
結(jié)論
本文通過一個簡單的示例工程及遷移過程,探討了FreeRTOS和SAFERTOS的差異。
通過示例項目,在FreeRTOS轉(zhuǎn)換為SAFERTOS的每個階段,分析預(yù)先配置的項目源代碼,運行每個版本,可以分析原來的FreeRTOS平臺上的應(yīng)用程序與最終的非特權(quán)版本之間的差異。
顯然,即使非常簡單的代碼,也有許多不同的SAFERTOS轉(zhuǎn)換實現(xiàn)方式,早期的設(shè)計決策也會影響轉(zhuǎn)換的簡單性。建議盡量減少使用FreeRTOS特有的API,使用內(nèi)核管理的任務(wù)間通信機制,使用FreeRTOS和SAFERTOS共享的類型名稱,可以讓事情變得更容易。
從應(yīng)用一開始就考慮到任務(wù)為非特權(quán)執(zhí)行模式,當(dāng)升級到安全應(yīng)用時,會更簡單。
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!