PMA¶
本文来一起了解一下RISCV的PMA(Physical Memory Attributes)设计。主要是基于riscv-privilege 1.12版本其中的3.6章节,对PMA做一个描述,分析清楚它的设计目的和实现方法
背景¶
PMA针对的是包含不同地址范围的完整的系统,这些地址范围,一些对应到内存区域,一些映射到了控制寄存器,还有一些是保留区域。某些地址范围不支持读,写或者执行。一些或许不支持子字或者子块访问,一些或许不支持原子操作,一些或许不支持cache一致性或者有不同的内存模型。同样的,内存映射控制寄存器在支持的访存宽度,支持原子操作,以及读或者写操作是否会带来一些影响等方面各不相同。因此RISCV引入了PMA
什么是PMA¶
下述是基于spec的直译,有些描述乍看挺难理解它在说什么,所以我在其中加了个人理解的脚注,有些里理解或许会有很大偏差,后续应该会有机会再改进。
PMA是基础硬件的固有的属性,一旦SOC确定了,地址空间也就划分好了,那么不同的地址空间的属性也就确定了,因此在系统运行期间很少修改PMA。这也是PMA和PMP的区别,它不会因为执行上下文不同而不同。1
某些地址空间的PMA在芯片设计时就固定了,比如片上ROM。其他的地址空间在整板方案确定时才能确认,比如其他芯片连接到片外总线,用1G内存和2G内存,PMA的配置是不同的。当然,也并不是说PMA就不能在运行时修改,一些设备可以在运行时修改,以达到不同用户使用不同PMA配置的目的。比如一个SRAM,可以在一个应用中被一个核私有并经过cache,也可以在另一个应用中共享并不经过cache
大多数系统将要求在执行的流水中当知道物理地址后,至少有一些PMA是动态检查的,因为在整个物理内存空间中,可能不支持某些操作,有些操作可能需要知道当前PMA配置。许多其他的架构的PMA可以在虚拟地址中工作。通过TLB去告诉流水线这些属性。这种实现注定会把平台定制化信息传递到虚拟层,可能会导致系统错误,除非在每个页表项中为每个物理内存区域正确初始化属性。另外,对于在物理内存空间中指定属性而言,可用的页面大小可能不是最佳的,从而导致地址空间碎片化和对昂贵的TLB条目的低效使用。 RISCV把PMA放到了一个独立的单元中,叫做PMA Checker。在许多场景中,每一个物理地址区域的属性在系统设计阶段就知道了,这样就可能固化到PMA Checker中。如果属性是可以在运行时配置的,那么可以提供平台定制的内存映射控制寄存器,这样就能以一个合适的粒度指定平台的每一个区域的属性。(举例,一个片上SRAM,可以被灵活的分成过cache和不过cache的区域)2
PMA检查任何对于物理内存的访存,也包括虚拟地址到物理地址转换过程中的访存。为了协助系统调试,强烈建议,可能的话,处理器能精确的捕获PMA检查失败的物理内存访问。当指令,load, store 发生access-fault异常时,精确的触发PMA违规清单,这区别于虚拟内存page-fault 异常。精确的PMA异常可能不会总是可用,例如,将access-fault作为发现机制的一部分的传统总线架构。这样的话,从设备的错误返回将会以不精确的bus-error中断来进行上报。3
PMA一定是软件可以访问的,这样软件才能正确的访问某个设备或者正确的配置其他硬件组件去访问内存,比如说DMA控制器。当然PMA与给定的物理平台结构紧紧的绑定,很多细节是平台特有的,因此软件可以学习PMA值作为一个平台。某些外设,特别是传统总线,不支持PMA发现,如果尝试发出一个不支持的访问,将会给出错误响应或者超时。典型的,平台特有的机器模式代码将会提取PMA并且立即把这个信息通过一些标准实现发送给更高层次低特权的软件。 当平台支持动态可再配置PMA时,将会提供一个接口,通过给一个能正确再配置平台的机器模式驱动发送请求去设置属性。例如,在一些内存区域切换cacheability属性会引入平台特殊的操作,像cache flush, 只有在机器模式下才能操作。4
区域的划分¶
内存空间划分为**主内存区域**,IO区域**和**空闲区域。主内存区域需要有一些属性,IO设备有更宽泛的属性范围。那些不是通常意义的主内存的内存区域,比如设备RAM,也被划分为IO区域。空闲区域也被划分为IO区域,但携带不能访问的属性。
PMA支持的访问类型¶
访问类型包含访存宽度,从8-bit到long multi-word burst, 都支持。也支持每种宽度下的对齐和非对齐访问。主存储器区域始终支持对所连接设备所需的所有访问宽度的读取和写入,并且可以指定是否支持指令提取。
I/O 区域可以针对特定数据宽度,进行读、写、执行access的组合配置。基于页的虚拟内存,IO以及内存区域的系统,可以指定某个页表的读或者写的组合。
atomic PMA¶
atomic PMAs 描述的是在这个地址区域支持哪个原子指令。对原子指令的支持被划分为两类,LR/SC和AMO内存指令
AMO PMA¶
AMO PMA分了四个等级
等级 | 支持的操作 |
---|---|
AMONone | None 不支持任何AMO指令 |
AMOSwap | 仅支持amoswap |
AMOLogical | 支持 above + amoand, amoor, amoxor |
AMOArithmetic | 支持above + amoadd, amomin, amomax, amominu, amomaxu |
对每一个支持的等级,如果内存区域支持一个给定宽度的读和写,对于这个给定宽度的对齐的AMO指令是支持的。主内存和IO区域可能只支持一个子集或者不支持原子操作。
AMOLogical support for I/O regions where possible
LR/SC原子操作¶
LR/SC分了三个等级
等级 | 说明 |
---|---|
RsrvNone | 不支持LR/SC指令 |
RsrvNonEventual | 支持LR/SC操作,但是缺少特权指令文档中描述的最终成功保证 |
RsrvEventual | 支持LR/SC操作,并且提供最终成功保证 |
建议对主内存区域支持RsrvEventual,大多数IO区域不支持LR/SC访问,因为这些构建在cache一致性策略的上层最方便,但也有一些支持RsrvNonEventual或RsrvEventual。 当内存区域的LR/SC标记为RsrvNonEventual, 软件应该提供额外的错误返回机制。
对齐¶
总结¶
spec中没有对PMA进行具体的设定,甚至没有寄存器,是因为它与整体设计紧密绑定,很难统一吗?所谓的PMA Checker到底要如何实现?
-
PMA更多的是针对硬件结构,一般不需要动态修改PMA,但可以做成能够动态改。 ↩
-
也就是说RISCV的PMA和其他架构的不太一样,很多其他架构的PMA都可以管理虚拟地址空间,RISCV的设计者认为这样引入了不必要的麻烦,并且它将PMA集成到了一个叫做PMAChecker的独立单元中 ↩
-
这里讲的是建议能够精确的捕获PMA触发的异常,如果通过总线中断的方式来上报,就不精确了,但有些时候也迫不得已,这里所谓的**discovery mechanism**是什么意思。 ↩
-
这一段是比较别扭的,我认为,设计者想表达的是,软件要把PMA做成模块化,而且要做到特权模式中,应用层通过提供的接口来对PMA寄存器进行读写,放到特权模式中是因为有些操作必须在特权模式下执行 ↩