
配电终端这个产品在电力自动化圈子里看着不如光伏逆变器、充电桩那么显眼但它就蹲在城市每一条馈线的环网柜里、电线杆上三五年没人碰它一次。这种设备一旦出了问题往往不是“重启一下”能解决的尤其是固件升级这种动作——大几十台甚至上百台终端同时升级任何一台变砖都会直接影响到那条线路的遥信、遥测、遥控功能责任是实打实的。所以这几年做配电终端国产化方案我最关注的不是主控性能跑多高而是安全启动和OTA这两个环节能不能做到“可靠、可回滚、可追溯”。这次聊的项目是用米尔-全志系列核心板来做配电终端的全国产化平台。整个方案里安全启动保证设备只能运行经过签名的固件OTA保证固件能远程更新且失败不会变砖两者配合起来才是一套完整的“设备生命周期管理”底座。这篇文章我会把安全启动的信任链怎么搭、OTA分区怎么划、密钥怎么管、产线怎么烧、现场踩过哪些坑从头到尾捋一遍适合正在做电力二次设备、工业物联网终端、或者准备从国外主控切国产平台的嵌入式工程师参考。1. 项目背景与整体方案设计1.1 配电终端这个场景到底特殊在哪配电终端这个品类常见的有DTU站所终端、FTU馈线终端、TTU配变终端核心工作就是采集开关位置、电流电压把数据通过101/104规约或者IEC 61850上送主站同时接收主站下发的遥控指令去分合闸。听着功能不复杂但它的部署环境和运行要求一点都不简单。首先是环境恶劣。户外杆上设备夏天暴晒能到七十度冬天北方零下三四十度还有雷击浪涌、强电磁干扰设备本身必须能扛。其次是运维困难。一个地级市可能部署几千台终端分散在几十上百条线路上想靠人工到现场升级固件成本高到不可接受所以远程OTA是刚需。再就是安全要求高。配电终端直接控制开关的分合如果固件被篡改或者升级过程中出了错轻则设备离线重则可能影响配网运行安全。这也是为什么现在配网自动化项目的招标技术规范里安全启动和远程升级能力越来越常被直接点名。在这样的背景下选择一个合适的国产硬件平台把安全启动和OTA做成标配而不是后期打补丁就成了方案设计的第一步。1.2 为什么选米尔-全志系列核心板项目定下“国产化”这个基调之后选型范围其实就明确了。市面上一线国外厂商的MPU方案虽然成熟但供应链不可控交期、授权、长生命周期供货都存在不确定性。而国产平台里瑞芯微、全志、君正这几家的工业级芯片都是可选项最后我们敲定了全志T113系列配合米尔的核心板来做整机方案。全志T113这个平台在配网终端这个场景里有几个比较匹配的优势。第一是功耗低整板典型功耗能控制住户外取电紧张的环境下比较友好。第二是接口够用原生带CAN、串口、以太网、USB扩展4G模块、加密芯片、蓝牙模块都不需要额外转接。第三是工业级温度范围T113系列有支持-40℃到85℃的型号这对户外设备是硬门槛。米尔的核心板在这个基础上又解决了两件事一是把DDR、eMMC或NOR Flash、电源管理、以太网PHY这些外围集成好了我们整机厂只需要做载板大大缩短硬件设计周期二是米尔在BSP层面针对T113做了适配U-Boot、内核、量产烧录工具都比较完整尤其是U-Boot里对安全启动和OTA相关的分区管理、环境变量机制都有现成方案可以承接。这对我们来说比从零去啃原厂BSP省太多事情了。1.3 安全启动和OTA在方案里是什么关系很多人会把安全启动和OTA当成两个独立功能来做但在我这个项目里它们是一体的。安全启动解决的是“信任起点”的问题设备上电后从片内Boot ROM开始每一级引导都要验签只允许运行经过私钥签名的固件。OTA解决的是“运行时更新”的问题新固件通过网络下发到设备写进备用分区重启切换。但如果这两件事不打通就会出现一个很尴尬的局面OTA下载回来的升级包本身没有经过可信验签或者签名验证只在应用层做了一遍、U-Boot根本不认那攻击者完全可以伪造一个“看起来正常”的升级包让设备执行。反过来如果只做了安全启动而没有设计好OTA回滚机制一次升级失败就可能让设备永远卡死在引导阶段只能人工到场处理。所以这个方案里的架构是一体的OTA下载的升级包必须经过和启动链同一套密钥体系的签名验证写入备用分区后由U-Boot根据标志位决定是否切换槽位切换后如果启动失败U-Boot通过bootcount机制自动回滚到上一个可用槽位。这样才构成一个完整的闭环。后面我会把这两块的实现细节逐一展开。2. 安全启动从Boot ROM到内核的完整信任链2.1 信任链为什么需要每一级都验签安全启动的核心思想我习惯用一个类比来解释它不像小区门禁刷一次卡就能进所有楼栋更像一个层层安检的机场每一道关卡都要重新验一次身份任何一个环节被混入异常后续的所有步骤都必须被及时阻断。在全志平台上正常的启动流程是Boot ROM - SPLSecondary Program Loader - U-Boot - Kernel - rootfs。如果只在最后启动内核时才做一次验签那攻击者完全可以把前面的SPL或U-Boot换掉用自己修改过的引导代码去加载任意内核。所以从Boot ROM开始就必须建立一条逐级验签的链Boot ROM验SPLSPL验U-BootU-Boot再验内核和设备树。每一级都持有上一级认可的公钥或者把公钥的哈希固化在eFuse里这样任何一级被替换验签都会失败设备直接拒绝启动。这里顺便说一个容易混淆的点网上搜“安全启动”会看到大量关于Windows 11安全启动证书更新、UEFI Secure Boot的内容。那是PC固件层面的东西和我们嵌入式里的安全启动不是同一套体系但思想很像——都是依靠证书和数字签名保证引导阶段的可信性。理解了这个大方向再去看你们平台上的具体实现就顺了。2.2 全志平台上的密钥体系和eFuse全志的安全启动方案中密钥管理是核心中的核心。做法是先生成一对RSA密钥公钥经过处理烧写到芯片的eFuse区域私钥则离线保存在安全环境里用于给每一版固件签名。芯片每次启动时Boot ROM从eFuse读取公钥去验签SPL镜像的签名验过才继续引导。实际操作中密钥体系建议做分级设计。根密钥只用来签名次级密钥证书次级密钥再用来签名具体的固件。好处是如果某一把次级密钥意外泄露你可以在设备端撤销这把密钥对应的公钥而不需要把整个平台的根密钥作废重来。当然eFuse空间有限能存几组密钥、支持不支持密钥撤销不同芯片型号不一样要在选型阶段就跟核心板厂确认清楚。还有一个要提前考虑的点很多配电项目会要求国密算法SM2、SM3、SM4这类的。安全启动的验签体系如果只用RSA/SHA256国密要求可能过不了。所以我们在方案里预留了密钥体系的扩展位观察平台是否支持在后续版本中加入SM2验签链。这事不能等到项目验收前才想起来最好在一开始选型阶段就问清楚。2.3 安全启动落地实现的关键操作下面把我们项目里实际走过的安全启动开启流程提炼一下具体命令和工具名称不同平台可能不一样但思路是通用的。第一步用OpenSSL生成密钥对。命令很常规# 生成RSA私钥2048位是底线有条件建议上4096 openssl genrsa -out priv_key.pem 2048 # 从私钥提取公钥 openssl rsa -in priv_key.pem -pubout -out pub_key.pem这个私钥生成之后就要立刻放进离线管理的密钥库里绝不能再出现在开发电脑上。公钥则被后续工具处理成芯片Boot ROM能识别的格式。第二步使用厂商BSP或核心板厂提供的签名工具把公钥打包进安全启动固件镜像里。具体操作上全志系的BSP一般会在打包脚本中预留Secure Boot的开关打开后脚本会要求指定私钥路径、公钥路径然后对镜像进行RSA签名。实际上我们当时是在米尔提供的BSP基础上做的U-Boot的配置菜单里可以直接使能Secure Boot然后脚本自动完成签名和打包。第三步把公钥烧写到eFuse。这一步一定要放在最后做因为eFuse是一次性可编程的烧进去之后不可逆转。建议先把所有镜像在没烧eFuse的开发板上完整验证过确认签名验签逻辑没问题再在量产板的烧录流程中把公钥写入。这里有个经验量产烧录和开发调试千万不要混用同一把密钥。开发阶段可以用一把“测试密钥”随便签、随便刷量产上线前换一把正式密钥并且测试密钥对应的公钥绝对不能烧到量产板子里。否则一旦测试私钥泄露整个存量设备的信任体系都崩了。3. OTA升级分区布局、双备份与回滚机制3.1 设备端分区怎么设计才不容易变砖OTA升级能不能做到安全很大程度上在烧录那一刻就决定了。我见过不少项目升级逻辑写得看似完整但因为Flash分区只留了一套系统升级包写到一半断电整机就成了砖现场只能派人拿烧录器救这在配电终端这种量级的设备上是没法接受的。所以我们这个方案采用了A/B双分区设计。大致分区布局如下如果你用16MB或32MB的NOR Flash可以参照这个思路调整分区内容建议大小说明boot0SPL1MB由Boot ROM直接验签加载boot1U-Boot1MB包含安全启动逻辑和OTA槽位判断envU-Boot环境变量256KB存bootcount、upgrade_available等标志dtb_a / dtb_b设备树512KB x2A/B双槽位kernel_a / kernel_b内核4MB x2A/B双槽位rootfs_a / rootfs_b根文件系统8MB x2A/B双槽位appdata应用数据剩余空间日志、配置、升级包缓存A/B分区的核心思路是同一份内核和根文件系统准备两份当前运行在A槽升级包写入B槽全部写完后通过U-Boot环境变量切换启动槽位下次上电就从B槽启动。如果B槽启动失败U-Boot在bootlimit之内回滚到A槽。这套逻辑在技术上就是Android的A/B无缝升级方案在嵌入式Linux上的落地只不过Android的bootloader把很多细节封装好了我们在这边需要自己把U-Boot脚本写好。如果Flash容量实在紧张也至少应该做到“单一rootfs 独立升级分区”的做法升级包先下到升级分区校验通过后由升级脚本覆盖写入当前系统分区重启后新系统跑起来再确认一次。这种方案依赖升级包校验省空间但有一个风险如果新系统在覆盖后启动失败没有回滚目标。所以在条件允许的配网终端项目里我还是强烈建议直接上A/B双槽位存储成本并没有想象中那么高换来的是彻底的远程无人维护能力。3.2 升级包怎么做全量包、差分包与签名校验OTA升级包里放什么决定了你的升级效率和可靠性。在配网终端环境里网络链路往往不稳定一个终端可能通过4G Cat-1模块联网有时信号就是两格三格下载一个大包很容易断了重来。我们的做法是两种包都做但策略上有所取舍。全量包是把完整的内核和设备树、rootfs打包进去优点是生成简单、在任何状态下都能刷缺点是体积大。差分包基于新旧镜像之间的差异生成体积能缩小一半以上但要做严格的版本匹配——如果设备当前版本太老跟差分包的基础版本对不上就会出现升级失败。所以OTA服务器在下发前必须确认设备端当前版本是否在差分包的起始版本列表里。不管全量包还是差分包打包之后的处理流程是一样的计算所有镜像文件的SHA256哈希把这些哈希和版本信息写进升级包描述文件再用我们之前那把正式签名私钥对整个升级包做RSA加密签名。设备端拿到升级包后先验签再比对哈希任意一步不通过就丢弃升级包不得写入备用分区。这里说一个热词相关的事情网上搜OTA会看到“OTA提取器”“OTA全量包提取img”这类工具那是手机圈子用的——从厂商发布的OTA包里提取出镜像文件刷机调试。我们做嵌入式设备调试时也会遇到类似需求比如从全量包里单独抽取rootfs.img放到开发板上跑起来分析方法其实类似。工具可以用但要注意提取出来的镜像没有经过你本机的签名链不能直接量产烧录。签名校验这一步一定要放在写入Flash之前不要先写了再验。我之前在某个项目里看到过先把升级包写到备用分区然后启动时再验结果一个被篡改的包直接覆盖了合法数据虽然最终验签失败没启动但备用分区已经脏了后续恢复多了一道工序。先验签再写入是最起码的规矩。3.3 升级主流程和回滚机制的完整时序把A/B分区、签名校验、U-Boot标志位串起来整条升级主流程是这样的设备端定时向OTA服务器上报当前固件版本号和硬件型号。服务器比对版本如果有新版本返回升级包下载地址和包大小、SHA256校验值。设备端下载升级包到appdata分区。应用层程序对升级包做签名验证和哈希校验失败则丢弃并上报错误码。校验通过后把镜像文件分别写入备用槽位的dtb、kernel、rootfs分区。写入完成再次读取备用分区内容做校验确认镜像完整。设置U-Boot环境变量upgrade_available1bootcount0active_slot切换。设备重启U-Boot读取环境变量按标志位从备用槽位启动。新系统启动成功后应用层向服务器上报新版本号并清除upgrade_available标志。如果第8步启动失败U-Boot的bootcount会累计达到bootlimit后自动回滚到上一个正常槽位并上报错误。这个流程里最容易出问题的是第9步“启动成功”的判定到底以什么为准。不能简单认为内核起来了就算成功——如果新rootfs挂载后应用进程持续崩溃这种“半成功”状态也要触发回滚。我们当时的做法是应用层主进程启动后在U-Boot环境变量里写一个boot_successful标志同时启动一个看门狗如果在规定时间内主进程没有置位该标志就触发强制重启并连续失败计数最终由U-Boot回滚。看门狗和标志位配合才是真正可靠的“健康判定”。断电场景也要专门设计。升级包写入备用分区期间断电最坏情况是备用分区损坏但当前运行槽位完全不受影响下次上电依然从原槽位启动只是升级被中断可以重新下载再来。这里要注意的是U-Boot切换槽位的动作本身要设计成“最后生效”先完成所有写操作再切换标志防止标志已经切了但数据没写完。4. 国产化适配与实际部署中的那些坑4.1 从国外平台切到国产核心板BSP差异比想象中大从NXP i.MX6或者TI AM335x这类平台切换过来硬件和BSP两边的差异都得重新适应。硬件方面米尔核心板已经把DDR、PMU、以太网PHY都集成好了载板设计相对简单但我们还是花了些精力去调整外围接口的引脚复用和电平匹配。尤其是跟加密芯片、4G模块的串口连接一定在载板设计阶段就把电气特性确认清楚别等板子回来了才发现某个串口的电平不对。BSP方面U-Boot的定制是所有工作里最需要小心的一环。国产平台的开源U-Boot代码虽然能编译通过但很多功能开关、驱动配置跟项目需求是错位的。我们当时花了一周时间把U-Boot里跟安全启动、OTA相关的配置逐一核对特别是环境变量偏移、分区表、MISC分区读写的实现这些地方一处不对整个升级回滚机制就形同虚设。内核适配同样有不少活。全志平台对常见外设的支持已经比较充分但配网终端里用的一些特定外设比如电力载波模块、专用加密芯片、特定的4G模块需要自己移植驱动或者适配设备树。还有一个容易忽略的点配网终端里面有时候会用到一些老型号的串口设备寄存器时序比较特殊这类驱动在国产平台上往往没有现成支持实测下来要么用gpio模拟时序要么就得重新写一个小的字符设备驱动。4.2 电力规约对升级时序的约束配电终端跑通信规约主要就是DL/T 634.5104IEC 60870-5-104的国内版本这类远动规约。这些规约对设备的数据采集和转发有时序要求但真正影响OTA的是另一件事升级动作会短暂中断设备的数据上报和遥控链路在配网调度那边看来就是这台终端“失联”了。所以远程升级一定要有“窗口”概念。我们当时的做法是在主站侧配置了升级维护时间段通常是凌晨低谷时段并且升级前要先把该终端的遥控功能闭锁再向主站发送“设备维护”状态。升级完成、新系统起来、通信链路恢复后再解除闭锁并确认遥控预置和执行的测试指令正常整个升级才算闭环。如果直接啪一下升级主站那边遥控告警、链路中断告警能刷满一屏。另外多台设备同时升级对网络的冲击也得控制。我们做了一个简单的“分批升级”策略服务器侧一次性下发一批设备的升级任务但每台设备之间错开30秒到1分钟启动下载避免集中流量把4G基站或机房带宽打满。实测下来几百台设备分批升级整个过程对现场网络基本无感。4.3 生产环节的密钥管理和供应链协作安全启动真正落地到量产最难的不是技术是流程。私钥管理这件事如果做不好前面所有安全设计都白搭。我们的做法是分出了三套密钥体系。第一套是开发密钥只用于开发板和产测阶段的固件签名私钥放在研发环境内部。第二套是量产密钥用于正式发布固件私钥离线存储在加密U盘里放在专门的保险柜只有版本发布负责人能接触。第三套是各台设备内部的eFuse公钥理论上就是量产密钥的公钥。三套密钥严格隔离开发机上绝对不允许出现量产私钥的副本。产线烧录流程也要仔细设计。核心板出厂时米尔会把U-Boot烧好、测试好但eFuse公钥通常是由整机厂在最后烧录阶段写入。因为eFuse一旦烧了就不能改所以产线烧录工位必须具备完善的防呆措施烧录前先读板子当前的eFuse状态确认是空白的才能烧烧录完成后马上回读校验并记录每台设备的序列号和eFuse哈希值。这些记录要长期保存万一后续哪台设备需要定位问题溯源就是靠这个。跟核心板厂、芯片原厂的协作也要提前约定清楚。比如eFuse区域怎么分配、哪几位是芯片厂保留的、哪些位我们能烧这些都得在项目启动时拿到正式文档。我们项目早期就吃过亏以为整个eFuse区域都能自由使用后来发现部分区域被芯片厂保留差点导致量产计划延误。5. 常见问题与排查技巧实录5.1 故障现象速查表这个项目从开发到小批量部署我前前后后整理了不少问题挑几个典型的做成表格方便大家直接对照排查故障现象可能原因排查方法与解决建议开启安全启动后设备完全无串口输出eFuse公钥未烧或烧错签名工具版本与镜像不匹配先用未烧eFuse的开发板验证镜像包能否正常跑检查公钥是否成功写进eFuse确认Boot ROM输出的gpio状态有没有变化U-Boot引导时循环重启bootcount不断累加触发了回滚机制用串口抓U-Boot日志看是哪个槽位启动失败检查env里upgrade_available和active_slot状态清空env后手动指定槽位启动OTA下载完成后重启仍是旧版本升级包写入了当前槽位或者U-Boot槽位判断逻辑有误查看升级脚本里的写入偏移地址是否正确在U-Boot命令行手动打印env变量检查active_slot是否切换升级包验签一直失败私钥和公钥不匹配签名算法被工具改了确认打包签名用的私钥与设备eFuse公钥对应统一全链路使用RSA2048SHA256不要中途换算法升级到一半网络断开设备离线后不复联下载中断后重试逻辑不完善设备没有断点续传能力升级包下载模块增加断点续传机制下载超时后重新发起请求从断点偏移继续拉取新系统能启动但应用进程反复崩溃业务程序依赖的库版本变化配置数据格式变更新rootfs启动后先检测关键配置版本看门狗超时强制重启并计数超过阈值回滚不要只靠内核启动判断升级成功5.2 我现场排查软件问题的“三板斧”配网终端设备部署在户外现场排查没法像实验室里那么舒服所以我一般按照效率从高到低来安排先看串口日志再看U-Boot环境变量最后查分区数据。第一板斧是串口日志。设备正常工作时串口1作为调试口会输出内核和业务日志但如果U-Boot阶段就挂了那串口输出能帮你判断是哪一级验签失败还是哪个槽位没有正确的标识。我建议在生产固件中保留一个受管控制的调试串口平时通过密文方式开启日志输出权限排查问题时针对性打开不要默认全开。第二板斧是U-Boot环境变量。很多OTA问题归根结底是env里的标志位不对。可以在U-Boot命令行直接打印env确认bootcount数值、upgrade_available是否为1、active_slot到底指向哪个槽位。曾经遇到一台设备反复回滚排查到最后是env分区有个字节被干扰写坏了导致U-Boot永远认为升级未完成。清空env后设备就恢复了这类问题不看env很难定位。第三板斧是分区原始数据比对。拿Flash里的数据跟PC上保存的正式固件做哈希比对能直接判断是不是写入时发生了位翻转、写错偏移或写了一半就中断。用烧录器读回整个分区内容在PC端用工具做SHA256比对加上时序分析基本能锁定是硬件问题还是软件逻辑问题。这三步下来多数问题都能定位到具体层面。如果三板斧还排查不出那就别在设备端纠结了把升级包拿到开发板上完整复现一遍升级流程在U-Boot的每个启动节点加打印逐级确认状态。开发板上复现要比在户外终端上盲猜高效得多。再说一个很实用的经验开发阶段一定要模拟一遍“升级过程中断电”的场景而且要在不同写入阶段各断电一次写SPL、写kernel、写rootfs、写env标志位分别做断电测试。我们当时专门用可控电源做了几十轮断电测试把回滚机制的边界都摸了一遍。没有这个条件等设备真在户外遇到一次断电升级你连问题现象都很难复现出来。最后回到我个人的实际感受。做配电终端国产化方案安全启动和OTA的难度不在某个单点技术上而在把这些技术串成一条完整的链路。密钥管理、分区布局、U-Boot环境变量、升级包签名、回滚判定、产线烧录任何一个环节脱节整条链就断了。米尔-全志这个平台给我们提供了不错的起点但真正决定方案靠不靠谱的还是你有没有把这个链路的每一个细节都盘到位。如果你正在做类似项目我的建议很简单先画清楚信任链和升级链路然后照着链路把每个环节做成可验证的测试用例最后用最笨的方法——断电、断网、篡改升级包——把每个环节都挑战一遍。这套流程走完心里基本就有底了。