docs(review): 专家评审 2026-10-19
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>GD32_BOOT 专家评审 2026-10-19</title><style>
|
||||
body{font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;max-width:1180px;margin:0 auto;padding:24px;color:#1f2328;line-height:1.6;background:#fafbfc}
|
||||
h1{border-bottom:3px solid #0b5cad;padding-bottom:8px}h2{margin-top:36px;border-left:5px solid #0b5cad;padding-left:10px}
|
||||
table{border-collapse:collapse;width:100%;font-size:13.5px;background:#fff;margin:10px 0}th,td{border:1px solid #d0d7de;padding:6px 8px;vertical-align:top;text-align:left}th{background:#eef3f8}
|
||||
.loc{font-family:Consolas,monospace;font-size:12px;word-break:break-all}.b{padding:2px 8px;border-radius:10px;color:#fff;font-size:12px;white-space:nowrap}
|
||||
.crit{background:#b00020}.high{background:#e36209}.mid{background:#9a6700}.low{background:#57606a}
|
||||
.cards{display:flex;gap:12px;flex-wrap:wrap}.card{flex:1;min-width:140px;background:#fff;border:1px solid #d0d7de;border-radius:8px;padding:12px;text-align:center}.card b{font-size:26px;display:block}
|
||||
pre{background:#fff;border:1px solid #d0d7de;padding:12px;overflow:auto;font-size:12.5px}.note{background:#fff8c5;border:1px solid #d4a72c;padding:10px;border-radius:6px}
|
||||
</style></head><body>
|
||||
<h1>GD32_BOOT 专家评审报告</h1>
|
||||
<p>仓库:cbb/GD32_BOOT 分支:GD32C103 评审基线提交:<code>05069e3</code>(2026-07-26,“移除CAN DMA相关代码并优化编译配置”) 评审日期:2026-10-19 报告提交:2026-10-20</p>
|
||||
<div class="cards"><div class="card"><b style="color:#b00020">3</b>致命</div><div class="card"><b style="color:#e36209">9</b>严重</div><div class="card"><b style="color:#9a6700">11</b>一般</div><div class="card"><b style="color:#57606a">6</b>建议</div><div class="card"><b>5.0</b>综合评分 / 10</div></div>
|
||||
|
||||
<h2>1. 项目概述与架构</h2>
|
||||
<p>GD32C103CB(Cortex-M4,128 KB Flash / 32 KB SRAM,120 MHz HXTAL PLL)上的 CAN-FD Bootloader,C++(AC6 + microlib,CMSIS csolution 构建)。功能:上电判定标志位 → 直接跳 APP / 10 s 延迟窗口监听 OTA / 从备份区恢复 / 停留 OTA 模式;OTA 采用 AES-128 握手派生会话密钥,48 字节/包加密传输,每包带密钥 CRC32;另含深度睡眠与 PB8 EXTI 唤醒。</p>
|
||||
<table><tr><th>Flash 区域</th><th>地址范围</th><th>大小</th><th>用途</th></tr>
|
||||
<tr><td>BOOT</td><td class="loc">0x08000000-0x08005FFF</td><td>24 KB</td><td>Bootloader(当前使用 0x3398 ≈ 13 KB)</td></tr>
|
||||
<tr><td>APP_BACKUP</td><td class="loc">0x08006000-0x08011FFF</td><td>48 KB</td><td>恢复镜像(BOOT 只读不写)</td></tr>
|
||||
<tr><td>APP_LATEST</td><td class="loc">0x08012000-0x0801DFFF</td><td>48 KB</td><td>运行镜像,OTA 写入目标</td></tr>
|
||||
<tr><td>OTA 标志页</td><td class="loc">0x0801E000-0x0801E3FF</td><td>1 KB</td><td>6 个 32 位标志:LATEST/BACKUP 的 AVAL/EN/CHECK(0=有效,0xFFFFFFFF=无效)</td></tr>
|
||||
<tr><td>睡眠配置页</td><td class="loc">0x0801E400-0x0801E7FF</td><td>1 KB</td><td>追加式睡眠使能记录</td></tr>
|
||||
<tr><td>(flash.cpp 预留)</td><td class="loc">0x0801F800-0x0801FFFF</td><td>2 KB</td><td>EEPROM 模拟,未参与构建</td></tr></table>
|
||||
<pre>上电 → systick/USART0/CAN-FD 初始化 → check_sleep()(使能则深睡,PB8 唤醒后软复位)
|
||||
├─ LATEST.CHECK=0 且 EN=0 → jumpToApplication()
|
||||
├─ LATEST.CHECK=0 且 EN=0xFFFF.. → 10 s 窗口:发 WAIT 心跳(0x103),收到握手则进入 OTA 循环,否则跳 APP
|
||||
└─ 否则:BACKUP.CHECK=0 且 AVAL=0 → move_app_data() 备份→主区 → 跳 APP
|
||||
否则 → OTA 循环
|
||||
OTA 状态机:IDLE --REQ[00 AC]--> WAITING_RANDOM --REQ[16B nonce]--> WAITING_CONFIRM
|
||||
--REQ[16B AES(K_s, nonce^0x55)]--> CHECKING_FIRMWARE --DATA[4B size]--> 擦除 --> RECEIVING
|
||||
--DATA[64B: 会话号4|包号4|密文48|IFEND4|CRC4]...尾帧 IFEND=0xFFFFFFFF--> FINISHED → 跳 APP
|
||||
CAN ID(扩展帧):0x100 REQ / 0x101 DATA / 0x102 ACK / 0x103 WAIT / 0x000 CANCEL;1 Mbps 仲裁 + 2 Mbps 数据(BRS)</pre>
|
||||
|
||||
<h2>2. 评审范围与方法</h2>
|
||||
<ul><li>范围:Robot_V2/main.*、device/Can.*、sys/(OTA、aes128、initial、systick、flash、config)、RTE 中的中断文件/启动文件/链接脚本/区域定义、cproject/csolution 配置、Release map 文件;GigaDevice 标准外设库仅在被调用处核对行为(fmc_page_erase、can_message_receive 等)。</li>
|
||||
<li>排除:out/、tmp/ 构建产物(仅在仓库卫生项中指出,map 用于核对 ROM/RAM 与符号是否链接)。</li>
|
||||
<li>专家视角:MCU 固件架构、Bootloader/升级可靠性、中断与实时性、CAN-FD 协议、安全与故障保护、代码质量、构建与仓库卫生。</li>
|
||||
<li>方法:逐行静态阅读 + 交叉核对库实现与 map 符号;行号以基线提交 05069e3 为准。未上板实测,标注“需实测”的条目为推断风险。</li></ul>
|
||||
|
||||
<h2>3. 既有评审记录检查</h2>
|
||||
<div class="note">全仓(含历史提交)未发现任何 .md/.html 评审、审计或报告文件;Gitea issue 因访问令牌无 read:issue 权限无法读取。本报告是该仓库的第一份评审记录,因此没有可修订的原评审文件。作为替代,第 5 节逐条核对了提交信息中声明的修复/功能在当前代码中是否成立。</div>
|
||||
|
||||
<h2>4. 问题清单</h2>
|
||||
<table><tr><th>编号</th><th>严重度</th><th>领域</th><th>文件:行号</th><th>现象</th><th>风险</th><th>修改建议</th></tr>
|
||||
<tr><td>F-01</td><td><span class="b crit">致命</span></td><td>安全</td><td class="loc">Robot_V2/sys/config.h:70-72;sys/OTA.cpp:531-560</td><td>AES-128 主密钥 K_master 以明文常量写在头文件并提交进仓库,所有设备共用同一密钥;会话密钥 K_session = AES(K_master, nonce_server) 完全由上位机提供的随机数决定,设备侧不贡献随机性。</td><td>任何拿到仓库或任一固件镜像的人即可伪造合法上位机;设备无法区分新会话与录制的旧会话,可重放旧握手与旧固件(降级攻击)。</td><td>主密钥移出源码(读保护的 OTP/选项字节或按设备 UID 派生的设备密钥);握手加入设备侧随机数(双向 nonce);开启 Flash 读保护(SPC)。</td></tr>
|
||||
<tr><td>F-02</td><td><span class="b crit">致命</span></td><td>安全/升级可靠性</td><td class="loc">sys/OTA.cpp:423-478</td><td>固件没有整体签名或整镜像校验:仅有每包 4 字节“带密钥 CRC32”,CRC32 是线性函数,不是 MAC;AES-ECB 逐块加密,相同明文块产生相同密文,可被剪切/拼接/重排。</td><td>知道密钥即可构造任意固件;即便不知道密钥,ECB 也允许在包内替换整块。被篡改或损坏的镜像会被当成合法固件写入并激活。</td><td>改为“整镜像 SHA-256 + ECDSA/Ed25519 签名”或至少 AES-CMAC/HMAC;加密改为 AES-CTR/GCM 并带包序号作 nonce;结束时校验总长度与整体摘要后才置可用标志。</td></tr>
|
||||
<tr><td>F-03</td><td><span class="b crit">致命</span></td><td>升级可靠性</td><td class="loc">sys/OTA.cpp:369-373, 453, 466-471</td><td>① writeApplicationData 写 Flash 失败只 printf,不返回错误、不上报,随后照常回 ACK;② CRC 校验失败的包仍会继续检查尾帧标志 receive_IFEND,若尾帧本身 CRC 错误也照样置 FINISHED 并跳转;③ 结束时不校验 received_size 与 expected_size(received_size 从未累加)。</td><td>丢包、写失败、尾帧损坏都可能导致残缺镜像被 jumpToApplication 置为“可用+激活”(OTA.cpp:232-233),只做向量表两字检查就跳转,设备可能变砖或运行半截固件。</td><td>写失败要回错误帧并让上位机重发;尾帧必须 CRC 通过;累加已写字节并在结束时比对 expected_size 与整镜像校验值,全部通过后才写可用标志。</td></tr>
|
||||
<tr><td>S-01</td><td><span class="b high">严重</span></td><td>Flash/断电安全</td><td class="loc">sys/OTA.cpp:41-124(OTA_SET)</td><td>6 个 OTA 标志共用 0x0801E000 一页。把某位从 0 改回 1 时整页擦除后再逐项重写,无双页/日志结构,重写结果不检查。</td><td>擦除后、重写前掉电,所有标志(包括备份可用标志)全部变回 0xFFFFFFFF:主区与备份都被判无效,设备只能停在 OTA 模式等待上位机。</td><td>改为双页乒乓或追加式记录(序号+CRC),先写新记录再作废旧记录;写后回读校验。</td></tr>
|
||||
<tr><td>S-02</td><td><span class="b high">严重</span></td><td>Flash 驱动用法</td><td class="loc">sys/OTA.cpp:18-27, 54, 86, 98, 307-309;sys/initial.cpp:208</td><td>write_ADDRESS 每次写完都 fmc_lock()。OTA_SET 内先调用 write_ADDRESS(会上锁)再 fmc_page_erase;eraseApplicationArea 连续调用 3 次 OTA_SET,第 2、3 次进入时 FMC 已被上锁;EXTI 唤醒中断里调用 OTA_SET 前根本没有解锁。GD32 库在锁定时写 FMC_CTL 无效而 fmc_ready_wait 仍返回 READY。</td><td>页擦除可能被静默跳过却返回成功,标志位停留在旧值(例如“激活”标志清不掉),状态机与实际 Flash 状态不一致。</td><td>由 OTA_SET 自己负责一次 unlock/lock,write_ADDRESS 不再加解锁;擦除后回读确认 0xFFFFFFFF;所有 Flash 操作统一入口。</td></tr>
|
||||
<tr><td>S-03</td><td><span class="b high">严重</span></td><td>通信协议</td><td class="loc">sys/OTA.cpp:623-634</td><td>getDeviceSerialNumber 把寄存器地址常量(0x1FFFF7E8 等)本身当作 UID 数值,没有解引用。</td><td>所有设备上报的“UID”完全相同,UID 在握手中失去意义,无法做设备绑定或按设备派生密钥。</td><td>改为 *(volatile uint32_t*)DEVICE_SERIAL_ADDR_xxx 读取。</td></tr>
|
||||
<tr><td>S-04</td><td><span class="b high">严重</span></td><td>通信协议</td><td class="loc">sys/config.h:49-53;device/Can.cpp:105-119, 196-222</td><td>协议没有节点地址:所有设备使用相同的固定 CAN ID(0x100-0x103),硬件过滤器全通(mask=0)。</td><td>同一总线上多块处于 BOOT 的板子会同时响应握手、同时擦写、同时回 ACK,ACK 冲突/交错,升级结果不可预测;也无法单独升级某一节点。</td><td>在 ID 或负载中加入节点号(可由 UID 派生),过滤器只收本节点与广播 ID。</td></tr>
|
||||
<tr><td>S-05</td><td><span class="b high">严重</span></td><td>CAN 接收/实时性</td><td class="loc">device/Can.cpp:196-222, 150-163(communication_check)</td><td>接收只有单个 receive_message 缓冲,ISR 每收一帧整体覆盖,计数器 can0_receive_count 只是计数;主循环取出时读到的永远是最后一帧,且计数自减在主循环、自增在 ISR,无临界区。ISR 还接收 ACK/WAIT ID——其他 BOOT 节点每 10 ms 发送的 WAIT 心跳会覆盖本该处理的数据帧。</td><td>连续两帧到达(握手应答+数据、多节点心跳)就会丢帧或同一帧被处理两次;提交 26cf5af 声称的“修复BOOT丢帧”并未根治。</td><td>改为环形接收队列(深度≥4,ISR 入队/主循环出队,单生产者单消费者),ISR 只接收 REQ/DATA/CANCEL。</td></tr>
|
||||
<tr><td>S-06</td><td><span class="b high">严重</span></td><td>CAN 接收</td><td class="loc">device/Can.cpp:203-212</td><td>temp_message 是未初始化的栈变量,can_message_receive 只在扩展帧时写 rx_efid;收到标准帧时 rx_efid 为栈上残值。CANFD_OTA_CANCEL_ID = 0。</td><td>总线上任意标准帧都可能被判成某个 OTA ID,残值为 0 时会被当成“取消 OTA”,中途终止升级。</td><td>temp_message 先清零或调用 can_struct_para_init;先判断 rx_ff==CAN_FF_EXTENDED 再比较 ID;取消命令不要用 ID 0。</td></tr>
|
||||
<tr><td>S-07</td><td><span class="b high">严重</span></td><td>故障保护</td><td class="loc">整个工程(无 fwdgt/wwdgt 使用);device/Can.cpp:73;RTE/.../gd32c10x_it.c:54-98</td><td>没有启用任何看门狗;CAN auto_bus_off_recovery = DISABLE 且无软件恢复;HardFault/BusFault 等全部是死循环。</td><td>任何卡死(总线 bus-off、Flash 等待、异常)后设备永久停机,只能人工断电;BOOT 是最后一道防线,不能没有自恢复。</td><td>启用独立看门狗并在主循环喂狗(跳 APP 前保持启用,APP 接管);开启 bus-off 自动恢复;Fault 处理改为记录原因后系统复位。</td></tr>
|
||||
<tr><td>S-08</td><td><span class="b high">严重</span></td><td>调试代码进入发布版</td><td class="loc">sys/config.h:17;sys/OTA.cpp:311-337, 324;253-280</td><td>DEBUG_OTA=1 是当前发布配置。① eraseApplicationArea 在 __disable_irq() 后擦除失败分支调用 delay_1ms(5000),该延时依赖 SysTick 中断 → 永久死等;② 擦除循环每页在关中断状态下 printf;③ jumpToApplication 关闭 USART0 时钟后仍 printf(jumping3/jumping5),fputc 轮询 TBE。</td><td>擦除失败时设备永久挂死(无看门狗兜底);跳转路径存在挂在 fputc 的风险(与外设时钟关闭后寄存器读值有关,需实测);关中断时间长导致 CAN 溢出。</td><td>发布版置 DEBUG_OTA=0;关中断区段内禁止 printf/延时;跳转前先输出日志再关时钟。</td></tr>
|
||||
<tr><td>S-09</td><td><span class="b high">严重</span></td><td>备份恢复</td><td class="loc">sys/OTA.cpp:657-742;sys/flash.cpp:25</td><td>move_app_data 用硬件 CRC 校验拷贝结果,但 RCU_CRC 时钟只在 FlashEEPROM::init() 中开启,而 flash.cpp 不在构建清单、init() 从未被调用;main.cpp:88 也忽略 move_app_data 返回值,直接跳转。</td><td>CRC 外设无时钟时读回值恒定,src_crc==dst_crc 恒成立,校验形同虚设;拷贝失败也会跳转到半截镜像。另外拷贝前先擦除主区,拷贝中掉电则主区损坏,只能依赖备份再次恢复。</td><td>调用前 rcu_periph_clock_enable(RCU_CRC);检查返回值,失败时进入 OTA 模式而不是跳转;备份区自身应有长度+CRC/签名头。</td></tr>
|
||||
<tr><td>G-01</td><td><span class="b mid">一般</span></td><td>升级流程</td><td class="loc">sys/OTA.cpp:140-185;config.h:74</td><td>超时计数:非 IDLE 状态每次 process() 只 delay_1us(100) 后 ota_time++,OTA_TIMEOUT=10000 → 实际约 1 s,与注释“10 秒”不符;delay_1us 基于空循环估算,随编译优化变化。</td><td>上位机准备/擦除较慢时容易误超时;行为依赖优化级别。</td><td>超时统一基于 SysTick 毫秒计数(记录时间戳比较)。</td></tr>
|
||||
<tr><td>G-02</td><td><span class="b mid">一般</span></td><td>升级流程</td><td class="loc">sys/OTA.cpp:142-153, 319-329</td><td>页擦除失败只发错误帧并 break,process() 仍把状态置为 RECEIVING_FIRMWARE。</td><td>在擦除不完整的区域继续接收写入,产生 PGERR 或混合镜像。</td><td>eraseApplicationArea 返回结果,失败则回到 IDLE。</td></tr>
|
||||
<tr><td>G-03</td><td><span class="b mid">一般</span></td><td>升级流程</td><td class="loc">sys/OTA.cpp:456-457</td><td>offset = receive_packet_num * 48 为 u32 乘法,可溢出回绕后通过 offset+48 ≤ APP_MAX_SIZE 检查。</td><td>异常包序号会写入意外偏移。</td><td>先检查 receive_packet_num < APP_MAX_SIZE/48 再计算偏移;同时要求序号单调连续。</td></tr>
|
||||
<tr><td>G-04</td><td><span class="b mid">一般</span></td><td>A/B 设计</td><td class="loc">main.cpp:24-101;sys/OTA.cpp:221-234</td><td>所谓 A/B 实为“主区 + 恢复区”:BOOT 从不写备份区;新固件的 CHECK 标志只能由 APP 写入(隐含约定,无文档)。若 APP 未写 CHECK,下次复位会走备份分支,用备份覆盖刚升级的新固件。</td><td>升级后“回退”行为取决于 APP 是否遵守未文档化约定,容易出现“升级后重启又变回旧版”。</td><td>书面定义 BOOT/APP 标志握手协议(试运行→确认→回滚计数);或真正双槽并只切换启动槽。</td></tr>
|
||||
<tr><td>G-05</td><td><span class="b mid">一般</span></td><td>跳转</td><td class="loc">sys/OTA.cpp:250-271</td><td>切换到 IRC8M 后未等待 SCSS 生效,也未关闭 PLL/HXTAL、未复位 RCU 寄存器;SysTick 关闭后未清除 SCB->ICSR 挂起位。</td><td>APP 的 SystemInit 一般能兜底,但时钟残留状态与 APP 预期不一致时会出现难查的启动问题。</td><td>调用 rcu_deinit() 或按 SystemInit 逆序复位时钟,清 PendSV/SysTick 挂起。</td></tr>
|
||||
<tr><td>G-06</td><td><span class="b mid">一般</span></td><td>CAN 发送</td><td class="loc">device/Can.cpp:376-409;Can.h:5-43;Can.cpp:122</td><td>CAN0_TX_IRQHandler 未在 extern "C" 中声明,C++ 名字修饰后不会覆盖启动文件的弱符号(map 中无该函数);NVIC 也从未使能 CAN0_TX_IRQn。</td><td>发送队列只入队不出队:邮箱满时消息进入队列后永远不会发送,提交 d019b41 的“发送队列机制”实际不工作。</td><td>在 extern "C" 中声明 TX 中断函数并 nvic_irq_enable(CAN0_TX_IRQn);或在主循环轮询出队。</td></tr>
|
||||
<tr><td>G-07</td><td><span class="b mid">一般</span></td><td>CAN-FD</td><td class="loc">device/Can.cpp:315-334</td><td>DLC 长度映射有缺档:分支为 21-23→24、29-32→32,长度恰为 24 以及 25-28 没有任何分支,直接返回失败(应为 21-24→24、25-32→32)。</td><td>发送 24~28 字节报文会被静默丢弃(当前协议最大 36/64 字节,未来扩展易踩坑)。</td><td>用查表把长度向上取整到 {12,16,20,24,32,48,64}。</td></tr>
|
||||
<tr><td>G-08</td><td><span class="b mid">一般</span></td><td>睡眠/唤醒</td><td class="loc">sys/initial.cpp:147-177, 199-255</td><td>唤醒中断中执行 Flash 擦写与 OTA_SET(未解锁,见 S-02);地址循环用 address >= SLEEP_CONFIG_START 递减,起点为 0x0801E400 时边界写法易错;enter_deep_sleep 返回后无处理(醒来靠 EXTI 软复位)。</td><td>ISR 内长时间 Flash 操作;唤醒后标志写入可能失败。</td><td>ISR 只置标志,Flash 操作放主流程;睡眠标志使用与 OTA 标志相同的可靠记录格式。</td></tr>
|
||||
<tr><td>G-09</td><td><span class="b mid">一般</span></td><td>代码质量</td><td class="loc">sys/OTA.h:12;OTA.h:18</td><td>成员 u32 ota_stateota_time(明显拼接笔误,未使用);isActive() 返回 ota_state 非零,WAITING_RANDOM 等早期状态即被视为“进入 OTA”。</td><td>可读性差;延迟启动期间收到一帧握手就永久停在 OTA 循环,即使之后超时回 IDLE 也不会再跳 APP(main.cpp:61-67)。</td><td>删除笔误成员;OTA 循环中 IDLE 持续超时后重新走启动判定。</td></tr>
|
||||
<tr><td>G-10</td><td><span class="b mid">一般</span></td><td>代码质量</td><td class="loc">sys/OTA.cpp:18(inline)与 sys/initial.cpp:183</td><td>write_ADDRESS 在两个翻译单元各定义一次(一个 inline、一个外部链接),违反 ODR。</td><td>链接器选择哪份实现不确定,后续改动其中一份会产生隐蔽差异。</td><td>只保留一份,放到 flash 模块并在头文件声明。</td></tr>
|
||||
<tr><td>G-11</td><td><span class="b mid">一般</span></td><td>代码质量</td><td class="loc">sys/OTA.cpp:676, 709, 735 与 config.h:17</td><td>move_app_data 内用 OTA_DEBUG,而全工程定义的是 DEBUG_OTA,这些日志永远不会输出。</td><td>恢复失败时没有任何诊断信息。</td><td>统一宏名。</td></tr>
|
||||
<tr><td>A-01</td><td><span class="b low">建议</span></td><td>构建</td><td class="loc">sys/flash.h:5-14 / sys/flash.cpp(未加入 cproject.yml)</td><td>flash.cpp/flash.h 未参与构建,且 FLASH_EEPROM_OK 枚举与 config.h 的 constexpr 同名冲突;EEPROM 地址 0x0801F800 与其他区无文档说明。</td><td>死代码误导维护者,一旦加入构建即编译失败。</td><td>删除或整合进统一 Flash 存储模块。</td></tr>
|
||||
<tr><td>A-02</td><td><span class="b low">建议</span></td><td>内存配置</td><td class="loc">RTE/.../startup_gd32c10x.s:42;regions_GD32C103CB.h:96-97;map</td><td>启动文件 Stack 0x800 + scatter ARM_LIB_STACK 0x200 + HEAP 0xC00 三套配置并存(map 中均占用 RAM),microlib 下实际 MSP 来自向量表(2 KB)。</td><td>浪费 ~3.5 KB RAM,且栈大小以哪处为准不明确。</td><td>只保留一处栈定义;BOOT 不用 malloc 时把 HEAP 设为 0。</td></tr>
|
||||
<tr><td>A-03</td><td><span class="b low">建议</span></td><td>构建配置</td><td class="loc">Robot_V2.csolution.yml:42-47</td><td>Debug 为 optimize none,Release 为 size;ROM 使用 0x3398/0x6000(约 54%),余量可接受。BOOT 版本号写死在 config.h,未写入镜像固定位置。</td><td>上位机无法读取 BOOT 版本;Debug/Release 时序差异(空循环延时)大。</td><td>在固定偏移放置版本/构建信息结构;延时不依赖优化级别。</td></tr>
|
||||
<tr><td>A-04</td><td><span class="b low">建议</span></td><td>仓库卫生</td><td class="loc">.gitignore;out/、tmp/(65 个文件)</td><td>out/、tmp/ 构建产物(axf/hex/map/.o/CMake 缓存等)在 .gitignore 生效前已被跟踪,至今仍在库中,每次提交都产生大量噪声 diff;compile_commands.json 含本机路径 G:/Robot_v2/BOOT。</td><td>仓库膨胀、评审困难、泄露本机目录结构。</td><td>git rm -r --cached out tmp(由维护者执行);发布固件改用 Release 附件。</td></tr>
|
||||
<tr><td>A-05</td><td><span class="b low">建议</span></td><td>仓库卫生</td><td class="loc">Robot_V2.cbuild-idx.yml、*.cbuild-pack.yml、.vscode/*.json、.continue/mcpServers/new-mcp-server.yaml、RTE/*.base@1.0.0</td><td>生成文件与 IDE 本地配置被跟踪(.gitignore 已声明忽略但未从索引移除);.continue 下是未填写的模板。</td><td>多人协作时频繁冲突。</td><td>从索引移除并保持忽略;保留 cbuild-pack.yml(锁定包版本)即可。</td></tr>
|
||||
<tr><td>A-06</td><td><span class="b low">建议</span></td><td>文档/测试</td><td class="loc">仓库根目录</td><td>无 README、无协议文档(帧格式、状态机、标志位定义、BOOT/APP 约定)、无主机侧工具说明、无任何测试(AES 可用 FIPS-197 向量做单元测试)。</td><td>知识只在作者脑中,协议变更无法验证。</td><td>补 README + docs/protocol.md(状态机图、帧表、Flash 分区表);为 AES/CRC/标志模块加主机侧单元测试。</td></tr></table>
|
||||
|
||||
<h2>5. 提交声明跟踪表(替代既有评审跟踪)</h2>
|
||||
<table><tr><th>提交</th><th>声明</th><th>当前状态</th><th>核对说明</th></tr><tr><td class="loc">2f48255 / 9c7145e</td><td>OTA 功能测试通过;安全 OTA,AES 加密和 CRC 校验</td><td><b>部分成立</b></td><td>加解密与 CRC 已实现,但主密钥明文入库、无签名、ECB 模式、CRC 非 MAC(F-01、F-02);UID 读取错误(S-03)。</td></tr>
|
||||
<tr><td class="loc">c7c4451</td><td>支持 A/B 分区逻辑</td><td><b>部分成立</b></td><td>实为主区+恢复区,BOOT 不写备份区;确认依赖 APP 写 CHECK 的隐含约定(G-04)。</td></tr>
|
||||
<tr><td class="loc">aefb7d4</td><td>修复备份 APP 区域恢复功能</td><td><b>部分成立</b></td><td>恢复路径可执行,但 CRC 外设无时钟导致校验无效、返回值被忽略(S-09)。</td></tr>
|
||||
<tr><td class="loc">26cf5af</td><td>修复 BOOT 丢帧问题,优化标志位存储</td><td><b>未根治</b></td><td>单缓冲接收仍会被后续帧/心跳覆盖(S-05);标志页整页擦写断电风险仍在(S-01)。</td></tr>
|
||||
<tr><td class="loc">d019b41</td><td>CAN FD 协议栈优化和发送队列机制</td><td><b>不成立(队列未生效)</b></td><td>TX 中断函数名被 C++ 修饰、NVIC 未使能,队列不会出队(G-06);DLC 映射有缺档(G-07)。</td></tr>
|
||||
<tr><td class="loc">1e6d47d</td><td>完整的系统休眠和唤醒机制</td><td><b>基本成立,有缺陷</b></td><td>可休眠并通过 PB8 EXTI 唤醒复位;唤醒 ISR 内做 Flash 操作且未解锁(G-08、S-02)。</td></tr>
|
||||
<tr><td class="loc">46d4bfe</td><td>APP 延迟启动模式支持 OTA 请求检测</td><td><b>成立,有缺陷</b></td><td>10 s 窗口工作正常;一旦进入早期握手状态即永久停在 OTA 循环(G-09)。</td></tr>
|
||||
<tr><td class="loc">05069e3</td><td>移除 CAN DMA、-Oz/ROM 护栏、-fno-exceptions</td><td><b>成立</b></td><td>DMA 代码已移除;Release 为 size 优化,ROM 占用 0x3398/0x6000;但 jumpToApplication 仍关闭 RCU_DMA0(无害残留)。</td></tr></table>
|
||||
|
||||
<h2>6. 优先级修复路线图</h2>
|
||||
<table><tr><th>阶段</th><th>内容</th><th>对应问题</th></tr>
|
||||
<tr><td><b>P0 立即(发布前必须)</b></td><td>发布版关闭 DEBUG_OTA;修 UID 解引用;写失败/尾帧 CRC/长度校验失败一律不置可用标志;OTA_SET 解锁/上锁统一并回读校验;move_app_data 开 CRC 时钟并检查返回值;启用独立看门狗与 bus-off 恢复</td><td>F-03, S-02, S-03, S-07, S-08, S-09</td></tr>
|
||||
<tr><td><b>P1 短期(1-2 周)</b></td><td>接收环形队列 + 帧格式判断 + 只收本节点 ID;协议加入节点地址;标志区改双页/追加式记录;修 TX 中断与 DLC 映射;超时改为 SysTick 时间戳</td><td>S-01, S-04, S-05, S-06, G-01, G-02, G-03, G-06, G-07</td></tr>
|
||||
<tr><td><b>P2 中期(安全加固)</b></td><td>密钥移出源码并按 UID 派生;双向 nonce 防重放;整镜像签名(ECDSA/Ed25519)+ AES-CTR/GCM;版本号防降级;开启读保护</td><td>F-01, F-02</td></tr>
|
||||
<tr><td><b>P3 持续</b></td><td>书面 BOOT/APP 标志协议与回滚策略;清理 out/tmp 与生成文件;README + 协议文档;AES/CRC 单元测试;统一栈堆配置与调试宏</td><td>G-04, G-05, G-08-G-11, A-01-A-06</td></tr></table>
|
||||
|
||||
<h2>7. 总结评分</h2>
|
||||
<table><tr><th>维度</th><th>评分 /10</th><th>说明</th></tr>
|
||||
<tr><td>架构清晰度</td><td>6</td><td>模块划分简单明了,分区与状态机易懂;BOOT/APP 约定未文档化</td></tr>
|
||||
<tr><td>升级可靠性</td><td>4</td><td>有恢复区与延迟启动;写失败/断电/残缺镜像均可能被激活</td></tr>
|
||||
<tr><td>安全性</td><td>3</td><td>有加密握手的意图,但密钥入库、无签名、ECB、可重放</td></tr>
|
||||
<tr><td>通信与实时性</td><td>5</td><td>CAN-FD 配置正确、BRS 生效;单缓冲接收、无寻址、发送队列失效</td></tr>
|
||||
<tr><td>故障保护</td><td>3</td><td>无看门狗、无 bus-off 恢复、Fault 死循环</td></tr>
|
||||
<tr><td>代码质量</td><td>6</td><td>注释充分、可读;存在 ODR 重复定义、宏名不一致、死代码</td></tr>
|
||||
<tr><td>构建与仓库卫生</td><td>5</td><td>csolution 配置规范、ROM 余量足;构建产物与生成文件入库、无 README/测试</td></tr>
|
||||
<tr><td><b>综合</b></td><td><b>5.0</b></td><td>功能链路已打通、可用于台架;量产前须完成 P0+P1,面向现场设备须完成 P2</td></tr></table>
|
||||
<p style="color:#57606a;font-size:12px">本报告仅新增于 docs/review/,未修改任何源码。由 Hark 生成。</p>
|
||||
</body></html>
|
||||
Reference in New Issue
Block a user