NVMe系统内存结构 - PRP与PRP List
- 1 为什么需要PRP
- 2 PRP
- 3 PRP List
- 4 PRP寻址算法
- 4.1 仅PRP1指向数据
- 4.2 PRP1指向数据,PRP2指向数据
- 4.3 PRP1指向数据,PRP2指向PRP List
本文属于《 NVMe协议基础系列教程》之一,欢迎查看其它文章。
1 为什么需要PRP
-
Host向SSD写入数据
Host如果想往SSD上写入用户数据,需要告诉SSD写入什么数据,写入多少数据,以及数据源在内存中的什么位置,这些信息包含在Host向SSD发送的Write命令中。每笔用户数据对应着一个叫做LBA(Logical Block Address)的东西,Write命令通过指定LBA来告诉SSD写入的是什么数据。对NVMe/PCIe来说,SSD收到Write命令后,通过PCIe去Host的内存数据所在位置读取数据,然后把这些数据写入到闪存中,同时得到LBA与闪存位置的映射关系。 -
Host从SSD读取数据
Host如果想读取SSD上的用户数据,同样需要告诉SSD需要什么数据,需要多少数据,以及数据最后需要放到Host内存的哪个位置上去,这些信息包含在Host向SSD发送的Read命令中。SSD根据LBA,查找映射表,找到对应闪存物理位置,然后读取闪存获得数据。数据从闪存读上来以后,对NVMe/PCIe来说,SSD会通过PCIe把数据写入到Host指定的内存中。这样就完成了Host对SSD的读访问。
在上面的描述中,大家有没有注意到一个问题,那就是Host在与SSD的数据传输过程中,Host是被动的一方,SSD是主动的一方。你Host需要数据,是我SSD主动把数据写入到你的内存中;你Host写数据,同样是我SSD主动去你Host的内存中取数据,然后写入到闪存。SSD跟快递小哥一样辛劳,不仅送货上门,还上门取件。
无论送货上门,还是上门取件,你都需要告诉快递小哥你的地址,不然茫茫人海,快递小哥怎么就能找到你呢?同样的,Host你不亲自传输数据,那总该告诉我SSD去你内存中什么地方取用户数据,或者要把数据写入到你内存中的什么位置。你在告诉快递小哥送货地址或者取件地址时,会说XX路XX号XX弄XX楼XX室,也可能会说XX小区XX楼XX室,anyway,快递小哥能找到就行。Host也有两种方式来告诉SSD数据所在内存位置:
- 一是PRP (Physical Region Page)
- 二是SGL (Scatter/Gather List)
2 PRP
NVMe把Host的内存划分为一个一个页(Page),页的大小可以是4KB,8KB,16KB… 128MB。物理内存页面大小,由主机软件在“CC.MPS”中配置。
Physical Region Page (PRP),PRP是指向物理内存页(Page)的指针。
下图,显示了由Page Base Address和Offset组成的PRP的布局。
Bit | Description |
---|---|
63:02 | Page Base Address and Offset (PBAO):该字段表示,64位物理内存页地址。该字段的较低几位(n:2),表示内存页中的偏移量Offset。Offset字段的大小,由CC.MPS中配置的物理内存页面大小决定。 - 如果内存页大小是4KB,则Offset为11:02位; - 如果内存页大小是8KB,则Offset为12:02,以此类推。 |
01:00 | 保留 |
PRP本质就是一个64位内存物理地址,只不过把这个物理地址分成两部分:页起始地址Page Base Address和页内偏移Offset。最后两bit是0,说明PRP表示的物理地址,只能四字节对齐访问。
页内偏移可以是0,也可以是个非零的值。
- 命令的第一个PRP的Offset,可以不为0;
- 如果一个PRP指向PRP List,那么该PRP的Offset,也可以不为0;
- 此外,其他PRP的Offset,必须为0。
3 PRP List
PRP Entry描述的是,一段连续的物理内存的起始地址。如果需要描述若干段不连续的物理内存呢?那就需要若干个PRP Entry。把若干个PRP Entry链接起来,就成了physical region page list (PRP List)。
PRP List中的每个PRP Entry的偏移量都必须是0,PRP List中的每个PRP Entry都是描述一个物理页。它们不允许有相同的物理页,不然SSD往同一个物理页写入几次的数据,导致先写入的数据被覆盖。
每个NVMe命令中有两个域:PRP1和PRP2,Host就是通过这两个域告诉SSD,数据在内存中的位置或者数据需要写入的地址。
PRP1和PRP2有可能指向数据所在位置,也可能指向PRP List。类似C语言中的指针概念,PRP1和PRP2可能是指针,也可能是指针的指针,还有可能是指针的指针的指针。别管你包的有多严实,根据不同的命令,SSD总能一层一层的剥下包装,找到数据在内存的真正物理地址。
下面是一个PRP1指向PRP List的示例:
PRP1指向一个PRP List,PRP List位于Page 200,页内偏移50的位置。SSD确定PRP1是个指向PRP List的指针后,就会去Host内存中(Page 200,Offset 50)把PRP List取过来。获得PRP List后,就获得数据的真正物理地址,SSD然后就会往这些物理地址读入或者写入数据。
如果需要更多的PRP List页,则PRP List页的最后一个条目,是指向下一个PRP List页的指针。
PRP条目的总数,由命令参数和内存页大小暗示。
4 PRP寻址算法
由于一个PRP可能指向数据,也可能指向PRP List,因此,我们可以根据传输数据长度Data Length,来计算出2个PRP的内存指向情况。主要有三种情况:
- 仅PRP1指向数据;
- PRP1指向数据,PRP2指向数据;
- PRP1指向数据,PRP2指向PRP List。
4.1 仅PRP1指向数据
当满足Data Length <= 1 Page时,数据可以用一个Page Size容纳,因此仅需PRP1指向Page,PRP2未使用。
我们把PRP1的Offset考虑进来的话,那就是:
Data Length <= (Page Size - PRP1.Offset)
此时PRP1为非0,PRP2应该为0,可以作为assert条件,以验证编码预期。
4.2 PRP1指向数据,PRP2指向数据
当满足1 Page < Data Length <= 2 Page时,数据用1个Page无法容纳,用2个Page才能容纳,因此PRP1指向一个Page,PRP2指向另一个Page。
PRP1.Offset可以为非0,PRP2.Offset为0
我们把Offset考虑进来的话,那就是:
(Page Size - PRP1.Offset) < Data Length <= (Page Size - PRP1.Offset + Page Size)
此时PRP1为非0,PRP2也为非0,可以作为assert条件,以验证编码预期。
4.3 PRP1指向数据,PRP2指向PRP List
当满足Data Length > 2 Page时,数据用2个Page都无法容纳,因此需要借助PRP List,PRP1指向一个Page,PRP2指向另一个PRP List,可以表示若干个Page。
我们把Offset考虑进来的话,那就是:
Data Length > (Page Size - PRP1.Offset + Page Size)
此时PRP1为非0,PRP2也为非0,可以作为assert条件,以验证编码预期。
如何计算PRP List长度M(PRP个数),可以:
M = (Data Length - (Page Size - PRP1.Offset)) / Page Size
并且(Data Length - (Page Size - PRP1.Offset)) % Page Size == 0。
参考文档:
- SSD NVMe核心之PRP算法
- 蛋蛋读NVMe之三
- NVMe技术基础知识
- 一种自主分离的NVMePRP获取加速方法与流程