第4章 Bootloader设计:双区备份启动、固件加密与签名校验、OTA升级流程、看门狗集成
各位同学,今天我们来聊聊麻醉机嵌入式系统里一个特别关键、也特别容易出问题的部分——Bootloader。说实话,Bootloader这玩意儿平时不显山不露水,但一旦系统需要升级或者启动失败,它就是最后的救命稻草。我在呼吸机项目里就吃过亏,当时OTA升级到一半断电了,设备直接变砖,差点没被临床工程师骂死。从那以后,我对Bootloader的设计就格外上心。
4.1 双区备份启动:给系统上双保险
什么叫双区备份?说白了,就是在Flash里放两份固件。一份是当前运行的,另一份是备份的。启动时先检查主区,如果主区坏了或者校验不过,就自动切到备份区启动。你想想看,麻醉机正在手术室里用着,突然重启了,如果主区固件损坏,备份区能顶上,这多重要。
我一般这样划分Flash空间:
| 区域 | 起始地址 | 大小 | 说明 |
|---|---|---|---|
| Bootloader区 | 0x08000000 | 64KB | 启动加载程序,不可变 |
| 主固件区(A区) | 0x08010000 | 512KB | 当前运行固件 |
| 备份固件区(B区) | 0x08090000 | 512KB | 固件备份 |
| 参数存储区 | 0x08110000 | 128KB | 校准参数、日志等 |
启动流程是这样的:
- 上电后,Bootloader先检查主固件区的CRC校验和签名。
- 如果校验通过,跳转到主固件区执行。
- 如果校验失败,检查备份固件区。
- 备份区也坏了?那就进入恢复模式,等待串口或USB下载固件。
关键点:双区切换时,要确保切换标志位存储在独立的备份寄存器里,别放在主固件区。否则主区坏了,标志位也读不出来,那就尴尬了。
4.2 固件加密与签名校验:别让黑客钻空子
医疗设备的安全性,不用我多说。固件要是被人篡改了,后果不堪设想。我个人习惯用AES-128加密固件内容,再用RSA-2048对固件进行签名。加密是为了防止别人直接读Flash把固件抄走,签名是为了确保固件是官方发布的、没被改过。
校验流程大致这样:
- Bootloader里内置了RSA公钥。
- 固件头部包含签名信息(256字节的RSA签名值)。
- Bootloader先对固件做SHA-256哈希,然后用公钥验签。
- 验签通过后,再用AES密钥解密固件内容。
这里有个坑——AES密钥怎么存?我曾经直接把密钥写在代码里,结果被同事用JTAG读出来了。后来我改用芯片内置的OTP(一次性可编程)区域存储密钥,读出来就是全0,安全多了。
小技巧:签名校验时,建议把公钥的哈希值也存一份在Bootloader里。验签前先校验公钥本身有没有被篡改,这叫「信任链」的起点。
4.3 OTA升级流程:稳字当头
OTA升级,说白了就是远程更新固件。麻醉机可能分布在各个医院,总不能派人拿着烧录器到处跑吧?但OTA最怕什么?怕升级到一半断网、断电、或者传输错误。
我的设计思路是「三步走」:
- 下载阶段:把新固件先下载到备份区。注意,是备份区,不是主区。这样就算下载过程中出问题,主区还能正常运行。
- 校验阶段:下载完成后,对备份区的固件做完整性校验(CRC+签名)。校验不通过,直接丢弃,标记下载失败。
- 切换阶段:校验通过后,设置切换标志位,然后软复位。Bootloader检测到标志位,下次启动时从备份区启动,并把备份区和新主区互换。
代码示例(伪代码):
void ota_update_handler(uint8_t *firmware_data, uint32_t length) {
// 1. 写入备份区
if (flash_write(BACKUP_ADDR, firmware_data, length) != OK) {
log_error("Flash write failed");
return;
}
// 2. 校验签名
if (verify_signature(BACKUP_ADDR, length) != PASS) {
log_error("Signature verification failed");
flash_erase(BACKUP_ADDR);
return;
}
// 3. 设置切换标志
backup_register_write(SWITCH_FLAG, 0xA5A5A5A5);
// 4. 软复位
NVIC_SystemReset();
}
警告:千万不要在升级过程中断电!虽然我们有双区备份,但如果在擦写Flash时断电,可能导致Flash损坏。硬件上建议加一个超级电容,保证掉电后还能维持几十毫秒,让MCU完成当前操作。
4.4 看门狗集成:系统最后的守护者
看门狗,说白了就是一个定时器。系统正常运行时,会定期「喂狗」。如果系统卡死了,看门狗超时,就会强制复位。麻醉机这种设备,系统卡死是绝对不能接受的。
我一般用独立看门狗(IWDG),因为它独立于主时钟,即使主时钟挂了,它还能工作。喂狗的位置很讲究——不能放在主循环里,因为主循环卡死了,喂狗还在跑。我习惯放在任务调度器的空闲任务里,或者放在最高优先级的定时器中断里。
看门狗超时时间怎么设?设太短,正常流程稍微慢点就复位了;设太长,系统卡死了半天才复位。我一般设3-5秒,这个时间足够系统完成一次完整的呼吸周期,又不会让用户等太久。
嗯,这里还要注意一点:调试时记得把看门狗关掉。我曾经在调试时忘了关看门狗,每次单步执行到一半就复位了,折腾了半天才发现是看门狗在捣乱。
避坑指南:我曾经遇到过一个案例,系统在OTA升级过程中因为看门狗超时复位了,结果升级到一半的固件被破坏了。后来我改了策略:进入OTA升级模式后,把看门狗超时时间临时延长到30秒,升级完成后再恢复。这样既保证了安全,又不会因为升级时间长而误复位。
4.5 总结一下
Bootloader设计,说白了就是三个字:稳、安、快。稳——双区备份保证系统永远能启动;安——加密签名防止固件被篡改;快——OTA升级流程要高效,别让用户等太久。看门狗则是兜底的,确保系统不会死锁。
这些经验都是我在项目里一点点踩坑踩出来的。你们以后做设计时,记得把这些点都考虑进去。好了,这一章就到这里,下一章我们聊聊实时操作系统(RTOS)在麻醉机里的应用。