结论:GM panda safety 按 HW_CAM、HW_CAM_LONG、EV 三个参数位切换硬件拓扑与 TX 表,三者的使能与转发策略互不相同:ASCM 分支 disable_forwarding=true 完全禁转发、由按钮沿使能;相机原车纵向跟随 PCM;相机自控纵向仅在调试构建且 HW_CAM_LONG 置位时才把 gm_pcm_cruise 改为假。白名单只控制 CAN 地址、总线、长度,不代表所有字段都经安全认证。
本文基于固定源码快照逐函数静态解析 opendbc/safety/modes/gm.h,结合通用 safety 分发与本机原版 GM 测试。未编译目标固件或接入车辆;这里的总线号、编码和阈值仅适用于该源码快照及匹配车型,不能直接当作新硬件配置。
RX:来源、使能与完整性缺口
GM_COMMON_RX_CHECKS 监视总线 0 的 0x184 驾驶员扭矩、0x34A 后轮速度、0x1E1 按钮、0xBE 踏板、0x1C4 油门/巡航和 0xC9 制动状态;0xBE 允许三种长度以适配不同车型。各项暂以 10 Hz 标称检查,且显式忽略校验和、计数器、质量位——源码 TODO 指出这不是完整报文完整性校验。EV 参数位另把 0xBD 再生制动消息纳入 RX 表,频率配置为 40 Hz。
| 报文 | 用途 | 完整性处理 |
|---|---|---|
| 0x184 | 驾驶员扭矩(11 位有符号,进共享采样窗口) | 忽略校验和/计数器/质量位 |
| 0x34A | 后轮双速;两轮原始速度均不超过 10 判静止 | 停车判据,不是完整车速估计 |
| 0x1E1 | 按钮沿使能(ASCM 用 SET 松开沿或 RESUME 按下沿) | 忽略完整性字段 |
| 0xBE | ASCM 刹车(字节阈值);允许三种长度 | 与相机刹车帧 0xC9 不是同义来源 |
| 0x1C4 | 相机原车纵向读取巡航接合状态 | 走 pcm_cruise_check() |
| 0xC9 | 相机刹车(bit 40) | 与 0xBE 不能互换 |
| 0xBD | EV 再生制动,仅 EV 参数位置位时入 RX 表 | 配置为 40 Hz |
safety_rx_hook() 只在检查通过、命中表后调用 gm_rx_hook(),因此再生制动分支并非在非 EV 模式下无条件接收。ASCM 以 0x1E1 的 SET 松开沿或 RESUME 按下沿使能,CANCEL 按下退出;相机原车纵向则从 0x1C4 读取巡航接合状态。
TX 与模式矩阵
GM 自控纵向时 gm_pcm_cruise=false;相机原车纵向时为 true。相机自控纵向仅在调试构建且 HW_CAM_LONG 位置位时把它改为假。这决定使能来自按钮沿还是 PCM,影响告警与执行权限,不只是 TX 白名单的变化。
| 模式 | 纵向 TX | 转发与使能 |
|---|---|---|
ASCM,HW_CAM=0 |
0x2CB 位于总线 0,0x315 位于总线 2;另有观测/keepalive 帧 | disable_forwarding=true,由按钮沿使能 |
| 相机,默认或 release | 无 0x2CB/0x315;0x1E1 总线 2 仅允许取消 | 跟随 PCM 巡航接合,仍可发横向 0x180 |
相机,ALLOW_DEBUG 且 HW_CAM_LONG=1 |
0x2CB/0x315 总线 0 | 改用按钮沿,禁原车 0x1E1 TX |
| 上述模式叠加 EV | 不改变所选 TX 表 | 仅增加 0xBD 再生制动 RX |
gm_tx_hook() 对 0x180 调用共享扭矩安全检查,含 300 原始单位上限、变化率、驾驶员扭矩与实时增量限制。0x315 的 12 位原始编码先反转为非负制动量,再用 longitudinal_brake_checks() 限制到 max_brake=400 且未使能时必须为零。0x2CB 将油门/再生制动信号偏移到整数域后分别按 ASCM/相机限值检查,apply 位在 controls_allowed=false 时禁止。相机原车纵向的 0x1E1 只有原车巡航已接合且按钮编码为 CANCEL 时放行。
白名单不等于字段认证
并非所有 GM 白名单帧都有逐信号检查:例如 ASCM 的 keepalive/观测帧和相机的 0x184 状态帧,在 gm_tx_hook() 中没有对应载荷分支。白名单控制的是 CAN 地址、总线、长度。
转发层面同样分层:相机模式中 0x184 总线 2 的 check_relay=true 会使共享转发逻辑阻断来自总线 0、目标为总线 2 的同地址帧;ASCM 则完全禁转发。应把「是否允许发」「是否阻断原车转发」「是否检测原车 ECU」分别建模。
验证范围与插件边界
test_gm.py 有 ASCM、相机、EV、相机自控纵向测试类,包含按钮、踏板、扭矩/纵向限值和点火用例。本机运行原版 GM 模块测试为 Ran 192 tests、OK (skipped=19),即 173 项执行且通过,19 项未执行。跳过项来自无 _user_regen_msg 的通用再生制动用例、无第二车速消息的通用检查,以及四个抽象基类的 setUpClass,不能计入通过。
测试调用 libsafety_py._build_libsafety() 默认加 ALLOW_DEBUG,因此相机自控纵向用例不能证明 release 固件接受 HW_CAM_LONG。本机另用严格警告把测试库 safety.c 分别编译为不含/含 ALLOW_DEBUG 的目标文件,只在后者找到 GM_CAM_LONG_TX_MSGS——这核对的是本机编译分支,不是 STM32 固件或运行时许可。实板转发、实际 CAN 来源和目标 ECU 响应仍未测试。
- 自制硬件的 GM 插件契约应固定车型/DBC、ASCM 或相机接线、EV 位、总线号、固件构建类型和
safetyParam。 - 只读采集和回放先验证 0xBE 长度变体、0xC9 刹车、0xBD 再生制动、按钮沿、PCM 巡航及 0x184 驾驶员扭矩。
- 台架再做丢帧、重放、错总线、故障继电器和 release/debug 差异。
- 普通插件只产生候选控制,不能设置安全钩子或绕过板端 TX/转发判定。
常见问题
GM 白名单里的帧都经过字段级安全检查吗?
不是。白名单只控制 CAN 地址、总线、长度;ASCM 的 keepalive/观测帧和相机的 0x184 状态帧在 gm_tx_hook() 中没有对应载荷分支,不能据此声称所有字段都经过安全认证。
相机自控纵向在 release 固件里能用吗?
测试不能证明。相机自控纵向仅在调试构建且 HW_CAM_LONG 位置位时把 gm_pcm_cruise 改为假;而测试默认加 ALLOW_DEBUG,本机只在含该宏的目标文件里找到 GM_CAM_LONG_TX_MSGS,这核对的是编译分支而非运行时许可。
ASCM 和相机的刹车帧可以互换吗?
不能。ASCM 的刹车取 0xBE 字节阈值,相机刹车取 0xC9 的 bit 40,切换拓扑时不能把两种刹车帧视为同义来源;0xBE 还允许三种长度以适配不同车型。
GM 的 RX 完整性与校验和有关系吗?
没有做完整校验。各项暂以 10 Hz 标称检查,且显式忽略校验和、计数器、质量位;源码 TODO 指出这不是完整报文完整性校验。所以「命中 RX 表」不等于「报文完整可信」。
延伸阅读
- Ford 与 GM:两家接入链上的差异 —— 对照另一套构帧与安全分支。
- Hyundai 与 Honda 的车型接入:经典 CAN 与 CAN FD 的分野 —— 补齐车型拓扑切换的同类对照。
- 从使能到车轮:执行链上的八道门,以及它们各自不保证什么 —— 解释「是否允许发」为何不等于「是否阻断原车转发」。
- 同一个「转向灯」在三家车厂是三种实现:车辆状态归一化的坑 —— 说明 0xBE 与 0xC9 这类品牌差异为何不能统一处理。
参考资料
- 项目 02 ——
openpilot-research/GM_PANDA_SAFETY_MODE_DEEP_DIVE.md(取用了 GM 三参数位模式矩阵、RX/TX 与转发边界、白名单不等于字段认证,以及本机测试计数)。 - 项目 02 ——
openpilot-research/ACTUATION_GATE_CHAIN_DEEP_DIVE.md(仅用于确认执行链分层语义,未取用其未公开内容)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11