资讯动态

从 MPU 违例到 AUTOSAR OS ProtectionHook:深入理解 MCU 内存保护

发布时间:2026/10/14 18:31:22 来源:尧图企业网站定制
从 MPU 违例到 AUTOSAR OS ProtectionHook深入理解 MCU 内存保护一次非法内存访问在 CPU、OS、功能安全三个层面分别发生了什么一条 store 指令写到了不该写的地址接下来会发生什么是悄悄改坏数据让故障传导下去还是被硬件当场拦下、交给 OS 处置这篇文章顺着「一次越权访问被 MPU 拦下」这条线把它串起来讲CPU 的 MPU 如何做访问权限检查、这次访问被拦下后如何进入 AUTOSAR OS、OS 又如何通过 ProtectionHook 决定故障响应最后收在 MPU 本身的能力边界上。内容只涉及公开的 CPU/OS 机制示例地址与验证用例均为虚构。第一章为什么已经有 AUTOSAR OS Task 隔离还需要 MPU1. 内存损坏和故障传递内存损坏是意料之外的内存修改比如栈溢出、非法指针操作、变量写越界或者团队间跨模块协作导致的意外内存修改——它们都不属于原有业务逻辑的操作。而且这种修改是静默的不能及时被 OS trap 发现。内存损坏后程序继续运行原本的故障会通过接口继续传导到其他模块。比如某个数据被非法篡改如果是一个明显的非法值这种还容易发现但如果被篡改成一个仍落在合法范围内的偏差值就会悄悄影响其他模块的判断——这种问题十分难查碰到就老实了。2. OS Application 和 Task那么我们的代码是怎么分隔的呢AUTOSAR 中Task 是 OS 的最小调度单元正常的业务代码以 Runnable 组的形式对数据、地址进行访问。OS Application 是 AUTOSAR OS 的资源隔离容器包含 Task、ISR、Counter一个 OS Application 里是需要共用同一块内存区域的元素集合。也就是说OS Application 是软件层面的资源隔离单位MPU 也以 OS Application 作为隔离的最小单位。换个角度思考为什么 MPU 的保护单位不是 Task 而是 OS Application范围不同同一个业务比如以太网一次报文收发会同时依赖 Task 和 ISR。如果以 Task 为隔离单位ISR 和 Task 的协同访问就会触发 MPU 保护。而 OS Application 是 Task、ISR、Counter、SWC 的集合内部元素互相访问内存不受限只有跨 OS Application 的内存访问才被 MPU 拦截从而实现故障隔离。MPU 硬件资源有限频繁切换 MPU 配置性能开销大。切换 MPU 配置要执行特权指令并重载对应的 MPU region而 OS Application 内部的切换只是换栈和 PC开销小得多。软件架构SWC 和 RTE 的粒度是 OS Application。一个 SWC 的 Runnable 可以分配到多个 Task一个 Task 也可以承载多个 Runnable这些 SWC 需要自由读写 RTE buffer。RTE 通信中OS Application 内部通信不需要 MPU 校验跨 OS Application 必须走 RTE 保护接口trusted function不允许指针直接访问。功能安全故障响应故障回收的单元是 OS Application而不是 Task。当一个 non-trusted OS Application 触发 MPU 访问保护被隔离、重启、关闭的是整个 OS Application而不是单独杀掉一个 Task。如果只 kill 出错的 Task残留的全局变量、中断上下文依旧会破坏系统。功能安全分析里论证「一个功能域独立、不扩散」的对象是 OS Application不是单个 Task。总之Task 是 Runnable 的载体不是功能打包单元自然不能作为内存保护的边界。3. 为什么软件保护不能替代硬件保护软件保护是通过代码来校验的而代码执行本身依赖内存访问——如果代码所处的内存先出了错软件保护也会跟着失效。MPU 硬件保护则是 CPU 在内存访问流水线里对读、写、取指做强制校验发生在真正访问内存之前不依赖任何软件逻辑是否完好。4. MPU 和 MMU 的区别MMUMemory Management Unit内存管理单元负责把 CPU 发出的虚拟地址转换成物理地址。通过页表、TLB 等机制实现虚拟内存。同时做权限检查读/写/执行、特权/用户、缓存属性等。支持缺页异常、按需分页、交换、内存映射文件、进程地址空间隔离。典型用于 Cortex-A、Linux、Android、Windows 等。MPUMemory Protection Unit内存保护单元不转换地址CPU 直接访问物理地址。只定义内存区域的权限哪些区域可读、可写、可执行特权/用户模式能否访问。越权访问会触发异常但不支持虚拟内存、缺页、交换。区域数量有限大小通常是 2 的幂且要对齐。典型用于 Cortex-M、RTOS、裸机、安全关键系统。第二章MPU 如何实施内存访问权限MPU 把内存划分成不同的地址区域每个区域带有相应的内存权限这样一个区域就是一个 MPU region。MPU region 包含三个要素起始地址、终止地址、内存权限。读read、写write的校验发生在访问内存总线之前执行execute的校验发生在取指时。特权模式和非特权模式在 MPU region 中有各自独立的访问权限对同一个 region可以分别规定特权模式和非特权模式的权限。region 通过 address 进行匹配匹配成功后再对权限进行校验。如果校验失败则触发 OS abort。一个 MPU region 在概念上可以抽象成这样的结构typedefstruct{uint32 startAddress;/* 起始地址含 */uint32 endAddress;/* 结束地址含 */struct{uint8 Read:1;/* 特权模式 读 */uint8 Write:1;/* 特权模式 写 */uint8 Exec:1;/* 特权模式 执行 */uint8 enable:1;/* 使能 */}permission;}MpuRegionConfig;一次访问的判定可以理解成「拿访问地址去匹配 region再用访问类型R/W/X和当前模式特权/用户去查对应权限位」图 1CPU Memory Access Permission Checking否无区域覆盖是否命中但无权限是参考权限判定依据 (region.permission)R / W / XSupervisor / UserCPU 发起访问load / store / fetch(地址 addr, 类型 R/W/X, 模式 SV/UM)地址 addr 命中某个 enable 的 region?拦下ACCESS_DENIED该 region 对当前模式 访问类型是否授权?放行ACCESS_GRANTED访问正常完成触发异常读/写 → MDP取指 → MIP进入 OS abort图中为通用地址与虚构 region仅示意判定流程不对应真实 MPU 配置。第三章越权访问被 MPU 拦下后会怎样一般 CPU 流水线的指令执行顺序是取指、解码、执行、内存访问、写回。MPU 在不同的访问环节做校验并据此区分出两类拦截MDPMemory Data Protection读写被拦和 MIPMemory Instruction Protection取指被拦。以一次非法写入为例执行 store 指令时检查访问权限检测到非法后进入 OS abort同时系统寄存器记录下对应的异常地址、异常 PC、异常类型MDP 还是 MIP之后内核把这些寄存器现场解码成 OS 标准错误码E_OS_PROTECTION_MEMORY值为 14作为入参传给 ProtectionHook。硬件锁存的异常现场可以抽象成这样一组信息示意typedefstruct{uint32 faultPc;/* 出错指令的 PC */uint32 faultAddress;/* 被拒访问的地址MDP 为数据地址 MIP 为取指地址 */uint32 faultCause;/* 异常原因MDP / MIP */uint32 accessInfo;/* 访问信息读/写、宽度、SPID 等 */uint32 coreId;/* 在哪个核上被拦下的 */}MpuFaultContext;这一条从「指令」到「ProtectionHook」的链路如下图图 2From MPU Violation to ProtectionHook否是读 / 写 (操作数访问)取指 (instruction fetch)Task 执行指令store / load / fetchCPU 访问权限检查(MPU 判定)访问被拦下?访问正常完成访问类型MDP数据保护拦截MIP取指保护拦截CPU 异常入口硬件锁存 FaultContext(faultPc / faultAddress / cause / coreId)异常处理 / OS 集成解码为 OS error codeE_OS_PROTECTION_MEMORY (14)AUTOSAR ProtectionHook(14)故障响应 (由返回值决定)TerminateTaskISR / TerminateApplRestart / Shutdown第四章AUTOSAR OS 如何处理内存保护违例MPU 属于硬件处理只关注当前的 region 和 access permission。AUTOSAR OS Protection 则定义了内存错误的处理流程和后续动作通过 ProtectionHook 接口进行。AUTOSAR OS Protection 本身不关心 MPU 的具体动作但会根据E_OS_PROTECTION_MEMORY由 ProtectionHook 的返回值决定后续PRO_TERMINATETASKISR结束出错的 Task/ISRPRO_TERMINATEAPPL结束 ApplicationPRO_TERMINATEAPPL_RESTART结束并重启 ApplicationPRO_SHUTDOWN关机下电ProtectionHook 的骨架大致是这样——它收到 OS 错误码返回一个「希望 OS 采取的动作」ProtectionReturnTypeProtectionHook(StatusType fatalError){switch(fatalError){caseE_OS_PROTECTION_MEMORY:/* 内存保护违例 *//* 保存现场 / 记录诊断信息 ... */returnPRO_TERMINATEAPPL;/* 例隔离出错的 OS Application *//* 其他保护类错误时间保护、到达率保护等 ... */default:returnPRO_SHUTDOWN;}}注意ProtectionHook 被调用并不意味着系统一定能安全地继续运行。某些执行上下文和保护错误会限制可用的恢复动作——比如这次越权访问发生在不可重入的上下文里OS 可能只接受PRO_SHUTDOWN。返回值只是「请求」最终受 OS 规范和当前上下文约束。实战设计一个基础的 MPU 验证矩阵把 MPU 的基础功能抽象成MPUEnable、MPUDisable、RegionAddress以及 Read / Write / Execute 三类权限。分成三个 region示例使用虚构地址与权限Region地址范围permissionRegion10x0000–0x00FFRead、Execute写被禁止Region20x0100–0x01FFWrite、Execute读被禁止Region30x0200–0x02FFRead、Write执行被禁止伪代码如下testfunction(){MPUEnable();/* TC01向只读/不可写的 Region1 写 —— 写被拦下 */testaddress(uint32*)0x0000;*testaddress0x12345678;// 执行后进入 Os_Abort/* TC02从不可读的 Region2 读 —— 读被拦下 */testaddress(uint32*)0x0100;readvalue*testaddress;// 执行后进入 Os_Abort/* TC03跳到不可执行的 Region3 取指 —— 取指被拦下 */executetarget(void(*)(void))0x0200;executetarget();// 执行后进入 Os_Abort}第五章一个真实案例 —— 常开保护抓到的空指针上面的验证矩阵是「主动注入」我们故意去访问禁止区看它是否被拦。但 MPU 兜底保护更大的价值是抓住那些你没预料到、系统里本来就存在的坏访问。设计一个「启动区保护」试验把地址空间最前面的一小块通常是启动代码区设成不可读写执行并让 MPU 在运行期一直开着supervisor 保护常开。本意是防止程序跑飞或野指针破坏启动区。结果一上电系统就在这块保护区报了一次数据访问违例MDP。看异常现场出错地址正好落在被保护的低地址区而出错 PC 指向某个未被配置、却仍被周期调度的通信栈模块。对照反汇编sld.w 0x0[r30], r30 ; r30 *(r30 0) —— 从配置结构读出一个指针 sld.w 0x4[r30], r30 ; r30 *(r30 4) ← 这里违例访问地址 0x4真相很清楚上一条读出的指针是NULL0下一条没判空就接着-下一级于是访问了0 0x4 0x4。这是一次经典的空指针解引用——该模块实际没配置但它的周期函数仍在被调用拿着未初始化的 NULL 配置指针往下解引用。这个 bug 的价值在于对比没有 MPU 时这次 NULL 读会悄悄读到低地址区的某个字节拿到一个垃圾值继续往下跑——静默故障可能在很久以后以莫名其妙的行为暴露极难定位。有常开 MPU 时低地址区被保护这次越权读当场被拦异常现场直接给出出错地址0x4和出错 PC那个模块的函数——一步定位到「未配置模块 空指针解引用」。这就是硬件内存保护相对软件校验的根本优势它在真正访问内存的那一刻强制拦截不依赖任何软件逻辑是否正确连「本不该跑的代码里的空指针」都能兜住。说明这类「启动区常开全禁」更适合做问题暴露/取证。真要让系统带着这类保护长期运行要么修掉触发它的缺陷如上例的空指针要么把保护粒度调整到不误伤合法访问——这正好引出下一章MPU 的能力边界。第六章MPU 保护不了什么MPU 也有它的局限性如果内存因电磁干扰等原因产生 bit 翻转MPU 无法检测——它管访问权限不管数据本身是否被物理损坏。MPU 只限制访问权限对内存数据内容不做校验需要数据完整性校验时要靠 CRC、ECC 等机制。高性能 MCU 内核可能支持乱序执行分析问题尤其复杂逻辑时要注意识别异常现场的 PC 不一定是直觉上的那条指令。MPU 不一定约束所有 DMA 和总线主设备的访问这取决于具体 SoC 的保护架构总线侧另有 Slave Guard 等机制要按具体型号识别。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