3. Bootloader 架构设计:双分区、启动模式与升级流程
好,咱们进入正题。Bootloader 的架构设计,说白了就是回答三个问题:代码放哪?怎么启动?怎么升级? 这三个问题搞定了,整个安全启动的骨架就搭起来了。
我个人习惯把 Bootloader 看作一个「看门人」。它不负责业务逻辑,只负责两件事:验证镜像的合法性,以及把控制权交给合法的镜像。今天咱们就聊聊这个看门人的内部结构。
3.1 双分区设计:为什么是「双」?
你想想看,如果只有一个分区,升级时断电了怎么办?设备就变砖了。双分区就是为了解决这个「原子性」问题。
双分区通常指:槽位 A (Slot A) 和 槽位 B (Slot B)。每个槽位都包含完整的应用程序镜像。Bootloader 运行在独立的保护区,不参与分区切换。
| 分区 | 用途 | 特点 |
|---|---|---|
| Slot A | 主运行区 | 默认启动,包含当前稳定版本 |
| Slot B | 备份/升级区 | 接收新固件,升级后与 Slot A 互换角色 |
| Bootloader 保护区 | 存放 Bootloader 自身 | 硬件写保护,不可被应用层擦除 |
核心原则:任何时候,至少有一个可启动的合法镜像。这就是双分区设计的底线。
我在项目中遇到过一种情况:某厂商为了省 Flash 空间,只做了一个分区加一个差分补丁区。结果升级补丁写到一半,电池没电了。嗯,从那以后,我再也不敢在量产产品上省这个空间了。
3.2 启动模式选择:三种典型路径
Bootloader 启动时,会根据外部引脚、标志位或通信接口来决定走哪条路。我一般把它分为三种模式:
- 正常启动模式:验证 Slot A 的签名,通过则跳转。这是最常用的路径。
- 升级模式:进入固件下载流程,等待上位机或 OTA 推送新镜像。
- 恢复模式:当两个分区都不可用时,进入最小系统,等待串口或 USB 强制烧录。
为什么会需要恢复模式?我曾经遇到过一批设备,OTA 下载时网络闪断,导致 Slot A 和 Slot B 的镜像都被写坏了。如果没有恢复模式,这批设备就得全部返厂。后来我强制规定:恢复模式必须用硬件引脚触发,且 Bootloader 自身不能被升级覆盖。
避坑指南:千万不要把恢复模式做成纯软件判断。如果 Flash 内容全乱了,软件判断逻辑都跑不起来。用 GPIO 电平或专用按键最靠谱。
3.3 固件升级流程:从下载到生效
完整的升级流程,我把它拆成 5 步。每一步都有对应的验证机制。
| 步骤 | 动作 | 验证点 |
|---|---|---|
| 1. 下载 | 接收固件包,写入 Slot B | 校验包完整性(CRC/哈希) |
| 2. 验证 | Bootloader 对 Slot B 做签名验证 | 公钥验证签名,防止篡改 |
| 3. 切换 | 更新启动标志位,标记 Slot B 为下次启动分区 | 写入标志位后回读确认 |
| 4. 重启 | 系统复位,Bootloader 读取标志位 | 检查标志位有效性 |
| 5. 回滚 | 如果新镜像启动失败,自动切回 Slot A | 看门狗超时或应用程序主动报告 |
这里有个细节:步骤 3 的「切换」不是立即擦除 Slot A。我习惯的做法是,先让设备在新分区上跑一次,确认没问题后,再把旧分区标记为「可覆写」。这叫「试运行机制」。
个人经验:试运行期间,让应用程序主动向 Bootloader 发送一个「确认健康」的标志。如果 30 秒内没收到,Bootloader 就自动回滚。这个机制救过我好几次。
3.4 架构总览:一张图说清楚
下面这张图展示了 Bootloader 双分区架构下的启动决策流程。你可以看到,所有路径最终都会回到「验证签名」这个核心环节。
从图上你能看到,三种模式最终都会汇聚到「签名验证」这个环节。区别只在于:正常模式验证 Slot A,升级模式验证 Slot B,恢复模式则跳过验证直接等待外部干预。
3.5 关键设计决策点
最后,我总结几个实际项目中容易踩坑的设计决策:
- 分区大小怎么定? 我建议 Slot A 和 Slot B 大小完全一致,且都预留 10% 的余量。别问为什么,问就是被「差一点点就够用」坑过。
- 标志位放哪? 放在 Bootloader 保护区末尾,用两个备份 + 取反校验。防止写入一半断电导致标志位状态不明。
- 回滚触发条件? 硬件看门狗 + 应用程序心跳。缺一不可。纯软件看门狗在系统死锁时没用。
- 升级中断电怎么办? 双分区的优势就在这里——下次启动时 Bootloader 发现 Slot B 验证失败,自动切回 Slot A。
一句话总结:双分区是骨架,启动模式是路径,签名验证是灵魂。骨架不稳,后面全白搭。