大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是利用 IAR 自带 CRC 完整性校验功能的一次实践(为 KBOOT 加 BCA)。
痞子衡之前写过两篇关于 IAR 中自带 CRC 校验功能的文章 《在 IAR 开发环境下为工程开启 CRC 完整性校验功能的方法》、《探析开启 CRC 完整性校验的 IAR 工程生成 .out 和 .bin 文件先后顺序》,算是把这个功能细节介绍得比较清楚了,但是俗话说得好,理论懂得再多,不能用于实践那等于没学。今天痞子衡就利用这个功能来解决一个实际需求:
一、KBOOT 中 BCA 填入 CRC 校验需求
说起这个需求,记得那是 2014 年的第一场雪,那时候痞子衡正在飞思卡尔软件组参与 Kinetis Bootloader 项目(简称 KBOOT)的研发,痞子衡为这个项目写过一些文章,详见 《飞思卡尔 Kinetis 系列 MCU 开发那些事》 里的启动篇系列,Kinetis 是飞思卡尔当时主推的 Cortex-M 微控制器,KBOOT 就是为 Kinetis 设计的全功能 Bootloader,这可能是嵌入式世界里第一个精心设计的通用架构 Bootloader。这个 Bootloader 包含一个用户配置功能(BCA),简单说就是在用户 Application 的偏移 0x3c0 - 0x3ff 这 16 个 word 存放一些 Bootloader 配置,当 Bootloader 运行时会先尝试从 Application 区域读出这 16 个 word,获取用户配置(超时时间、外设类型、id、速度选项等),然后根据用户配置再去启动或升级用户 Application。
CRC 完整性校验功能占据了 BCA 里的 12 个 byte,是一个很重要的 Bootloader 特性,其完整功能详见 《KBOOT 特性(完整性检测)》,今天痞子衡要说的需求就是直接在 Application 工程编译时生成包含正确 CRC 相关参数的 BCA,而不是像以前那样在最终 binary 文件里二次编辑添加。
我们以 MK64FN1M 这颗芯片为例,下载它的软件包,软件包里有 KBOOT 及其示例 Application,找到 \SDK_2.8.2_FRDM-K64F\boards\frdmk64f\bootloader_examples\demo_apps\led_demo_freedom_a000\iar 下的 Application 工程,工程源文件 startup_MK64F12.s 里定义了 __bootloaderConfigurationArea,但是 CRC 区域是全 0xFF(即没有使能),编译生成的 bin 文件里 CRC 区域也是全 0xFF,我们要做的就是填入正确的 CRC。
二、开始动手实践
2.1 确定匹配的 CRC 算法参数设置
在 KBOOT 用户手册里可以找到其 CRC 具体算法,它使用的是比较主流的 CRC32-MPEG2 分支,具体参数如下表所示:
为了方便核对结果,痞子衡找了一个在线 CRC 计算的网站,利用这个网站,设置与 KBOOT 一致的 CRC 参数(下图红色框内),然后我们选取 led_demo_freedom_a000.bin 的前 16 个字节(下图蓝色框内)作为测试数据输入,点击 Calculate CRC 按钮生成结果 0x8D96BDF0(下图紫色框内)。
在线网站:http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
我们现在回到 led_demo_freedom_a000 工程,在 Linker/Checksum 下,使能 CRC 功能,为了与上述测试一致,CRC 计算范围设为 0xa000 - 0xa00f(因为程序起始链接地址是 0xa000,所以也就是最终 .bin 里的前 16 个字节)。查阅 IAR development 手册,做了如下 CRC 算法参数设置,编译工程得到结果也是 0x8D96BDF0,因此 CRC 设置是匹配的。
2.2 填充 BCA 的首次尝试
确认了 CRC 设置,现在就是修改源代码了,在 BCA 的 CRC 区域里将初始的 0xFF 值全部更换为真实的 CRC 设置值 __checksum、__checksum_begin、__checksum_end,代码简单修改如下。重编工程后查看 .bin 文件,发现起止范围两个参数是对的,但是 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 常量数组,把除 crcExpectedValue 之外缺失的 BCA 数据全部放进去。
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,发生了变化,因为源代码的改动,bin 前 16 个字节内容也相应变化了),大功告成。底下的事情就简单了,在 CRC 设置界面里调整想要的 CRC 计算范围即可。
至此,利用 IAR 自带 CRC 完整性校验功能的一次实践(为 KBOOT 加 BCA)痞子衡便介绍完毕了,掌声在哪里~~~