前言
缓存一致性篇讨论了 DMA 路径上的显式维护动作,但软件对内存行为的控制还有另一个维度:属性配置。同一块物理内存,作为普通数据访问时应当缓存,作为设备寄存器访问时必须不缓存且保持顺序,作为帧缓冲时又希望写合并。这类差异不能靠缓存维护指令解决------它们需要在访问发生之前就被声明。
RISC-V 的内存属性由三层机制共同决定:平台级属性(PMA)由硬件固定,页表级属性(Svpbmt)由软件按页配置,显式维护动作(CMO)用于处理一致性域之外的数据。本文聚焦前两层,厘清其语义边界与优先级关系。
一、三层属性体系
| 层次 | 配置主体 | 粒度 | 确定时机 |
|---|---|---|---|
| PMA | 平台实现 | 物理地址区间 | 芯片设计时固定 |
| Svpbmt | 操作系统 | 页(4KB 起) | 运行时按页设置 |
| CMO | 软件显式发起 | cache block | 每次数据传递 |
三者的分工可以概括为:PMA 回答"这段物理地址是什么性质",Svpbmt 回答"这一页希望以什么方式访问",CMO 回答"此刻需要同步哪些数据"。属性是声明式的,一致性维护是动作式的------混淆两者会导致"配了属性却仍出错"或"发了维护指令却无效果"两类问题。
二、PMA 的平台级语义
PMA 描述物理地址空间各区域的固有性质,典型字段包括:
- cacheable:该区域是否可缓存
- idempotent:重复读取是否返回相同结果(设备寄存器通常不满足)
- read / write / execute:该区域允许的访问类型
- AMO / LR-SC 支持:是否允许原子操作
- misaligned 访问支持:是否允许非对齐访问
这些属性由硬件在地址译码阶段判定,软件无法修改。工程含义是明确的:任何物理地址的访问规则首先由芯片决定,软件只能在硬件允许的范围内做选择。例如设备寄存器区域在 PMA 中通常标记为非幂等且不可缓存,任何试图将其映射为普通可缓存内存的做法都不会生效,且可能触发访问异常。
设备树中的 riscv,pma-* 类描述与固件的内存区域声明,是软件获知这些边界的可读来源。开发板 bring-up 阶段核对硬件手册的地址映射表,是不依赖软件描述的唯一可靠手段。
三、Svpbmt 的页表级控制
3.1 页表项的 PBMT 字段
Svpbmt 扩展在页表项中定义了 PBMT 字段,取值语义如下:
| 取值 | 名称 | 语义 |
|---|---|---|
| 0 | PMA | 按硬件固有属性访问(默认) |
| 1 | NC | 非缓存、幂等访问 |
| 2 | IO | 非缓存、强顺序访问 |
| 3 | 保留 | 不可用 |
非叶节点页表项同样可携带该字段,语义为该子树下所有映射的默认属性。这一设计让驱动可以为整段设备地址空间一次性设置属性,而不必逐页处理。
NC 与 IO 的差别在于顺序性:NC 允许弱内存序(适合帧缓冲、写合并区域),IO 保证访问按程序顺序完成(适合设备寄存器)。选择依据是目标区域是否要求严格的访问顺序。
3.2 与 PMA 的优先级关系
两者冲突时,规范的方向是明确的:PBMT 只能在硬件允许的方向上收紧,不能放宽。具体而言:
- PMA 标记为非缓存的区域,PBMT 无法将其变为可缓存
- PMA 标记为不幂等的区域,PBMT 无法将其变为幂等
- PMA 标记为可缓存的区域,PBMT 可将其降级为 NC 或 IO
这条规则来自安全与正确性的双重考虑:若允许软件将设备区域声明为可缓存,硬件可能因缓存行预取读到无效值,且写合并会破坏寄存器写入的语义。
一条容易被忽略的细节是 PBMT 与 CMO 的关系:缓存块操作指令不受 PMA 可缓存属性与 PBMT 降级的约束,仍会作用于对应的 cache block。因此不能通过将页面标记为 NC 来规避缓存维护 ------该发的 cbo 指令一条都不能省。
四、驱动的实际用法
4.1 设备寄存器映射
驱动通过 ioremap 系列接口建立设备映射,内核据此设置 IO 或 NC 属性:
c
ioremap 与 ioremap_wc 的差别正是 PBMT 取值差异的体现。在此基础上,访问接口的选择同样重要:readl/writel 已经隐含正确的屏障语义,而直接解引用映射指针并配合普通内存屏障,容易遗漏顺序要求。
4.2 DMA 缓冲与属性
DMA 缓冲的属性要求与非一致域维护是两个独立问题:
| 场景 | 属性要求 | 是否需 CMO |
|---|---|---|
| 设备位于一致性域内 | 按普通可缓存内存映射 | 不需要 |
| 设备位于一致性域外 | 普通映射 + 显式维护 | 需要 |
| 非一致设备 + 页面标为 NC | 需权衡 | 仍需要(CMO 不受 PBMT 约束) |
最后一行是常见误区:把缓冲页标记为 NC 后,CPU 侧的缓存不再持有副本,但设备侧的一致性维护仍不能省------两个方向的同步责任分别落在不同主体上。
4.3 执行权限与内存属性
代码段通常要求可缓存以获得取指性能,非缓存映射会显著降低取指效率。若因调试或安全需求必须使用非缓存执行映射,应局限在必要的页范围内,避免整段代码空间受影响。
五、平台适配与验证
5.1 能力探测与工具链
Svpbmt 扩展自 RVA22 起进入强制列表,平台实现状态可通过 ISA 字符串与运行时探测接口确认。工具链侧需要支持在内核页表宏中选择 PBMT 属性------这部分由内核完成,驱动与应用不直接接触。
真机适配前,处理器的属性支持范围与 SDK 内存属性相关说明可在玄铁资源中心核对,以平台的最新发布文档为准。
5.2 QEMU 的验证边界
QEMU 对 Svpbmt 提供基本支持,可验证的部分与不可验证的部分需要区分:
| 验证对象 | QEMU 是否可验 | 说明 |
|---|---|---|
| 页表项 PBMT 字段写入 | 可 | 映射建立与属性设置路径 |
| 非法属性组合的异常 | 部分 | 依赖具体实现判定 |
| 非缓存访问的实际延迟差异 | 不可 | 无缓存层次建模 |
| 写合并的效果 | 不可 | 无总线层建模 |
| 属性配置错误导致的静默数据错误 | 不可 | 数据语义未被建模 |
最后一行是这类配置问题的核心风险:属性配错在仿真环境中不产生任何可观测后果,只在真机特定访问模式下暴露为数据错误或性能退化。
六、高频问题排查
| 现象 | 排查方向 |
|---|---|
| 设备寄存器读取返回固定值 | 映射属性误用为可缓存,检查 ioremap 使用 |
| 写入设备寄存器偶发丢失 | 使用了 NC 而非 IO 属性,顺序得不到保证 |
| 标记为 NC 后 DMA 仍出错 | 误以为可省略 CMO,检查一致性域归属 |
| 页表项属性不生效 | 与 PMA 冲突:只能在允许方向收紧 |
| 非叶节点属性未覆盖子页 | 子树默认属性被更低层级页表项覆盖 |
结语
内存属性配置把"访问方式"从运行时的动作式维护提前到映射建立时的声明式描述,其工程价值在于把设备访问的正确要求固化进地址映射。三层体系的分工是清晰的:PMA 给出硬件边界,Svpbmt 在边界内做选择,CMO 处理跨域数据同步。
对开发者而言,实际判断可以概括为:属性配置的第一原则是服从 PMA,第二原则是区分 NC 与 IO 的顺序语义,第三原则是不把属性配置当作一致性维护的替代。后续可展开的议题包括非叶节点属性的完整继承规则,以及异构集成场景下不同内存域的属性统一策略。