1. MPU 相关基础

内存保护单元(MPU)是 Cortex-R52 中用于管理内存访问权限和属性的硬件模块。它通过划分内存区域来工作,每个区域最小为 64 字节,并且起始地址必须对齐到其大小的整数倍(例如,一个 64 字节的区域必须从一个能被 64 整除的地址开始)。对齐要求就像整理书架时规定每本书必须从固定的格子开始摆放,这样系统才能快速、准确地找到和管理这些内存区域,否则可能导致硬件错误或性能下降。


1.1. 4.1. R52 内存模型功能支持

Cortex-R52 的内存模型有若干关键特性,这些特性深刻影响着系统设计和编程:

  1. 共享性与缓存的强制规则:为了在无硬件缓存一致性的多核系统中保证数据安全,任何被标记为 Inner Shareable(集群内共享)或 Outer Shareable(集群间共享)的内存区域,其数据访问都会强制绕过缓存,变为不可缓存(Non-cacheable)。这就像在团队协作中,所有需要共享给团队成员的文件都必须放在公共公告板上,而不是个人的抽屉里,确保每个人看到的都是最新版本,避免了数据不一致的风险。

  2. 不支持快速上下文切换(FCSE):Cortex-R52 作为实时处理器,优先考虑确定性和简单性,因此不支持 FCSE 这一用于加速任务切换的功能。这意味着任务切换的延迟可能稍高,但系统行为更可预测。

  3. 辅助寄存器支持:Cortex-R52 提供了一组用于深度调试和系统控制的辅助寄存器,它们是系统工程师的“诊断工具”。

    • Auxiliary Fault Status Registers (AIFSR 和 ADFSR):当处理器遇到指令获取错误(AIFSR)或数据访问错误(ADFSR)时,这些寄存器会记录详细的错误原因。例如,当 DMA 控制器试图访问一个未配置权限的内存区域而触发总线错误时,工程师可以通过读取 ADFSR 来定位问题根源。
    • Auxiliary Control Register (ACTLR):这是一个权限寄存器(通常在 EL1 或 EL3 级别才能访问),用于微架构行为控制,例如调整缓存策略、预取器行为或多核交互。一个典型应用是禁用特定核心的 L2 缓存预取功能,以在特定工作负载下降低功耗。
  4. 受限的 PMSA 架构:Cortex-R52 采用受保护的存储器系统架构(PMSA),它不支持虚拟内存(这与 MMU 的 VMSA 不同),而是通过 MPU 实现物理内存的保护,架构更简单,非常适合实时嵌入式系统。

  5. 支持 TCM 及相关 DMA:TCM 是一种紧耦合内存,具有低延迟、高带宽的特性,常用于存储关键代码和数据。Cortex-R52 支持 TCM 并且能够与 DMA 控制器高效协作,例如,DMA 可以将传感器数据直接写入 TCM,然后 CPU 核心能够极速处理这些数据。

  6. 两级共享等级:共享性分为两个层级,Inner Shareable 通常指在一个处理器集群内部(例如,同一芯片上的多个 R52 核心)之间的共享;Outer Shareable 范围更广,指在不同集群之间(例如,系统中多个芯片)的共享。在 R52 中,无论哪个级别的共享,都会触发上述的不可缓存强制规则。


1.2. 4.2. MPU 寄存器详解

