RISC-V Svpbmt扩展详解:PMA、PBMT与缓存访问控制

发布时间:2026/10/4 14:58:14
RISC-V Svpbmt扩展详解:PMA、PBMT与缓存访问控制 做RISC-V相关底层的人迟早会遇到这么一个问题同样是一条普普通通的load指令凭什么有的访问稳稳命中缓存有的却一路捅到总线上延迟差出好几个数量级答案就藏在“内存属性”这四个字里。今天这篇笔记围绕RISC-V的Svpbmt扩展把PMA、PBMT编码、非缓存访问的完整硬件路径一次讲透顺便给出一套可以在自己SoC里落地的验证思路。文章适合正在做RISC-V CPU设计、SoC集成或者BSP开发的工程师也适合想搞懂MMU和缓存如何协作的同学。我尽量用工程化的语言少绕弯子。我最早接触这套机制是在调一个带设备寄存器映射的FPGA平台当时莫名奇妙所有MMIO访问都跑进缓存里折腾了一周才发现是PMA和页表属性没配对。所以这篇笔记不仅讲规范更会把我踩过的坑和验证方法都写出来。1. PMA物理地址上的“出厂铭牌”想要理解Svpbmt必须先明白PMA是什么。PMA的全称是Physical Memory Attributes直译过来就是物理内存属性。它描述的是物理地址空间中的某一段区域硬件允许怎么访问、不允许怎么访问。这个“出厂铭牌”在SoC设计阶段就被定死了软件在正常运行时几乎改不了。1.1 一个访问能不能缓存PMA说了算大多数人以为“能不能缓存”只和页表项里的某个标志位有关但实际上在RISC-V体系里最底层约束来自PMA。PMA明确声明某一段物理地址是否允许被缓存、是否支持原子操作、访问是否幂等。举一个具体例子你有一片DDR物理地址从0x8000_0000开始平台把它标记为cacheable且支持AMO而UART寄存器所在的0x4000_0000区域PMA则标记为non-cacheable、non-idempotent。这两个区域即使你都在页表里做了完全相同的映射硬件执行起来的行为也完全不同。这部分规则不属于某个可选的指令集扩展而是RISC-V架构的基础约定。PMA甚至在MMU关闭、直接在M模式下物理地址访问时依然生效。也就是说就算你根本没开分页PMA也会影响总线上发生的实际事务。很多做裸机开发的人没意识到这一点一旦访问某个不存在的PMA区域总线直接返回错误系统表现千奇百怪。1.2 PMA只认物理地址不关心你从哪个虚拟地址来PMA的判定完全基于物理地址和虚拟地址、页表映射方式没有任何关系。CPU最终发出的访问请求落到哪一个物理地址段就套用那一段的PMA规则。这意味着同一块物理内存如果被两个不同虚拟地址分别映射两个映射属性再怎么设最终都逃不过PMA的边界。有个容易混淆的点Svpbmt中的PBMT字段存在页表项里看起来像是“虚拟地址层的属性”但它的作用对象仍然是翻译后的物理访问。硬件在拿到物理地址后会查PMA表再结合PTE上的PBMT合成出一个“最终有效内存属性”。所以严谨地说PBMT不是在覆盖PMA而是在PMA允许的范围内做“微调”。1.3 一张表看清PMA的主要属性PMA包含的属性不只缓存一项为了后面讲PBMT方便我先列出最常见的几个属性含义典型取值区域类型这段地址是主内存还是IO空间Memory / IO缓存能力是否允许访问被缓存行缓冲Cacheable / Non-cacheable幂等性重复访问是否产生副作用Idempotent / Non-idempotent原子性是否支持AMO指令AMO支持 / AMO不支持读/写/执行是否允许相应类型的访问R/W/X支持位在CPU设计里PMA的实现通常是一张地址解码表硬件根据物理地址高位命中某个条目得到这一段的属性。有的SoC会把这套表固化成寄存器软件可以查也有的直接硬连线在总线互连里软件只能通过行为推断。从规范角度说PMA并不是一个标准CSR怎么暴露可以自定义所以别指望有一套统一接口。2. Svpbmt页表项里长出来的内存属性开关PMA虽然基础但粒度太粗而且完全由硬件平台静态决定。操作系统往往需要在同一块物理内存上按页切换访问属性比如把一段普通内存映射成非缓存给DMA使用。这就引出了Svpbmt这个可选特权架构扩展。Svpbmt的全称是Supervisor-mode-based Page-Based Memory Types说人话就是允许我们在页表项里直接携带内存类型信息让虚拟页级别的内存属性可编程。2.1 PBMT字段的编码规则Svpbmt在64位PTE中拆出了两位用于存放PBMTPage-Based Memory Type。这两位在PTE的bit 62和bit 61。规范里定义了四种编码其中三种有实际含义一种保留PBMT[1:0]名称含义00None内存类型完全由PMA决定这是默认状态01NCNon-cacheable, Non-idempotent10IONon-cacheable, Non-idempotent, Non-coherent11保留软件不要使用硬件应忽略补充个前提PBMT字段在64位PTE里RV32的Sv32页表只有32位没有位置放这两位所以Svpbmt通常配合RV64的Sv39、Sv48、Sv57一起用。设计RISC-V CPU核时如果只做RV32那么这个扩展天然不可用RTL里可以不实现。2.2 为什么有了PMA还不够需要PBMTPMA是一个物理地址段级别的静态属性集合粒度大且平台固定。可实际工程里软件经常要在一个PMA为“支持缓存”的区域里单独把某一页切成非缓存使用。比如DMA场景CPU和DMA共享一个缓冲区如果CPU侧写缓存DMA直接读内存就会读到陈旧数据。传统方案是操作完手动clean/invalidate cache但这样既麻烦又容易漏。Svpbmt提供的是更干净的思路把那块缓冲区的PTE直接设成NC访问绕过缓存CPU和DMA看到的永远是最新值省掉一堆同步操作。把PMA和PBMT放一起看一个管物理地址的静态边界一个管虚拟页的动态调控两者配合才能既保证硬件安全边界又给软件灵活度。维度PMAPBMT定义层次SoC硬件平台页表项软件可写作用粒度物理地址区间单个虚拟页动态性静态固定可随页表切换覆盖内容全部内存属性仅内存类型相关部分约束关系基础边界只能在边界内做选择2.3 Svpbmt的铁律PBMT不能突破PMA这块必须单独讲因为很多人在这栽跟头。Svpbmt确实允许PBMT覆盖PMA的某些属性但有一个前提PMA本身允许这种覆盖。规范把PMA中的内存属性分成“强制属性”和“可选属性”。强制属性意味着无论页表里写什么都必须遵守比如PMA声明这段地址是non-idempotentPBMT再怎么写也改变不了。可选属性则是平台允许软件调整的部分PBMT才有发挥空间。打个比方PMA是交规某个路段标了“限速60但允许驾驶者根据情况调整为40”你可以把速度降到40设置NC但不能在没有应急车道的地方停靠改成缓存。更实际一点的做法一个物理区域PMA写“支持缓存也支持非缓存”这时PBMT设置None就按缓存走设置NC就按非缓存走如果PMA只写了“支持非缓存”那么PBMT设置None最终仍然是非缓存因为PMA的强制属性兜底。还有一个必须记住的规范细节如果PTE的全局映射位G为1硬件必须忽略PBMT字段相当于强制当作None处理。原因很直白全局映射可能被多个不同的虚拟地址共享如果每个虚拟地址还能带不同内存类型TLB里就说不清了属性必须统一。3. 三种内存类型实战辨析None、NC、IO现在进入实操层面。我猜很多人看完第二章已经知道编码了但不太清楚什么时候该用哪个。这一章我把三种类型拆开讲每个都附上实际使用场景。3.1 None最省心的默认值操作系统里的绝大多数普通内存页PTE的PBMT都是00也就是None。它表示我不在这里发表意见一切听PMA的安排。系统刚启动、页表还没建立里CPU访问的也是None状态所以启动阶段跑在DDR里行为和直接物理访问一致。对CPU设计者来说None是最容易处理的因为你的内存子系统只需要根据PMA判断即可不需要额外解析PTE属性。这里有一个很实用的建议整个系统里尽量让绝大多数页保持None只在有明确需求的地方开启NC或IO。过度使用非缓存会让整体性能很难看还容易掩盖设计上的缓存热路径问题。3.2 NC给DMA缓冲区准备的“非缓存直通”NC是Non-cacheable、Non-idempotent。先解释Non-idempotent它的意思是这个访问不能随便重试、合并或重复执行因为重复访问可能会产生不同的效果。对于普通内存读写本质是幂等的读一百次都是一个值但设备寄存器的读可能清除中断标志位写可能触发数据传输这种就是非幂等。NC最常见的用途是DMA描述符和DMA数据缓冲区。当CPU和DMA需要共享数据而你又不想处理cache的clean/invalidate直接把缓冲区PTE设为NC是最高效的办法。CPU写NC缓冲区时数据不落缓存直接发到内存总线DMA读到的就是最新值。反过来DMA写完数据CPU读NC缓冲区也不需要担心缓存里有旧数据。需要留神的是NC存储访问对顺序和合并的限制比普通缓存访问严格但它并不要求所有访问严格按程序顺序执行。工程上NC适合数据一致性敏感但不必强排序的外设内存比如网卡DMA环形缓冲区。3.3 IO设备寄存器访问的标准答案IO类型在NC基础上又加了一个Non-coherent属性而且实际总线行为上通常会被翻译成更强的顺序约束和设备类型事务。它面向的是MMIO寄存器这类真正有副作用的访问。所谓“副作用”典型代表是读UART状态寄存器会清掉接收中断标志写FIFO会触发数据发送这类访问必须严格按程序意图执行不能预取、不能合并、不能缓存。IO类型能阻止处理器把所有访问合并成一笔宽事务也阻止读写重排发生。用透明一点的话说你写多少次IO总线上就出现多少笔独立的事务每一笔都“问一答一”。这在调试设备驱动时特别重要否则一个写操作被合并掉硬件行为整个错乱。在Linux上ioremap出来的地址通常就是按IO语义处理的RISC-V平台上如果硬件没有实现Svpbmt内核只能靠PMA或者fence指令来兜底性能和确定性都差一截。所以Svpbmt对跑Linux的RISC-V设备真的很重要。3.4 选型决策的小抄给你一张快速决策表是我实际项目里一直用的使用场景推荐PBMT原因普通RAM页、代码段、堆栈None交给PMA性能最好DMA收发缓冲区、描述符NCCPU和DMA数据一致无需flushMMIO寄存器、配置空间IO严格非缓存、非合并、非预取早期启动、固件镜像NonePMA足够兜底避免额外配置这个表可以当作默认参考遇到特殊情况再做调整。4. 非缓存访问的完整硬件路径前面把两个概念讲清楚了现在从CPU发出一条load/store指令开始到总线端出现一笔事务完整走一遍非缓存访问的路径。这部分是对CPU设计者最有价值的章节也是很多入门资料避而不谈的细节。4.1 从TLB拿到物理地址的那一刻开始假设CPU执行一条ld a0, 0(x1)。虚拟地址送到MMUTLB命中后得到两个关键信息物理地址和PTE里的内存属性位包括PBMT。如果TLB miss则需要走页表Walk从内存里读回PTE把PBMT位存进TLB条目。值得注意的是页表Walk本身也会经过缓存所以“属性读错了”这种问题真的会在古老设计里出现后面排查部分细说。TLB输出给load/store单元的信息里必须包含一个pbmt信号。这条信号会跟着访问请求一起穿过load/store队列最终进入缓存子系统。很多初学者设计CPU时忽略这一步认为只要页表翻译完成就万事大吉结果后面想支持NC访问就发现属性信息断了必须回头改流水线接口。4.2 缓存子系统如何合并PMA与PBMT访问请求到达缓存子系统时同时带着物理地址和pbmt。缓存控制器要做两件事第一根据物理地址查PMA表得到该区域的强制属性第二把PMA和PBMT合并得出本次访问的“最终有效属性”。为方便理解我给出一个简化的SystemVerilog伪代码。typedef enum logic [1:0] { PBMT_NONE 2b00, PBMT_NC 2b01, PBMT_IO 2b10 } pbmt_t; logic cacheable; logic order_strict; always_comb begin case (pbmt) PBMT_NC: begin cacheable 1b0; order_strict 1b0; end PBMT_IO: begin cacheable 1b0; order_strict 1b1; end default: begin // PBMT_NONE cacheable pma.cacheable; order_strict pma.idempotent ? 1b0 : 1b1; end endcase // 强制属性兜底如果PMA不允许缓存无论如何都不能缓存 if (!pma.cacheable) cacheable 1b0; end实际设计里要考虑的细节更多比如PMA不支持当前PBMT请求类型时的回退策略规范允许平台自定义常见做法是忽略PBMT按None处理。但伪代码至少展示了核心逻辑cacheable信号决定本次访问是否参与缓存查询order_strict信号则决定后续总线事务的访问顺序约束。一旦判定为非缓存访问数据缓存和指令缓存都会被跳过。这里说的“跳过”是逻辑上的旁路bypass不代表整块缓存被禁用只是这笔事务不进去、不查询、不分配。4.3 在AXI总线上非缓存事务长什么样缓存命中的访问通常不会立刻产生总线事务只有缓存未命中才会触发内存填充而且填充是以整个cache line为粒度比如64字节作为一笔burst。非缓存访问则完全不同它不查缓存直接为当前这笔load/store生成一笔总线事务事务宽度基本等于访问宽度。以AXI为例cacheable的linefill事务通常是一个较长的burst例如8拍16字节或4拍32字节而NC/IO的单次访问往往只有1拍。ARCACHE等缓存属性信号也会被置为non-cacheable相关编码总线互连和下游设备能一眼认出这是一笔“不需要缓存参与”的事务。很多外设控制器看到这种事务类型就知道不能做预取或合并必须老老实实搬运数据。从总线上区分缓存和非缓存访问最直观的办法是看链路层的burst长度和cache属性信号。调试时抓波形一个正常的非缓存写应该是AWVALID打一拍WVALID打一拍BVALID回应一拍干净利落。如果看到AW上面挂着十几拍的burst那一定还是走了缓存路径。4.4 一致性视角NC访问为何干净利落NC访问不产生缓存行因此不会留下一个“等待写回”的脏行。CPU写NC缓冲区数据流经写缓冲或直接跨过写缓冲进入总线DMA读内存时拿到的就是刚写的值。反过来DMA写内存CPU读NC缓冲区也直接绕过缓存去内存拿天然看不到旧数据。但这里藏着一个重要警告同一块物理内存不允许既被映射成cacheable又被映射成NC。否则CPU把数据写进了某条cache lineDMA却通过NC路径读内存读到的是老数据逻辑混乱。硬件层面不会帮你拦这种别名错误软件必须自觉。Svpbmt规范里G位忽略PBMT的设计正是为了避免全局映射造成的属性混乱但它解决不了两个不同虚拟页映射同一物理页却带不同属性带来的自找麻烦。5. 实操案例在自己的SoC上把Svpbmt跑起来理论说完了来点能直接抄作业的内容。假设我们在设计一个带Svpbmt支持的简单RISC-V SoC包含CPU核、DDR控制器、UART和DMA。接下来我从RTL、平台PMA配置、软件设置到验证手段完整走一遍。5.1 RTL侧从PTE到TLB到请求的属性传递首先在MMU的页表Walk模块里从PTE[62:61]提取pbmt写入TLB条目。这里要特别注意TLB是流水线里非常关键的一环pbmt必须和物理地址一起锁存不能丢。我建议在TLB数据结构里增加一个2bit字段和PPN、权限位一并存储。第二步TLB输出到load/store单元的总线接口上增加pbmt信号。需要设计成访问请求属性的一部分。这一步往往还要考虑异常处理和写缓冲的顺序约束IO类型访问在某些微架构里会要求强顺序所以这条信号也得陪伴它走完整个访存流水线。第三步缓存控制器入口处接PMA查表模块。推荐的做法是PMA查询和标签比较并行做因为cacheable判断最好在标签比较前就定下来否则等比较完才发现该旁路时序上会多一拍加大访问延迟。// 简化版接口信号 output logic [1:0] req_pbmt; output logic req_nc; // 非缓存请求 output logic req_io; // IO类型请求5.2 平台侧PMA表该怎么定PMA表的设计其实是最容易忽略的部分。常见做法是地址解码器加属性寄存器。拿我的参考平台举例物理地址空间划分如下地址范围用途缓存能力幂等性AMO0x0000_0000 - 0x1FFF_FFFFDDRCacheableIdempotent支持0x2000_0000 - 0x2000_FFFFSRAMCacheableIdempotent支持0x4000_0000 - 0x4000_FFFFMMIONon-cacheableNon-idempotent不支持0x6000_0000 - 0x6000_0FFFDMA控制寄存器Non-cacheableNon-idempotent不支持这里我把DDR和SRAM都标记为同时支持缓存和非缓存这样软件的PBMT才能真正“二选一”。如果PMA只标支持缓存不支持非缓存那你后面设置NC是无效的硬件大概率会忽略PBMT访问照旧走缓存。5.3 软件侧写一个带PBMT的页表项在裸机环境下假设我们要把虚拟地址0x1000映射到物理地址0x80000000并设置成NC。步骤如下#define PBMT_SHIFT 61 #define PBMT_NC (0b01UL PBMT_SHIFT) uint64_t *pte (uint64_t *)get_pte_address(); uint64_t ppn 0x80000000 12; uint64_t new_pte (ppn 10) | PBMT_NC | PTE_V | PTE_R | PTE_W; *pte new_pte; // 刷新TLB确保PTE更新生效 asm volatile(sfence.vma ::: memory);这里面有三个细节必须强调第一PTE必须设置V否则访问触发异常第二PBMT设置之前确认这个页的G位是0否则硬件忽略PBMT第三更新完页表之后必须执行sfence.vma不光是刷新常规TLB页表Walk缓存也需要同步刷新否则下次访问可能还在用旧PTE里的属性。如果你在Linux里面做需要开启CONFIG_RISCV_ISA_SVPBMT内核会在映射设备内存和DMA缓冲区时自动生成合适的PBMT不用手写。5.4 验证手段肉眼可见的缓存绕过验证Svpbmt是否真的生效有几个很实用的实验方法。第一个延迟测量。写一个循环对一个NC缓冲区反复读和另一个普通Cacheable缓冲区反复读比较平均延迟。如果NC路径生效NC读的延迟一般显著高于L1命中延迟接近内存总线延迟。注意要排除编译器优化用内联汇编或者让地址外部化。第二个AXI波形观察。用逻辑分析仪抓总线对比两类访问事务形态普通缓存未命中会引发一笔长的line-fill burstNC访问则是短丛发甚至单拍。看到单拍事务基本可以确认缓存被旁路了。第三个DMA一致性测试。这个最贴近真实使用场景CPU往NC缓冲区写一串数据直接启动DMA把数据搬到另一块内存再把搬完的结果读回来比对。如果Svpbmt生效整个过程完全不需要cache flush而且数据正确。如果NC设置无效DMA很可能读到旧数据这时你就要回头查看G位、PMA表和TLB刷新流程。6. 常见问题与排查技巧实录Svpbmt这种底层机制调试起来特别容易一头雾水。下面几个问题是我自己和团队在实际项目中都遇到过的整理成速查表按“现象 - 可能原因 - 检查动作”的顺序写。6.1 设置了NC却还在缓存里命中这是最经典的问题。第一检查PTE的G位如果这一位是1硬件无条件忽略PBMT你写再多NC也白搭。第二检查TLB和页表Walk缓存更新PTE后没有执行sfence.vma老属性被缓存下来新访问参考的还是旧PTE。第三检查PMA表如果PMA根本没允许这个区域使用非缓存硬件按平台自定义策略可能直接丢弃PBMT实际按None执行。还有一个容易被忽略的点PBMT字段位置是bit 62和bit 61有些人的软件代码里习惯用PTE的bit 60或者bit 63一不留神就写错位了。最好先打印一下PTE原始值确认高两位真的像预期那样变化了。6.2 PBMT和PMA打架时谁说了算规范在PBMT请求类型与PMA冲突时没有强制规定硬件行为由平台自选可以忽略PBMT按PMA执行也可以保留PBMT无视PMA的某些强制属性甚至某些实现会返回异常。绝大多数SoC选择最省事的“忽略PBMT”。这意味着你设置NC但PMA只允许缓存最终行为仍然是缓存访问而且没有任何异常和提示。设计CPU的时候我建议在RTL里显式实现“PMA不支持则回退None”的逻辑并留一个可读的调试寄存器记录被忽略的PBMT请求。这样软件出问题时能立刻从硬件侧看到“我曾经试图设NC但被丢掉”。这种可观测性在开发阶段价值极高。6.3 别忘了指令侧和TLB刷新你很可能把数据页的NC设置得明明白白但指令页没做同样处理。指令缓存和数据缓存是两套独立路径ICache同样需要响应PBMT。如果有一段非缓存指令区却不小心进了ICache你会看到“改代码却不生效”的灵异现象。另外一个坑是全局映射。一个G1的页在TLB里是全局项不区分ASID。如果系统里有多个进程一个进程把某全局页改成NC另一个进程还在用旧的cacheable属性行为自然错乱。有关Svpbmt的修改尽量限制在非全局映射的PTE上。6.4 排查工具和观察点建议如果你在写RTL建议在缓存控制器入口加断言当req_nc为高时L1标签比较结果不得命中。这句断言能最早暴露属性信号有没有传到缓存控制器。如果是软件排查阶段优先做三件事一读出PTE原始值确认PBMT位正确二读出PMA表对应条目确认该区域允许非缓存三在总线接口抓波形确认事务形态。三个证据对上了才能说Svpbmt状态没问题。经验上只要这一步证据链齐了剩下基本就是别名或全局映射这种软件逻辑问题了。7. 写在最后几个容易被忽略的实操心得跑通Svpbmt之后我最大的感受是这套机制真正的难点不在编码而在“属性到底在哪一层被决定”的全局视角。PMA是硬件平台静态画的圈PBMT是软件在圈里画的格子。你做CPU设计光实现PTE解析不行还得保证pbmt信号一路传到缓存子系统和总线你做BSP开发光设置PTE不行还得搞清楚你的SoC里PMA到底怎么定义的。根据我个人经验想要少踩坑建议从简单场景起步先保证整个系统的PMA对普通DDR默认支持非缓存然后只做DMA缓冲区这一条NC路径验证总线行为、数据一致性和延迟表现都符合预期再考虑MMIO的IO类型。这样即使出问题排查范围也被缩到最小。再说一个小技巧在RTL调试阶段给每个TLB条目加一个“最近一次访问是否被PMA忽略PBMT”的计数器我在实测中用这个办法快速找到了好几处软件漏配PMA的问题比反复抓波形高效得多。这套机制后续还能继续扩展比如结合Svinval做更细粒度的TLB维护或者在更复杂的多核一致性场景里把NC内存类型和I/O设备访问统一建模。但那是下一步的事了先把PMA和PBMT这条主链路吃透后面怎么走都顺。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询