我正着手在STM32(类似IAP AN4657)上开发一个定制的引导加载程序。假设flash分为3个区域scratch,那么用户区域、IAP代码(bootloader)和要升级的固件都在scratch区域。我想有一个带有固件版本和校验和的头,我需要一些理解如何实现头到固件和检查从IAP(bootloader)代码固件的有效性。如有任何参考资料,敬请谅解。

最佳答案

您可以创建一个保存头信息的结构,并将这个头放在flash中的一个已知位置。有两种常用的方法:
将固件二进制文件填充到flash大小,减去头的大小并将其放在末尾,
将固件头放在开始的某处,在大小不同的.text、.data和.bss之前。
该方法取决于您的需求是什么,您希望引导程序有多复杂,以及您愿意投入多少精力以使其更优化或更灵活。通常需要引导加载程序尽可能简单,并且通常不可自编程(有一个引导加载程序部分在出厂后永远不会修改)。不管是哪种方式,报头都应该位于flash中的一个恒定偏移处。进一步阐述上述两种方法:
一。固件头位于(填充的)二进制文件的末尾。
这是一种更简单的方法,特别是一些工具/ide(例如IAR)已经准备好使用机制来实现这一点。假设您有以下格式的固件头:

typedef struct
{
  uint32_t firmware_verson;
  uint32_t crc32;
} sFirmwareHeader;

在这种情况下,您将固件二进制文件(例如0xFF)填充到FLASH_SIZE - sizeof(sFirmwareHeader),并将结构放在那里。这些相同的工具通常还具有计算固件二进制文件的CRC并将其放在末尾的能力,这正符合这种方法。最大的缺点是,每次你想用这种方式升级固件时,你需要从头到尾传输整个应用程序二进制文件,包括填充字节。如果你的应用程序很小,这是相当多不必要的字节被传输。当然,我没有提到任何压缩方法会使这个更小,因为这些方法会使引导加载程序更复杂,因此更容易出错。
2。应用程序二进制文件开头的固件头
另一种方法是将固件头放在开始的某个位置。这可能是在ISR向量之后,但在.text、.data和.bss之前的好地方,这些向量的大小会随着应用程序代码的更改而变化。一个好主意是用firmware_size字段扩展上述结构:
typedef struct
{
  uint32_t firmware_verson;
  uint32_t firmware_size;
  uint32_t crc32;
} sFirmwareHeader;

这样,引导加载程序不仅可以验证要加载的固件文件的CRC,还可以验证已经加载到flash中的应用程序的完整性,因为固件头仍然位于flash内存中的恒定偏移量下,它只是不像第1种方法那样在最后。这种方法的优点是只需要传输尽可能多的字节。缺点是,可能不会有任何现成的工具供您使用。在构建应用程序固件二进制文件(链接器可以提供固件大小值)之后,您需要编写某种简单的程序/脚本来计算CRC值。
为了使答案更完整,这里有一段代码,无论您打算使用哪种方法,都应该为您提供一个良好的起点。这些是给海合会的。
链接器脚本的一部分,该脚本定义了一个节,用于将固件头保持在从0x200内存节开始的恒定FLASH偏移计数处:
__fw_header_offset = 0x200;

SECTIONS
{
    /* ISR vectors */

    .fw_header : ALIGN(4)
    {
      FILL(0xFF)

      . = ORIGIN(FLASH) + __fw_header_offset;
      KEEP(*(.fw_header))
    } >FLASH

    /* Other sections in Flash */
}

然后在应用程序代码中可以执行以下操作:
const sFirmwareHeader __attribute__ ((section(".fw_header"))) FirmwareHeader = {
    1,  // firmware_verson
    0   // crc32, this can be filled with an external application after building firmmwre binary
};

这将创建一个全局FirmwareHeader结构,并将其放置在定义为eariler的“.fw_header”节下。

关于c - 将 header 添加到固件镜像stm 32,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49705924/

10-09 09:04