MPU 的功能通过一系列寄存器进行配置,理解它们是进行内存保护编程的关键。

  • MPU 的启用与背景区域:MPU 的全局开关由系统控制寄存器(SCTLR)的 M 位控制。当 SCTLR.M=0,MPU 被禁用,此时系统会使用 EL1 控制的 MPU 背景区域作为默认内存映射,这相当于一个“安全网”,定义了未受 MPU 明确管理的内存区域的属性。当 MPU 启用(SCTLR.M=1) 后,还可以通过设置 SCTLR.BR 位来单独启用或禁用这个背景区域。

  • MPU 区域数量:系统支持的 MPU 区域数量(即可配置的内存保护区块数)是一个硬件特性,可以从 MPU Type 寄存器中读取。

  • EL2 Hypervisor 支持:对于支持虚拟化的场景,EL2 级别的 MPU 是可选的。如果实现,其相关配置寄存器为 HPRBAR(Hypervisor Physical Region Base Address Register)和 HPRLAR(Hypervisor Physical Region Limit Address Register)。在 Hypervisor 模式下,一次内存访问会同时检查 EL1 和 EL2 的 MPU 区域设置,两者共同决定最终的访问权限和内存属性。

  • 区域配置寄存器(以 EL1 为例):每个 MPU 区域通过一对寄存器定义:

    • PRBAR(区域基址寄存器):
      • SH 字段:控制内存区域的共享性(Shareable)。对于普通内存,一旦设置为共享,该区域即被强制为不可缓存。
      • AP 字段:控制访问权限(Access Permission),定义在 EL1(操作系统)和 EL0(应用程序)特权等级下是否可读、可写。
      • XN 字段:控制是否可执行(eXecute Never)。设置为 1 可防止在该区域执行代码,有效抵御某些代码注入攻击。
    • PRLAR(区域限界寄存器):
      • AttrIndx 字段:这是一个索引值,用于选择 MAIR(Memory Attribute Indirection Register) 寄存器中的属性配置。MAIR 寄存器可以看作一个“属性模板库”,提供了 8 个(attr0 到 attr7)可编程的内存属性槽。
      • EN 位:区域启用位。只有设为 1,该 MPU 区域的配置才生效。

1.3. 4.3. 内存属性深度解析

内存属性决定了处理器访问内存时的微观行为,如缓存策略、排序要求等。Cortex-R52 在此有特殊规定。

2. 4.3.1. Cortex-R52+ 内存属性核心行为要点

  1. 数据缓存策略强制为 Write-Through(直写):这是 R52 的一个关键特性。无论软件在属性中配置为 Write-Back(回写)还是其他,实际的内存访问行为都是 Write-Through。这意味着数据写入时会同时更新缓存和主内存,保证了数据的实时一致性,简化了多核数据共享的处理,但可能比 Write-Back 模式性能稍低。
  2. Shareable 属性强制为 Non-cacheable:如前所述,标记为 Inner 或 Outer Shareable 的内存区域会被强制当作 Non-cacheable 处理,所有访问直接到达内存,这是保证多核数据一致性的核心机制。
  3. Transient 提示被忽略:Transient 属性用于提示某次访问是临时的、可能不会重用,但 Cortex-R52 忽略所有 Transient 提示,统一按 Non-transient 处理。
  4. 非一致性架构:Cortex-R52 的各个核心的缓存之间没有硬件自动维护一致性,因此对共享数据的软件管理要求更高。

3. 4.3.2. 属性编码与实际行为

内存属性编码分为外层(Outer)和内层(Inner)属性,但对于 Cortex-R52 的实时应用场景,许多配置的实际行为被简化或强制改变。

3.1. Device 内存类型(用于访问外设寄存器)

当外层属性编码为 0000 时,内存类型为 Device。其内层编码决定了访问设备的严格程度,这对于外设的正确操作至关重要。

内层编码Device 类型严格程度实际行为(对寄存器的操作)典型使用场景
0b0000nGnRnE最严格无合并、无重排序、无提前写确认中断控制器、系统关键控制寄存器
0b0100nGnRE较严格无合并、无重排序、有提前写确认UART、SPI、定时器等普通外设
0b1000nGRE较宽松无合并、有重排序、有提前写确认帧缓冲区、DMA 描述符表
0b1100GRE最宽松有合并、有重排序、有提前写确认大块内存映射 IO 区域
  • 名词解释:
    • 聚集(Gathering):将多个小访问合并成一次大访问。
    • 重排序(Reordering):改变内存访问的先后顺序。
    • 提前写确认(Early-acknowledge):在写入操作实际完成前就通知处理器完成。

3.2. Normal 内存类型(用于普通数据内存)

当外层属性编码不为 0000 时,内存类型为 Normal。下表展示了配置值与 Cortex-R52 实际行为的差异。

