大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是利用 IAR 自帶 CRC 完整性校驗功能的一次實踐(為 KBOOT 加 BCA)。
痞子衡之前寫過兩篇關于 IAR 中自帶 CRC 校驗功能的文章 《在 IAR 開發(fā)環(huán)境下為工程開啟 CRC 完整性校驗功能的方法》、《探析開啟 CRC 完整性校驗的 IAR 工程生成 .out 和 .bin 文件先后順序》,算是把這個功能細節(jié)介紹得比較清楚了,但是俗話說得好,理論懂得再多,不能用于實踐那等于沒學。今天痞子衡就利用這個功能來解決一個實際需求:
?
一、KBOOT 中 BCA 填入 CRC 校驗需求
說起這個需求,記得那是 2014 年的第一場雪,那時候痞子衡正在飛思卡爾軟件組參與 Kinetis Bootloader 項目(簡稱 KBOOT)的研發(fā),痞子衡為這個項目寫過一些文章,詳見 《飛思卡爾 Kinetis 系列 MCU 開發(fā)那些事》 里的啟動篇系列,Kinetis 是飛思卡爾當時主推的 Cortex-M 微控制器,KBOOT 就是為 Kinetis 設計的全功能 Bootloader,這可能是嵌入式世界里第一個精心設計的通用架構 Bootloader。這個 Bootloader 包含一個用戶配置功能(BCA),簡單說就是在用戶 Application 的偏移 0x3c0 - 0x3ff 這 16 個 word 存放一些 Bootloader 配置,當 Bootloader 運行時會先嘗試從 Application 區(qū)域讀出這 16 個 word,獲取用戶配置(超時時間、外設類型、id、速度選項等),然后根據(jù)用戶配置再去啟動或升級用戶 Application。
CRC 完整性校驗功能占據(jù)了 BCA 里的 12 個 byte,是一個很重要的 Bootloader 特性,其完整功能詳見 《KBOOT 特性(完整性檢測)》,今天痞子衡要說的需求就是直接在 Application 工程編譯時生成包含正確 CRC 相關參數(shù)的 BCA,而不是像以前那樣在最終 binary 文件里二次編輯添加。
我們以 MK64FN1M 這顆芯片為例,下載它的軟件包,軟件包里有 KBOOT 及其示例 Application,找到 SDK_2.8.2_FRDM-K64Fboardsfrdmk64fbootloader_examplesdemo_appsled_demo_freedom_a000iar 下的 Application 工程,工程源文件 startup_MK64F12.s 里定義了 __bootloaderConfigurationArea,但是 CRC 區(qū)域是全 0xFF(即沒有使能),編譯生成的 bin 文件里 CRC 區(qū)域也是全 0xFF,我們要做的就是填入正確的 CRC。
?
二、開始動手實踐
2.1 確定匹配的 CRC 算法參數(shù)設置
在 KBOOT 用戶手冊里可以找到其 CRC 具體算法,它使用的是比較主流的 CRC32-MPEG2 分支,具體參數(shù)如下表所示:
為了方便核對結果,痞子衡找了一個在線 CRC 計算的網站,利用這個網站,設置與 KBOOT 一致的 CRC 參數(shù)(下圖紅色框內),然后我們選取 led_demo_freedom_a000.bin 的前 16 個字節(jié)(下圖藍色框內)作為測試數(shù)據(jù)輸入,點擊 Calculate CRC 按鈕生成結果 0x8D96BDF0(下圖紫色框內)。
在線網站:http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
我們現(xiàn)在回到 led_demo_freedom_a000 工程,在 Linker/Checksum 下,使能 CRC 功能,為了與上述測試一致,CRC 計算范圍設為 0xa000 - 0xa00f(因為程序起始鏈接地址是 0xa000,所以也就是最終 .bin 里的前 16 個字節(jié))。查閱 IAR development 手冊,做了如下 CRC 算法參數(shù)設置,編譯工程得到結果也是 0x8D96BDF0,因此 CRC 設置是匹配的。
?
2.2 填充 BCA 的首次嘗試
確認了 CRC 設置,現(xiàn)在就是修改源代碼了,在 BCA 的 CRC 區(qū)域里將初始的 0xFF 值全部更換為真實的 CRC 設置值 __checksum、__checksum_begin、__checksum_end,代碼簡單修改如下。重編工程后查看 .bin 文件,發(fā)現(xiàn)起止范圍兩個參數(shù)是對的,但是 CRC 校驗值并不對,填成了 0x0000a7fc,查看 map 文件得知這是 __checksum 的鏈接地址,并不是 __checksum 的值。想想也是,CRC 校驗值是鏈接生成 bin 后才計算的,但源文件是在鏈接前編譯的,不可能在編譯時得到鏈接后的結果。
- Note: 上圖中有筆誤,左邊匯編代碼第 306 行應更改為(__checksum_end - __checksum_begin + 1),因為這是 crcByteCount,下同。
2.3 填充 BCA 的最終方案
首次嘗試失敗,事情遠沒有想象得那么簡單,我們需要在工程鏈接文件上動心思,要直接把 __checksum 鏈接到 BCA 里的具體偏移位置。因此 startup_MK64F12.s 里 __bootloaderConfigurationArea 從 crcExpectedValue 及其之后全部去掉,并且 __FlashConfig 也實際不需要(僅對于鏈接在 0 地址才有效,這是 Kinetis 特性)。
然后我們需要重新在 main.c 里定義一個 bca 常量數(shù)組,把除 crcExpectedValue 之外缺失的 BCA 數(shù)據(jù)全部放進去。
const?uint32_t?bca[16]?@?".bca_left"?=?{0x1388ffff,?0xffffffff,?0xffffffff,?0xffffffff,
????????????????????????????????????????0xffffffff,?0xffffffff,?0xffffffff,?0xffffffff,
????????????????????????????????????????0xffffffff,?0xffffffff,?0xffffffff,?0xffffffff,
????????????????????????????????????????0xffffffff,?0xffffffff,?0xffffffff,?0xffffffff};
最后我們需要修改鏈接文件 MK64FN1M0xxx12_application_0xA000.icf 如下:
//place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec, readonly section .noinit };
//place in FLASH_region { block ApplicationFlash };
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place at address mem:0xa3cc { ro section .checksum };
place at address mem:0xa3d0 { ro section .bca_left };
place in FLASH_region { readonly section .noinit, block ApplicationFlash };
經過這么一番操作,讓我們重新編譯工程再看 bin 里結果,哈哈,這次 BCA 果然是正確的 CRC 校驗值了(這次值是 0xf62ce2b6,發(fā)生了變化,因為源代碼的改動,bin 前 16 個字節(jié)內容也相應變化了),大功告成。底下的事情就簡單了,在 CRC 設置界面里調整想要的 CRC 計算范圍即可。
至此,利用 IAR 自帶 CRC 完整性校驗功能的一次實踐(為 KBOOT 加 BCA)痞子衡便介紹完畢了,掌聲在哪里~~~