Bootloader 与 OTA
本文性质声明:本机无开发板,全部内容未实测,为手册级框架。站内对照:emb-startup(向量表与 VTOR)、linux-daemon(优雅退出的思想)、engineering-version-release-and-rollback(发布与回滚的桌面侧对照)、win-registry-config(配置持久化)。
一、分区表:双 Bank 的地基
能 OTA 的固件布局,核心是两份应用区:
0x08000000 Bootloader (小,只干引导和升级)
0x08008000 Application A( Bank 1,当前运行)
0x08088000 Application B( Bank 2,升级接收区)
0x08100000 Configuration(参数区,独立 Flash 块)
0x08108000 Backup/Log (emb-reliability 的取证区)
五条设计规则:
- Bank 边界对齐 Flash 块:擦除按块来,Bank 大小 = 块的整数倍——跨块的应用升级会”擦一半写一半”。
- Bootloader 永不被 OTA 覆盖:它自己是烧录器进去的(emb-devtools 的调试器烧录)——OTA 只动 Bank,这是安全底线。
- 配置区分开:OTA 不该碰用户的校准参数——独立块 + 双备份(A/B 配置各一份 + CRC,掉电写一半时另一份兜底)。
- 每个 Bank 头带元数据:版本号、镜像长度、CRC32、构建时间戳、目标 Bank——升级的第一步是校验这个头,头不对直接拒收。
- Bootloader 要知道”上次为什么重启”:看门狗标志(RCC/备份寄存器里的复位原因)——升级后首次启动若崩,自动回滚的触发器(第三节)。
二、镜像校验与跳转
校验链:接收时逐块 CRC(通道错误的早期发现)→ 收齐后全镜像 CRC32/SHA256 → 签名校验(安全启动才有,第四节)→ 写版本号到 Bank 头 → 置”下次启动用 Bank B”标志 → 重启。
跳转的汇编细节(emb-startup 的延伸,错了就是 hardfault):
JumpToApp:
; 1. 关中断:NVIC 全 disable + 清 pending(否则应用的中断处理进 bootloader 的向量表)
; 2. 关 SysTick、清外设状态(用了的 DMA/UART 复位)
; 3. 设 MSP = *(uint32_t*)APP_ADDR (应用向量表第一项)
; 4. 设 VTOR = APP_ADDR (应用的向量表位置)
; 5. 跳转 *(uint32_t*)(APP_ADDR + 4) (Reset_Handler)
三个必须做的:VTOR 重设(忘了 = 中断跳回 bootloader 的死循环)、中断全关(挂着旧 NVIC 状态进应用 = 灵异中断)、跳转用函数指针不用 bl(bl 会把返回地址压进应用的栈——要用 bx 且在此之前 MSP 已切)。
看门狗在升级期间的处理:烧 Flash 期间最耗时的操作(擦块几十 ms、写页几 ms)——升级前喂狗/关窗口,或升级期间用独立的硬件看门狗长超时。整镜像写入期间系统处于”半新半旧”状态,崩了就要靠第一节的头元数据判定。
三、升级通道、断点续传与回滚
通道选择:串口(YMODEM 一类协议,简单可靠)、CAN(车载/工业)、BLE/WiFi(分片 + 序号)、本地(SD 卡/U 盘)。共同要求:分片、序号、ACK、整体校验——自己发明协议时,把 emb-fieldbus 那节的”帧格式/序号/校验”清单过一遍。
断点续传:每收到一片就更新”已接收偏移量”(写配置区或 Bank 头),重连后从偏移量继续——不用每次重传整个镜像。防的不仅是中断:弱网/车载振动下重传 1MB 是灾难。
回滚判定(升级成功与否,四个信号任一失败即回滚):
- 启动即崩:应用启动后 N 秒内没置”运行正常”标志(ping 服务器/写心跳),Bootloader 判失败 → 回滚到 Bank A。
- 看门狗重启且复位原因是看门狗:同上。
- 应用自判失败:新版本自检(外设自检、配置兼容性)不过,主动写”请求回滚”再重启。
- 版本回退保护:镜像头里的版本号 ≤ 当前版本默认拒收(除非强制升级标志)——防服务器下发旧包把新设备降级。
回滚本身也要幂等:回滚是把”下次启动”标志改回 Bank A 再重启——别在 Bootloader 里做复杂逻辑(Bootloader 越简单越可信,这是它存在的意义)。
四、安全启动:信任链的雏形
完整的安全启动(Secure Boot)是链条:硬件根(OTP/eFuse 里的公钥哈希)→ Bootloader 验签 → Bootloader 验签应用 → 应用验签配置/数据。最小实现的三级:
- Bootloader 只跑验签过的镜像:镜像头带 ECDSA/RSA 签名,Bootloader 用烧录时写入的公钥验签(私钥在构建服务器,永不上板)——验签失败 = 拒绝启动。
- 防回滚 + 防降级:安全版本号(Security Counter)单调递增,镜像头的版本低于已运行过的最高版本 = 拒收。
- 防调试提取:量产烧录后设 RDP(读保护)+ 关 SWD——注意 RDP 降级会擦 Flash(防”降级读固件”的标准设计,别在开发板上试)。
没上签名的 OTA = “谁能连上通道谁就能改写固件”——签名不是可选项,是 OTA 从 demo 到产品的分水岭。
五、排障索引
| 症状 | 入口 |
|---|---|
| 跳转后 hardfault | VTOR 没重设/中断没关/栈切错(第二节) |
| 升级后首次启动崩 | 头元数据或校验逻辑问题;看门狗窗口(第二节) |
| 回滚不触发 | “运行正常”标志的写入时机太早(还没真正稳定就写了) |
| 升级写到一半断电 | 断点续传没实现或偏移量没落盘;双 Bank 的意义就是这 |
| 设备被降级成旧版 | 版本回退保护没做(第三节第 4 条) |
| Bootloader 自己变砖 | OTA 流程碰了 Bootloader 区;分区表没对齐(第一节) |
六、未实测清单
- 本文所有 Bootloader/OTA 行为——无开发板,未测。
- 跳转汇编的实际效果——未测(emb-startup 给了同族代码框架)。
- YMODEM/CAN 升级协议——未部署。
- 安全启动的验签实现——未部署。