外层/内层属性编码与实际行为对照

配置的编码软件配置的类型Cortex-R52+ 实际行为说明
0b00RW (RW≠00)Write-Through Transient实际为 Write-Through,Transient 被忽略
0b0100Non-CacheableNon-Cacheable
0b01RW (RW≠00)Write-Back Transient实际为 Write-Through,Transient 被忽略Write-Back 配置被强制转换
0b10RWWrite-Through Non-transientWrite-Through Non-transient
0b11RWWrite-Back Non-transient实际为 Write-Through Non-transientWrite-Back 配置被强制转换

R/W 分配策略编码 此策略控制当缓存未命中时,是否为读(R)或写(W)操作分配缓存行。

R/W 值含义实际效果
R=0, W=0读写都不分配直接访问内存,不占用缓存空间
R=0, W=1读不分配,写分配仅当写入数据且不在缓存时,才将其载入缓存
R=1, W=0读分配,写不分配仅当读取数据且不在缓存时,才将其载入缓存
R=1, W=1读写都分配只要访问的数据不在缓存,就将其载入缓存

4. 4.3.3. 配置指南与决策流程

4.1. 推荐配置场景

  1. 私有数据(单核心访问):

    • 配置:Non-Shareable + Write-Through + 合适的 R/W 分配。
    • 场景:核心内部的局部变量、临时计算数据。
    • 策略建议:频繁读写的小数据用 R=1, W=1;读多写少的数据用 R=1, W=0。
  2. 共享数据(多核心/DMA 访问):

    • 配置:Shareable(自动变为 Non-cacheable)。
    • 场景:核心间通信缓冲区、DMA 数据区。
    • 说明:这是最简单且安全地保证数据一致性的方法。
  3. 设备寄存器:

    • 配置:Device 内存类型(根据外设要求选择 nGnRnE, nGnRE 等)。
    • 场景:外设控制/状态寄存器。
    • 原则:对顺序敏感的关键寄存器用 nGnRnE;对顺序要求不高的普通外设可用 nGnRE。
  4. 代码段:

    • 配置:Non-Shareable + Write-Through + R=1, W=0。
    • 场景:程序代码、常量数据。
    • 说明:利用缓存加速指令读取(R=1),由于代码通常不写入,故 W=0。
  5. 流式数据处理:

    • 配置:Non-Shareable + Write-Through + R=0, W=0。
    • 场景:处理大型数据块、一次性 DMA 传输缓冲区。
    • 说明:避免被只使用一次的数据“污染”缓存,提升缓存效率。

4.2. 配置决策流程

初学者可以遵循以下步骤来配置内存属性:

  1. 是否需要共享? 如果该内存区域会被多个核心或 DMA 访问 → 标记为 Shareable(它将自动变为 Non-cacheable,一致性得到保证)。如果否 → 进入下一步。
  2. 是否是设备内存? 如果该区域是映射的外设寄存器 → 选择合适严格程度的 Device 类型。如果否 → 配置为 Normal 内存。
  3. 选择分配策略:根据对该 Normal 内存区域的访问模式(读多还是写多)来选择合适的 R/W 位。请记住:Transient 属性可忽略,且任何 Write-Back 配置都无效。

5. 4.3.4. nGnRnE 深度解读

nGnRnE 是 ARM 架构中用于描述设备内存行为的最严格类型,其名称中的每个字母都代表一个限制:

  • nG (No Gathering):不允许事务合并。多个对同一设备的访问不能合并为一次更大的传输。
  • nR (No Reordering):不允许事务重排序。对该设备的访问必须严格按照程序代码的顺序执行。
  • nE (No Early-acknowledge):不允许提前确认。写操作必须在该操作确实在设备端完成之后,才能向处理器发送“完成”信号。

应用场景:nGnRnE 用于访问那些对操作顺序极其敏感的设备寄存器,例如中断控制器和系统关键控制寄存器。确保一个“开启”指令绝对在“配置”指令之后执行,是系统稳定性的基石。在 ARMv7 架构中,它对应于 Strongly Ordered 内存类型。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