使用IAR Embedded Workbench和MCU的CRC模块来检查代码的完整性

Technical Note

Architectures:

All

Component:

general

Updated:

2023/7/21 9:17

保证代码的完整性是嵌入式软件开发中非常重要的一项任务。代码的完整性检查主要可以用于以下场合:

  1. 在产线生产的时候,通过读取相关软件代码版本号和相应的校验码来保证烧录到MCU中的软件是正确的;
  2. 在通过Bootloader升级Application的时候,可以计算Application对应的校验码并和之前存取的Application的校验码进行比较,保证Application升级的正确性;
  3. 在运行过程中,可以计算Application对应的校验码并和之前存取的Application校验码进行比较,保证Application在没有损坏的情况下运行。(注意:根据需求的不同,在运行过程中可以分为上电检查一次和运行过程中周期性地检查)。

代码的完整性检查一般是通过计算对应代码区域的校验码,并和之前存储的校验码进行比较,若二者一致,说明对应代码区域的完整性是好的,否则说明对应代码区域数据被损坏。当然,完整性检查准确率跟校验码有很大的关系,业界比较常用的是CRC。(注意:本文不对CRC原理进行详细说明,想了解更多关于CRC的内容,请参考相关文献。)

IAR Embedded Workbench中内嵌了ielftool,可以在Link的时候生成对应代码区域的校验码并存储在指定的地址。

目前越来越多的MCU中内嵌了CRC硬件模块,可以用于快速计算对应代码区域的校验码。(本文以STM32 MCU为例介绍,方法同样适用于其它带CRC硬件模块的MCU。)

本文主要介绍如何在IAR Embedded Workbench中生成对应代码区域的校验码并存储在指定的地址,然后利用MCU中内嵌的CRC硬件模块计算对应代码区域的校验码,并和之前存储的校验码进行比较来检查代码的完整性。

在IAR Embedded Workbench中生成对应代码区域的校验码并存储在指定的地址

下面的选项使用CRC-32/MPEG-2为例生成对应代码区域的校验码:

在IAR Embedded Workbench工程选项(Options)里面Linker选项里面生成Checksum

  1. 勾选“Fill unused code memory”, Fill pattern里面填充相应的值(关于填充值请参考:“填充没有使用的ROM来提高系统的健壮性”)
  2. Start address和End address输入对应代码区域的地址(注意:不能包括存放Checksum的地址区域。比如,Checksum存放与0x080FFFFC ~ 0x080FFFFF, End address需要输入0x080FFFFB)
  3. 勾选“Generate Checksum”:
  • Checksum Size: 选择 “4 bytes”,
  • Alignment: 输入 “4”,
  • Algorithm: 选择 “CRC32”
  • Complement: 选择 “As is”,
  • Initial value: 输入“0xFFFFFFFF”,不要勾选“Use as input”
  • Bit order: 选择 “MSB first”
  • 不要勾选 “Reverse byte order within word”
  • Checksum unit size: 选择 “32-bit”

在ICF文件中输入相应命令将Checksum放置指定的地址(这里是将checksum放置到Flash的最后):

place at end of FLASH_region { section .checksum };

构建(Build)并查看相关Log信息和map文件

构建(Build)成功之后,在Build窗口会显示对应代码区域的Checksum相关信息(Build窗口中的Filter Level要为All):

查看生成的map文件:
__checksum:存放于地址0x80f'fffc ~ 0x80f'ffff (Size: 4 bytes)

__checksum_begin: Checksum计算的起始地址:0x800'0000

__checksum_end: Checksum计算的结束地址:0x80f'fffb

在代码中调用CRC硬件模块计算对应代码区域的校验码并和之前存储的校验码进行比较

首先需要在代码中声明Checksum相关的变量:

/* Linker generated symbols */
extern uint32_t const __checksum;
extern uint32_t __checksum_begin;
extern uint32_t __checksum_end;

然后在代码中计算对应代码区域的校验码并和之前存储的校验码进行比较(注意:每次重新计算之前需要Reset CRC模块):

/* Resets the CRC calculation unit */
CRC->CR = 0x01;

/* Calculate the code flash using CRC calculation unit */
CrcValue = HAL_CRC_Accumulate(&hcrc, (uint32_t *)&__checksum_begin,
(((uint32_t)&__checksum_end - (uint32_t)&__checksum_begin + 1u)/4u));

/* Compare the calculated CRC with the previously stored CRC */
if(__checksum == CrcValue)
{
RomTst_Result = true;
}
else
{
RomTst_Result = false;
}

调试

调试发现,通过CRC硬件模块计算出来的校验码和之前存储的校验码是一致的,说明检查代码区域的完整性是好的:

总结

本文主要介绍了如何在IAR Embedded Workbench中配置在Link时生成对应代码区域的校验码并存储于指定地址,然后在运行过程中使用MCU内嵌的CRC硬件模块计算对应代码区域的校验码,并和之前存储的校验码进行比较来检查对应代码区域的完整性。

 

参考文献:

  1. IAR C/C++ Development Guide (Checksum calculation for verifying image integrity)

  2. STM32 Series Reference manual (Chapter 4 CRC calculation unit)

  3. https://www.iar.com/knowledge/support/technical-notes/general/calculate-crc32-as-in-stm32-hardware-v.5.50-and-later/

  4. https://www.iar.com/knowledge/support/technical-notes/general/debugging-checksum-calculations/

  5. https://www.iar.com/knowledge/support/technical-notes/general/calculating-crc32-as-commonly-calculated-online/

  6. https://www.iar.com/knowledge/support/technical-notes/general/checksum-calculation-with-ielftool-after-linking-with-ilink/

  7. https://barrgroup.com/embedded-systems/how-to/additive-checksums

  8. https://barrgroup.com/embedded-systems/how-to/crc-math-theory

  9. https://barrgroup.com/embedded-systems/how-to/crc-calculation-c-code

  10. https://crccalc.com/

We do no longer support Internet Explorer. To get the best experience of iar.com, we recommend upgrading to a modern browser such as Chrome or Edge.