4.1 安全栈全景——Arctic Core的安全模块地图
场景:打开仓库的那一刻
你打开 Arctic Core 的源码仓库,准备搞清楚“功能安全代码到底藏在哪“。你翻遍了目录树,发现安全模块散落在三个完全不同的顶层目录里:
classic-platform/
├── safety_security/ ← 安全/加密核心
│ ├── WdgM/ ← 看门狗管理器(1450行)
│ ├── WdgIf/ ← 看门狗抽象接口
│ └── SafeLib/
│ ├── Crc/ ← CRC校验引擎(32/16/8位)
│ └── E2E/ ← 端到端通信保护库
├── memory/
│ ├── RamTst/ ← SRAM硬件自检
│ ├── NvM/ ← 非易失存储管理
│ └── ...
└── datastructures/
└── Safety_Queue/ ← CRC保护的安全队列
这些文件的位置不是随便定的。每个模块都是一道防御层,一个安全免疫系统。Arctic Core 是 ArcCore AB 开源的 AUTOSAR 平台,采用 GPLv2 双授权(GPLv2 + 商业许可),其安全性经过量产验证。它严格遵循 AUTOSAR 4.3.0 规范,并带有详细的 @req SWS_xxx 需求追溯标记。
本章总共涉及约 6560 行 C 语言安全代码,分布在 8 个核心源文件中。今天我们先来画一张地图,看清全貌。
一、为什么像免疫系统?
Arctic Core 的安全栈像人体免疫系统一样分层工作。RamTst 在 ECU 上电后遍历每一块 SRAM,检测硅片的 stuck-at 故障,这是硬件层面的物理检查。WdgM 在每个 MainFunction 周期内检查所有受监控实体的存活、时限和逻辑正确性,相当于运行时巡逻。E2E + CRC + Safety_Queue 通过数学签名验证每一次通信的真实性。而 WdgM 聚合所有局部状态,决定系统进入 OK/FAILED/EXPIRED/STOPPED 哪一个全局状态,触发复位或降级。
你会在后续各节中反复看到这套逻辑。现在先看架构。
二、AUTOSAR 层映射
Arctic Core 的安全模块在 AUTOSAR 分层架构中的位置:
┌──────────────────────────────────────────┐
│ 应用层 (SW-Cs, CDDs) │
│ 调用 WdgM_CheckpointReached() │
│ 调用 E2E_P01Check()/E2E_P01Protect() │
│ 使用 Safety_Queue 通信 │
├──────────────────────────────────────────┤
│ RTE (Run-Time Environment) │
│ Rte_Switch_globalMode_currentMode() │
│ modeFunctionSwitchPointer[] │
├───────────────┬──────────────────────────┤
│ 服务层 │ ECU抽象层 │
│ WdgM │ WdgIf │
│ RamTst │ Mcu (复位) │
│ Crc │ Os (计数器) │
├───────────────┴──────────────────────────┤
│ MCAL (Microcontroller Abstraction) │
│ 硬件看门狗驱动 │
└──────────────────────────────────────────┘
关键点:WdgM 位于服务层,它不直接操作硬件看门狗。而是通过 WdgIf 抽象层间接调用。这种间接性是 AUTOSAR 的核心哲学:上层只关心策略(何时触发看门狗),下层关心机制(如何操作寄存器)。
三、模块全景图
下面是安全栈所有模块的依赖关系图:
┌──────────────────────────────────┐
│ Application SW-C │
│ CheckpointReached(SE1, CP3) │
│ E2E_P01Protect(data, state) │
└───────┬──────────────┬───────────┘
│ │
┌───────────▼──────┐ ┌──▼──────────────────┐
│ WdgM (1450行) │ │ Safety_Queue (284行)│
│ alive/deadline/ │ │ 缓冲CRC+队列CRC │
│ logical监控 │ │ 双CRC防静默损坏 │
└──┬───────┬──────┬┘ └──┬──────────────────┘
│ │ │ │
┌────▼──┐ ┌─▼──┐ ┌─▼──────┐▼──────┐
│WdgIf │ │ Os │ │E2E(680)│Crc(232)│
│抽象层 │ │计数│ │6Profile│8/16/32│
└───┬───┘ └────┘ └────────┴───────┘
│
┌───▼────┐
│HW Wdg │
└────────┘
┌─────────────────────────────────┐
│ RamTst (561行) │
│ March X 算法 │
│ 启动时SRAM全检 │
└─────────────────────────────────┘
四、逐模块概览
4.1 WdgM(看门狗管理器)— 核心调度中心
文件:safety_security/WdgM/src/WdgM.c(1450行)
WdgM 是安全栈的“大脑“。它实现了 AUTOSAR 规范定义的三重监督:
- Alive Supervision(存活监控):应用软件调用
WdgM_CheckpointReached()报告自己还活着。WdgM 在每个 MainFunction 周期累计计数,用容忍度(MinMargin/MaxMargin)判断是否正常。 - Deadline Supervision(时限监控):利用 OS 计数器记录两个 checkpoint 之间的时间间隔,判断是否在 DeadlineMin 到 DeadlineMax 范围内。
- Logical Supervision(逻辑监控):维护一张转换表(Transitions),验证 checkpoint 的执行顺序是否合法,只有图中定义的有向边才是有效的程序执行路径。
每轮 WdgM_MainFunction() 执行时,WdgM 汇总三重监控的结果,更新每个 SupervisedEntity 的 LocalState(OK→FAILED→EXPIRED),然后汇总出 GlobalState(OK/FAILED/EXPIRED/STOPPED),最终决定是否触发硬件看门狗复位。
4.2 WdgIf(看门狗抽象接口)
位于 safety_security/WdgIf/,为 WdgM 提供统一的硬件看门狗接口:WdgIf_SetMode() 和 WdgIf_SetTriggerCondition()。WdgM 通过 WdgIf 切换看门狗模式(FAST/SLOW/OFF),而不关心底层是哪个芯片。
4.3 E2E 库(端到端通信保护)
文件:SafeLib/E2E/src/E2E_P01.c + E2E_SM.c + inc/E2E.h
E2E 库提供端到端通信的数据保护。它支持 6 种 Profile(P01 P02 P04 P05 P06 P11),Arctic Core 实现了 P01 和 P02。核心机制:
- Protect(发送端):在数据帧中嵌入 CRC 校验和 + 4-bit 计数器 + DataID。
- Check(接收端):提取计数器、计算 CRC、比对 DataID、检测重复/丢失/乱序/超时。
- State Machine(状态机):基于滑动窗口维护 OK/ERROR 计数,实现从 INIT→VALID→INVALID 的状态迁移。
值得注意:E2E 库不允许调用 RTE 或 BSW 模块,它必须是一个纯粹的数学函数库,错误只通过返回值报告。
4.4 CRC 引擎
文件:SafeLib/Crc/src/Crc_32.c(232行)
实现了 IEEE-802.3 CRC32(多项式 0x04C11DB7),支持两种模式:
CRC_32_RUNTIME:逐位计算(用于验证查表结果)CRC_32_TABLE:256 项预计算查表(生产模式)
同时实现了 CRC8(SAE J1850 多项式 0x1D)和 CRC16,供 E2E 和 Safety_Queue 调用。
4.5 Safety_Queue(安全队列)
文件:datastructures/Safety_Queue/src/Safety_Queue.c(284行)
一个双 CRC 保护的环形缓冲区。它在每次 Add/Next/Peek/Contains 操作前计算所有数据的 CRC8 并与保存值比对,如果硬件静默翻转了内存中的任何一个 bit,队列立即返回 QUEUE_E_CRC_ERR。这是为 ASIL 等级设计的特殊数据结构。
4.6 RamTst(SRAM 自检)
文件:memory/RamTst/src/RamTst.c(561行)
在 ECU 启动时执行 March X 算法:
- 按升序写入全0
- 按升序读0、写1
- 按降序读1、写0
- 按降序读0
每一步都检测特定的故障模型:stuck-at、耦合、地址解码错误。按块配置、按块报告,支持 Suspend/Resume 以允许中断期间的暂停。
五、编译时配置树
看 WdgM_ConfigTypes.h,你会发现一个关键设计:所有配置都是 const 结构体,没有运行时分配:
WdgM_ConfigType ← 顶层配置
├── WdgM_General
│ ├── SupervisedEntities[] → WdgM_SupervisedEntity(转换图、起止点)
│ └── Watchdogs[] → WdgM_Watchdog(设备映射)
└── WdgM_ConfigSet
├── DemEventIdRefs → DEM事件ID
├── initialModeId → 初始模式
└── Modes[] → WdgM_Mode
├── SEConfigurations[] → WdgM_SupervisedEntityConfiguration
│ ├── AliveSupervisions[] → 每个checkpoint的期望/容忍
│ ├── DeadlineSupervisions[] → 起止checkpoint + 时间上下限
│ └── FailedAliveSupervisionReferenceCycleTol → 容忍周期数
├── Triggers[] → WdgM_Trigger(看门狗模式+触发值)
└── ExpiredSupervisionCycleTol → Expired→STOPPED容忍
这一切在链接之前就完全确定了。配置错误会导致编译失败(#error 指令),而不是运行时崩溃。这是功能安全编码的核心原则。
六、文件组织速查
| 模块 | 路径 | 源文件行数 | 核心功能 |
|---|---|---|---|
| WdgM | safety_security/WdgM/src/ | 1450 | 三重监督状态机 |
| WdgIf | safety_security/WdgIf/ | ~200 | 看门狗硬件抽象 |
| E2E_P01 | SafeLib/E2E/src/E2E_P01.c | 680 | Profile 1 端到端保护 |
| E2E_SM | SafeLib/E2E/src/E2E_SM.c | 247 | E2E 状态机 |
| Crc_32 | SafeLib/Crc/src/Crc_32.c | 232 | CRC32 运行时+查表 |
| Safety_Queue | datastructures/Safety_Queue/src/ | 284 | 双CRC保护环形缓冲区 |
| RamTst | memory/RamTst/src/RamTst.c | 561 | March X SRAM自检 |
Arctic Core 的安全栈不是“堆砌功能模块“。而是用 const 编译时配置 将所有模块编织成一条完整的防御链:SRAM 启动自检 → 运行时三重监控 → 数据完整性校验 → 硬件看门狗复位。每一层的失败都有明确的状态机处理,不存在“悄悄失败“的路径。这就是量产级代码与原型代码的本质区别。
本篇小结
- Arctic Core 的安全栈分布于
safety_security/、memory/、datastructures/三个顶层目录,共约 6560 行 C 代码,构成一道从硬件自检到运行时监控再到数据完整性的分层防御链。 - WdgM(看门狗管理器)是安全栈的“大脑“,实现 Alive/Deadline/Logical 三重监督,在每个 MainFunction 周期内汇总局部状态为全局状态(OK→FAILED→EXPIRED→STOPPED),决定是否触发硬件看门狗复位。
- E2E 库和 CRC 引擎作为纯函数库,不依赖 RTE 或 BSW 模块,通过 CRC 校验、计数器和 DataID 实现端到端通信保护,可独立认证为 Safety Element out of Context(SEooC)。
- Safety_Queue 采用双 CRC 保护(bufferCrc + queueCrc),在每次 Add/Next/Peek 操作前验证数据完整性,检测 RAM 静默损坏后返回
QUEUE_E_CRC_ERR。 - RamTst 在 ECU 启动时执行 March X 算法,通过四遍升序/降序遍历检测 stuck-at、耦合和地址解码故障,所有配置均为 const 编译时结构体,错误在链接前暴露。
【下集预告】: 全景地图看完了,该钻进最核心的引擎了。下一节打开
WdgM.c的 1450 行源码,看三重监督(存活/时限/逻辑)如何用三个独立的 C 函数并行执行,然后通过一门精妙的加法算术聚合为全局状态。你会看到-MinMargin/+MaxMargin容忍度为什么不是性能优化而是安全设计,以及为什么 6 行冗余取反存储代码被 NASA 航天器采用同类思想。准备好面对真正的 AUTOSAR 级代码密度了吗?