Intel VT-d(2)- DMA重定向

DMA重定向硬件一般位于Root Complex中,Root-Complex是PCIe系统中引入的概念,它将CPU、内存子系统和PCIe子系连接起来。如下图所示:

而Root Complex则经常被集成到CPU芯片上、MCH(Memory Controller Hub)上或者是IOH(I/O hub)上。

DMA重定向硬件将来自于I/O子系统的内存访问请求分为两类:

  1. 不带地址空间ID的请求(Request without Process Address Space Identifier,即Request-without_PASID),相当于GPA(Guest Physical Address),这是一般Endpoint设备发出的内存访问请求,这类请求通常会表明该请求的类型(读、写或原子操作),DMA目标的地址、大小和发起请求的源设备的ID。
  2. 带有地址空间ID的请求(Request with Process Address Space Identifier,即Request-with-PASID),相当于GVA(Guest Virtual Address),能够发出这类请求的源PCI设备需要拥有virtual address capability,该请求带有额外的信息用于定位目标地址空间和一些其他信息。

不同虚拟机之间的隔离是通过防止分配到其他虚拟机的资源(CPU、I/O设备)访问到本虚拟机的物理地址。每个虚拟机都会有自己独立的物理地址空间,即GPA(Guest Physical Address)空间,该空间不同于主机物理地址空间,即HPA(Host Physical Address)空间。DMA重定向硬件将从I/O设备发过来的访问请求中包含的地址看做是DMA地址,根据不同的使用配置,该DMA地址可能是GPA;可能是跟PASID(Process Address Space ID)相关的VA(application Virtual Address);也可能是由软件定义的I/O虚拟地址(IOVA)。不管怎样,DMA重定向硬件将DMA地址最终转化为HPA(Host Physical Address)实现最终主机物理地址的访问。

如下图所示,系统中存在两个Domain,1和2,也可以理解为存在两个虚拟机,这两个虚拟机发出的内存请求通过在CPU上的内存管理单元(MMU),在x86 CPU上可以理解为分页机制和EPT(Extended Page Table)的组合,将发出的内存请求地址最终转化为主机的物理内存地址,即HPA,对应到主机物理内存上。而Device 1和2,则可以理解为分别分配给Domain 1和2的I/O设备,虽然它们发出访问请求的地址数值一样,但是由于它们所属的Domain不一样,导致DMA Memory Management将会使用不同的地址转换页表,将其分别转换到不同Domain所对应的HPA。VMM/Hypervisor负责对DMA Memory Management所使用的I/O地址转换页表进行创建和维护,同时需要对DMA重定向和I/O设备进行配置,协商好使用什么类型的地址,GPA或者GVA。

每个DMA重定向硬件的实现可以是一个硬件单元包含整个PCI Segment,也可以是多个硬件单元,每个硬件单元各自包含PCI Segment中的部分PCI设备。系统的BIOS或者UEFI负责在系统启动的时候对VT-d硬件进行检测,并分配相应的地址空间,让系统软件能够访问到VT-d硬件及其配置寄存器。BIOS/ACPI以ACPI表的子表(DMAR:DMA Remapping Reporting ACPT Table)的形式将VT-d硬件资源描述出来,这样VMM值需要找到DMAR表,就可以对相应的VT-d硬件进行访问或配置了。DMAR表的组织形式以后再详细讲。

每个从I/O设备往上传输经过重定向硬件的数据包都会包含source-id用于定位源I/O设备,不同的I/O设备其source-id的实现可能不一样,对于PCI设备而言,其source-id是传输层头部中包含的requester Identifier,由Bus、Device、Function组成,其格式如下所示:

所谓的重定向就是对目标地址进行转换或更改,DMA重定硬件向利用分层页表结构对地址进行转化。属于不同Domain的I/O设备请求需要被分配到不同的转换页表中,该索引、分配过程以I/O设备请求的source-id为输入源,对于PCI设备发出的Request-without-PASID而言,它将会使用请求包中包含的PCI Bus、Device和Function号作为索引值。在进行这样的索引之前,VMM需要在内存中建立好一个4KB的Root-table,该table包含256个entry,每个entry对应一个PCI Bus,每个Root-entry中包含一个指针,该指针指向一个4KB的Context-table,该Context-table中包含了256个entry,对应到该PCI Bus下的所有Device和Function。每个Context-entry都包含一个指向该PCI Function所对应的Domain的地址转换页表的指针。其结构如下图所示:

当找到相应的地址转换页表后,硬件才开始正常的地址分级页表转换,即所谓的page-walk,将请求中的GPA地址转化为HPA,实现最终的物理内存访问,该转化过程即称为Second-Level-Translation。Root-table的地址需要VMM在启动VT-d硬件的时候,将Root-table的地址写到VT-d硬件相应的寄存器(Root Table Address Register)上,为VT-d硬件提供一个入口。

对于Request-with-PASID而言,其请求中包含的地址转换页表入口索引,即(PCI、Bus、Device和Function值)是一样的,但是其包含的请求地址类型不一样,是GVA,而不是GPA,故需要现将GVA转化为GPA(即为First-Level-Translation),然后再将得到的GPA转化为HPA,即Second-Level-Translation,才能实现最终的物理内存访问。

该方法需要有两次索引地址转换页表的入口地址,所以需要用到Extended-root-table,该4KB的table每个Ext-root-entry中,包含两部分,分别包含Upper-context-table的指针和Lower-contex-table的指针,Upper-context-table指针指向的是PASID-Table,PASID-Table则根据PASID来对该表进行索引,每个PASID-entry都包含一个指向分级页表的入口,该分级页表用于完成First-Level-Translation,即将请求中包含的GVA转化为GPA。Sencond-Level-Translation分级页表的所以和前面Request-without-PASID一样。当Frist-Level-Translation完成后得到的GPA,将作为Second-Level-Translation作为输入地址,最终得到HPA,完成主机物理内存的访问。

不管是first-level translation (requests-with-PASID)还是second-level translation (request-without-PASID)。对于request-with-PASID而言,会先使用first-level translation table将DMA地址转换为一个不带PASID的地址,然后再将这个不带PASID的地址作为second-level-translation table的输入进行转换得到最终的物理地址。查询页表完成地址转换的方式就根普通的分页机制完全一致。页表的层数会根据具体使用的页框大小而变化,页框大小可以是4KB,2MB和1GB,下图以4KB为例。

由此可见要完成一次DMA重定向访问到真正的主机物理地址,中间会有很多的内存访问,为了加快这些内存访问,VT-d硬件中,会引入各种各样的Cache加快这些物理地址的转换,或者是主机物理内存的访问。

欢迎关注同名微信公众号“河马虚拟化”第一时间获取最新文章。

猜你喜欢

转载自blog.csdn.net/lindahui2008/article/details/83715106
今日推荐