CRC校驗 | 程序如何檢查自身完整性?(1)
在一些比較嚴格的行業(yè)里面,不是說你的程序能完成必要功能就可以,還需要添加一些額外的功能,比如最常見的看門狗功能,它可以在程序死機時完成重啟,但也僅僅如此而已。很多異常它是無法檢查的,比如程序偶然跑飛,ram 異常、flash異常等其他問題,只有程序hardfault或者其他嚴重問題導致程無法喂狗時才能起作用。
所以有些產品為了保障安全,會增加安規(guī)代碼,保證程序能夠正常運行(UL/CSA/IEC 60730-1/60335-1 B類認證)。
自檢內容
MCU 安全檢查一般包括以下幾個方面:
1、CPU 自測(寄存器測試)
2、系統(tǒng)時鐘頻率測量(保證時鐘正常工作,不快也不慢,GD 芯片在短路晶振后,程序暫停運行,無法檢查,但是 ST 芯片會自動切換到內部時鐘,可以由程序檢查這種異常)
3、RAM 自檢
4、FLASH 存儲器完整性檢查
5、獨立看門狗、窗口看門狗檢查
6、安全相關變量檢查
7、中斷檢查
8、I/O 口檢查
9、棧檢查
10、程序流程控制
11、AD 口檢查
你會發(fā)現(xiàn)真要完成這份安規(guī)代碼,難度不是一般的大,不過一般芯片廠商會提供相關參考例程和相關文檔,但不是說有了這些資料就完全沒有問題了。
比如 ST 提供了一個參考例子,但是它使用的 HAL 庫(事實上它還有標準庫,當時不知道),如果原本程序用的標準庫,那么就需要進行移植,這個工作量也不是一般大(首先要能理解程序,才能進行正確移植,而里面的邏輯還是很復雜的)。如果你不想移植,還有一個辦法是使用 lib 庫,就是將相關功能打包成一個庫,雖然程序會大一些(畢竟很多底層代碼和原來的重復了),但確實是比較簡單的方法(前提是 flash 夠大)。
魚鷹走的是第一條路,移植,并且將相關的底層代碼提供了接口,這樣不管是用標準庫還是 HAL 庫,只要自己實現(xiàn)這這些特定的接口即可完成。
另外,參考例子只是實現(xiàn)了一個最基本的功能,在真正的產品不一定能適用。比如你的程序負載大,而里面為了測量時鐘頻率,幾百微秒時間就要進入一次中斷(即使是分頻后),如果剛好在中斷產生時,其他程序禁用了中斷,運行這些代碼有可能就會出現(xiàn)問題,很容易錯過中斷而導致復位。
在我一開始移植的時候就是如此,在一個簡單的程序里面可以正常運行很長時間,但是移植到產品工程里面,時不時出現(xiàn)時鐘檢查不通過的時候,導致程序不停重啟,最終魚鷹通過 DMA 傳輸?shù)姆绞浇鉀Q了這個問題,再也不會因為時鐘檢查不通過導致重啟了。
另外一個難點是對 .sct (分散加載)文件的理解,這個會在后面介紹。
安規(guī)相關的內容實在是太多,要寫的話可以寫成一個系列了,如果各位道友感興趣的話,多多轉發(fā)支持一下魚鷹,如果效果不錯,魚鷹會考慮完成后續(xù)的其它部分。(這里有一份比較全面但簡單一些的參考文章可以看看 http://news.eeworld.com.cn/mp/STM32/a80041.jspx,只介紹如何做,沒怎么介紹為什么這么做)
資料
ST 相關資料可以查看以下內容(www.st.com,下載時需要注冊郵箱才行,魚鷹公眾號后臺提供了部分資料,可自行領?。?/p>
《AN4435 應用筆記》中文版,《AN277》(ROM Self-Test)
STM8-SafeCLASSB
https://www.st.com/en/embedded-software/stm8-safeclassb.html
STM32-CLASSB-SPL(基于標準外設庫)
https://www.st.com/en/embedded-software/stm32-classb-spl.html#tools-software
X-CUBE-CLASSB(基于HAL庫)
https://www.st.com/en/embedded-software/x-cube-classb.html(不同版本有不同芯片,比如 2.2.0 版本的是 Fx 相關的,2.3.0 是H7、G0 相關的)
當然國產芯片也一般會提供例程。
本篇筆記只介紹其中一個內容,即 FLASH 檢查,換句話說就是程序完整性檢查。
FLASH 檢查
我們以比較復雜的 boot + app + rtos ,開發(fā)環(huán)境 keil 、stm32f103 為例介紹相關知識。
一般 boot 和 app 部分是用不同工程管理的,所以 app 部分代碼只能檢查自身的完整性,而不能檢查 boot 部分。
并且 app 的 flash 區(qū)也不是完全檢查的,有一小部分是也沒法檢查的,但這并不影響它的功能(既然已經跳轉到 app 里面了,那么 boot 部分 flash 即使在運行時有問題也不影響功能,而如果變量初始值的flash有問題就是關鍵變量檢查的問題了)。
現(xiàn)在就是如何檢查的問題了。
如何檢查 | 基本原理
校驗手段有很多,比如 和校驗、MD5 校驗、CRC 校驗,這里我們使用 CRC,因為一般芯片內部會內置該外設硬件計算(如果沒有,可以純 CPU 計算)。
然后我們需要了解完整性檢查的基本原理。
所謂程序完整性檢查,就是在下載代碼前,先用工具把要校驗的部分通過計算公式計算出一個值,保存在某個地方(flash),然后程序在運行的時候,自己也去讀取要校驗的 flash 部分,通過同樣的計算公式計算出一個值,然后將這個值和保存在 flash 里面的值進行比較,就可以看出代碼是否存在異常了,有異常及時處理,沒有異常就繼續(xù)重新檢查。
而檢查分成兩個步驟:
1、開機時,一次性完成所有計算,保證運行前完整。
2、正常運行時,定時計算,每次計算一個小塊,當計算完最后一塊時才比較結果,成功就重新繼續(xù)計算,失敗則終止程序運行,周而往復(計算需要較長的時間,分時計算可以不影響程序正常功能),這樣可以保證程序在運行時也能檢查 FLASH 的完整性,防止 FLASH 運行過程中破壞掉。
現(xiàn)在有個問題,CRC 保存在何處才是合適的?
隨便保存在一個地方肯定是不行的。假設這個位置在要校驗代碼部分的里面,那么當工具計算這個值時,又會篡改掉校驗部分里面的數(shù)據(因為你把 CRC 值放到里面了),那么你的程序校驗時,肯定不通過,因為你讀了一個被改變的 CRC 值。所以這個值一定要放在代碼的最后面才行。
另外前面說過,運行時會一小塊一小塊,所以要保證你的 CRC 值存放位置應該在小塊大小的邊界位置上。比如一次計算 16 字節(jié),那你存放的位置應該是 16 的倍數(shù)才是正常的。
所以,CRC 存放位置存在這兩個限制。
另外,如何提前計算好 CRC 的值呢?IAR 內置該功能,而 KEIL 我們可以借助強大的開源工具 SRecord《功能強大的 HEX 開源轉換工具,你值得擁有》(一轉眼,這篇文章差不多鴿了四個多月了)幫助我們計算。
基本知識都了解的差不多了,接下來就是如何操作的問題。
實操
1、固定 CRC 位置。
我們可以在啟動文件的最后加入以下代碼(END 前)
這里默認是 0x3D334398,但會在后續(xù)修改成正確的 CRC 值
;******************************************************************************* ; User Checksum - must be placed at the end of memory ;******************************************************************************* AREA CHECKSUM, DATA, READONLY, ALIGN=6 EXPORT __Check_Sum ; Alignement here must correspond to the size of tested block at FLASH run time test (16 words ~ 64 bytes)!!! ALIGN __Check_Sum DCD 0x3D334398; ; Check sum computed externaly
這里保證了 __Check_Sum 的地址是 2 ^ 6 大小對齊,所以你的計算小塊可以這個大小,當然也可以小一些,比如 2 ^ 5 等。這樣就可以將檢查部分分成固定的小塊,不會多,也不會少,剛剛好(必須)。
那么如何將這個地址固定在代碼最后呢?這個時候就需要我們的 .sct 文件發(fā)揮作用了
(ClassB_stm32F10x.sct)。 ER_IROM1 0x08000000 0x10000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) *.o (CHECKSUM, +Last) ;放置在最后 }
我們用了 +Last 將其放置在代碼的最后部分,你想把它放置在 bin 文件最后面?暫時魚鷹還沒想到怎么做,有知道的道友可以告訴魚鷹(通過 sct 的方式)。
2、CRC 計算腳本
在 windows 叫批處理,.bat ,我們可以在參考例程中找到。crc_gen_keil.bat
我們需要需改三個位置
第一個是你的計算工具的路徑,里面應該要有計算工具。
第二個就是你的工程名字,我們通過下面位置確定(魚鷹用的 Main):
最后是工程路徑。一般在 Objects 文件夾里面,而 map 文件一般在 Listings 文件夾里面。
說白了,這些變量就是為了讓腳本能夠找到 map、hex 文件和工具。但一般默認工程,這兩個文件可能不在一個文件夾里面,所以我們可以對例子中的批處理文件 crc_gen_keil.bat 進行適當修改。
map 文件的作用是為了讓腳本能夠搜索到 __Check_Sum 的地址,然后就可以計算 CRC 并修改 HEX 里面這個值了。
另外還有新增了一個變量 HEX_ADRR,當我們的計算位置不是從 0x08000000 開始時(比如 app 起始地址在 0x08009000),我們就可以修改這個變量值。還有我們希望在計算完并修改 CRC 后可以自己生成 bin 文件方便我們更新固件,還需要加入轉化成 bin 的命令。
其中為了下載修改(CRC)后的 HEX 文件,我們還需要簡單修改一下,用于判斷工具是否存在,不存在,直接刪除 hex 和 axf 文件(防止下載未修改的文件)。
%xxx% 類似腳本中的 $xxx
if not exist %SREC_PATH% ( echo %SREC_PATH% is not exit, exit echo ----------------------------------------del %INPUT_HEX% -- %AXF_FILE% --------------- del %INPUT_HEX% %AXF_FILE% exit )
*博客內容為網友個人發(fā)布,僅代表博主個人觀點,如有侵權請聯(lián)系工作人員刪除。
斷路器相關文章:斷路器原理
高壓真空斷路器相關文章:高壓真空斷路器原理 漏電斷路器相關文章:漏電斷路器原理