跳到正文

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 的取证区)

五条设计规则:

  1. Bank 边界对齐 Flash 块:擦除按块来,Bank 大小 = 块的整数倍——跨块的应用升级会”擦一半写一半”。
  2. Bootloader 永不被 OTA 覆盖:它自己是烧录器进去的(emb-devtools 的调试器烧录)——OTA 只动 Bank,这是安全底线。
  3. 配置区分开:OTA 不该碰用户的校准参数——独立块 + 双备份(A/B 配置各一份 + CRC,掉电写一半时另一份兜底)。
  4. 每个 Bank 头带元数据:版本号、镜像长度、CRC32、构建时间戳、目标 Bank——升级的第一步是校验这个头,头不对直接拒收。
  5. 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 是灾难。

回滚判定(升级成功与否,四个信号任一失败即回滚):

  1. 启动即崩:应用启动后 N 秒内没置”运行正常”标志(ping 服务器/写心跳),Bootloader 判失败 → 回滚到 Bank A。
  2. 看门狗重启且复位原因是看门狗:同上。
  3. 应用自判失败:新版本自检(外设自检、配置兼容性)不过,主动写”请求回滚”再重启。
  4. 版本回退保护:镜像头里的版本号 ≤ 当前版本默认拒收(除非强制升级标志)——防服务器下发旧包把新设备降级。

回滚本身也要幂等:回滚是把”下次启动”标志改回 Bank A 再重启——别在 Bootloader 里做复杂逻辑(Bootloader 越简单越可信,这是它存在的意义)。

四、安全启动:信任链的雏形

完整的安全启动(Secure Boot)是链条:硬件根(OTP/eFuse 里的公钥哈希)→ Bootloader 验签 → Bootloader 验签应用 → 应用验签配置/数据。最小实现的三级:

  1. Bootloader 只跑验签过的镜像:镜像头带 ECDSA/RSA 签名,Bootloader 用烧录时写入的公钥验签(私钥在构建服务器,永不上板)——验签失败 = 拒绝启动。
  2. 防回滚 + 防降级:安全版本号(Security Counter)单调递增,镜像头的版本低于已运行过的最高版本 = 拒收。
  3. 防调试提取:量产烧录后设 RDP(读保护)+ 关 SWD——注意 RDP 降级会擦 Flash(防”降级读固件”的标准设计,别在开发板上试)。

没上签名的 OTA = “谁能连上通道谁就能改写固件”——签名不是可选项,是 OTA 从 demo 到产品的分水岭。

五、排障索引

症状入口
跳转后 hardfaultVTOR 没重设/中断没关/栈切错(第二节)
升级后首次启动崩头元数据或校验逻辑问题;看门狗窗口(第二节)
回滚不触发“运行正常”标志的写入时机太早(还没真正稳定就写了)
升级写到一半断电断点续传没实现或偏移量没落盘;双 Bank 的意义就是这
设备被降级成旧版版本回退保护没做(第三节第 4 条)
Bootloader 自己变砖OTA 流程碰了 Bootloader 区;分区表没对齐(第一节)

六、未实测清单

  • 本文所有 Bootloader/OTA 行为——无开发板,未测。
  • 跳转汇编的实际效果——未测(emb-startup 给了同族代码框架)。
  • YMODEM/CAN 升级协议——未部署。
  • 安全启动的验签实现——未部署。