由于KVM虚拟机的设备直通方案目前基本都采用vfio方式,而vfio下层依赖于平台的iommu功能,因此我决定研究下intel iommu。计划根据Intel vt-d spec和Linux内核相关源码(主要在drviers/iommu/
下面)进行学习。
DMA Remapping
Types of DMA requests
Remapping硬件将来自于 集成在root-complex中 或 挂载在PCIE bus上的 设备的memory request分成两类:
Requests-without-PASID:这是来自于endpoint devices的普通memory requests。它们一般指明了访问类型(read/write/atomics)、DMA目的地的地址与大小、源设备标识。
Requests-with-PASID:这是来自于支持virtual memory capabilities的endpoint devices的memory requests。它们除了指明上述普通信息外,还带有附加信息:目标PASID、扩展属性等…
(注:PASID全名Process Address Space ID,来源于PCIE中的概念)
Domains and Address Translation
Domain是一个抽象的定义,表示平台上一个隔离的、从host physical memory中分配的子集。对于虚拟化来说,软件可以将每个虚拟机看作是一个单独的domain。
Remapping硬件的作用是:在硬件进行进一步处理(例如:address decoding, snooping of processor caches, and/or forwarding to the memory controllers)之前,将memory request中的地址转换成host physical address。
Mapping Devices to Domains
Source Identifier
source-id:用于标识I/O transaction的发起者。 对于PCIE设备,其source-id位于PCI-Express transaction layer header中,由Bus/Device/Function组成。
Root-Entry & Extended-Root-Entry
Root-table是devices mapping的最顶层结构。它的起始地址由Root Table Address Register指定,共计4-KB大小,由256个root-entries组成(可以算出:每个root-entry有16个字节空间)。每个root-entry对应一个bus number,所以source-id中的bus number在mapping过程中会被当做root-table中的index来使用。
Root Table Address Register
我们首先来看看Root Table Address Register的详细描述:
可以看到:有两种形式的table,根据RTT bit进行控制。下面就依次来看这两种table。
regular Root-table entry
Extended Root-table entry
在支持Extended-Context-Support (ECS=1 in Extended Capability Register)的硬件上,如果RTADDR_REG的RTT=1,则它指向的是一个extended root-table。
综上,又会涉及到两种context entry,下面依次来看。
regular Context-Entry
一个context-entry用于将一个bus上的一个特定I/O device映射到其所属的domain中,也就是指向该domain的地址翻译结构。
source-id中的低8位(device#和function#)用来作为设备在context-table中的index使用。
Context-entries只能支持requests-without-PASID,它详细结构如下:
Extended-Context-Entry
一个Extended root entry可以同时索引一个lower-context-table和一个upper-context-table,这两者都是4-KB大小、包含128个extended-context-entries。
- lower-context-table 对应了特定bus(root entry索引)上device#为0-15的PCI设备
- upper-context-table 对应了特定bus(root entry索引)上device#为16-31的PCI设备
Extended-context-entries既支持requests-without-PASID,也支持requests-with-PASID。对于前者,entry结构与上述regular context entry一致;对于后者,其结构如下所示:
First-level Translation
Extended-Context-Entry可以被配置为通过First-level Translation来翻译requests-with-PASID。这种配置下Extended-Context-Entry包含了指向PASID-table的指针和大小,而requests-with-PASID中的PASID-number作为PASID-table中的offset来索引一个PASID-entry。在PASID-entry中包含了相应进程地址空间的first-level translation structure的指针。
Second-level Translation
Extended-Context-Entry可以被配置为使用second-level translation。这种配置下,Extended-Context-Entry中包含了指向second-level translation structure的指针。
second-level translation可以用来转换requests-without-PASID,也可以在nested translation过程中用来转换requests-with-PASID的first-level translation。(这种使用方式还不太明白,或许和嵌套虚拟化相关,L1虚拟机向L2虚拟机呈现vt-d dma remapping功能时或许会用到)