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





