IOMMU主要功能包括DMA Remapping和Interrupt Remapping
在虚拟化环境下,guest VM使用的物理地址是GPA(参考这篇文章),如果直接用guest OS中的驱动程序去操作I/O设备的话(这里的I/O限定于和内存统一编址的MMIO),那么设备使用的地址也是GPA。这倒不难办,使用CPU的EPT/NPT MMU查询对应guest VM的nPT页表,进行一下GPA->HPA的转换就可以了。
可是别忘了,有一些I/O设备是具备DMA(Direct Memory Access)功能的。由于DMA是直接在设备和物理内存之间传输数据,必须使用实际的物理地址(也就是HPA),但DMA本身是为了减轻CPU的处理负担而存在的,其传输过程并不经过CPU。对于一个支持DMA传输的设备,当它拿着GPA去发起DMA操作时,由于没有真实的物理内存地址,传输势必会失败。
那如何实现对进行DMA传输的设备的GPA->HPA转换呢?再来一个类似于EPT/NPT的MMU?没错,这种专门转换I/O地址的MMU在x86的阵营里就是IOMMU。
然而,不和AMD使用相同的名字是Intel一贯的路数,所以Intel通常更愿意把这种硬件辅助的I/O虚拟化技术叫做VT-d(Virtualization Technology for Direct I/O)。作为后起之秀的ARM自然也不甘示弱,推出了对应的SMMU(System MMU)。
以Intel的VT-d为例,它规定了一个domain对应一个IO页表。在具体的实现中,通常是一个guest VM作为一个domain,因此分配给同一个guest VM的设备将共享同一个IO页表。
IOMMU能将device使用的虚拟地址(也称为设备地址或者IO地址)转化为物理地址,如果没有IOMMU,DMA也能直接访问RAM中的内容,但是让DMA没有限制地访问RAM是一件很危险的事情,而IOMMU能够对这个过程加以限制,当DMA访问的地址合法时,IOMMU才返回正确的数据.
硬件中断重映射
除了翻译地址的功能,IOMMU还能对硬件中断进行重映射,达到屏蔽部分中断,或自定义中断处理函数的目的.
设备隔离
基于地址翻译和硬件中断重映射两大功能,IOMMU就具有了隔离设备的能力,这提高了设备访问RAM时和设备发出中断时的安全性.
除了将单个设备隔离的功能外,IOMMU还能隔离一组设备,如隔离PCI桥上的几个设备,所以IOMMU还有一个概念,叫做IOMMU_GROUP, 代表一组被隔离的设备的集合.
Iommu 的主要功能为设备dma时刻能够访问机器的物理内存区,同时保证安全性。
在没有Iommu的时候,设备通过dma可以访问到机器的全部的地址空间。
1、这种机制下如果将设备的驱动放在用户态,那么如何保护机器物理内存区对于用户态驱动框架设计带来挑战。当出现了iommu以后,iommu通过控制每个设备dma地址到实际物理地址的映射转换,使得在一定的内核驱动框架下,用户态驱动能能够完全操作某个设备dma和中断成为可能。
2、如果将这个物理设备通过透传的方式进入到虚拟化虚拟机里,虚拟机的设备驱动配置设备的dma后,hypervisor必须在透传设备dma访问时刻,对dma访问进行截获,将其中dma访问的虚拟机物理地址,转换为hypervisor为虚拟机分配的物理地址,也就是需要将虚拟机透传设备dma访问做vpaddr(虚拟机物理地址)---->ppaddr(物理机物理地址)。这部分截获对虚拟机dma来说带来切换到hypervisor开销,hypervisor转换地址开销。
当引入了iommu以后,这部分开销由iommu硬件承担,所有hypervisor工作就更加简单,只需要将透传设备Iommu dma地址映射表使用vpaddr--->ppaddr地址转换表即可(这部分表在hypervisor里配置在ept中)
3、方便了老式32位pci硬件在64位机器上的使用。只需要在iommu地址映射表上配置32bitpci设备dma地址-->64位机器物理地址即可。
4、方便了主机os配置设备dma工作,因为dma要求使用连续的地址空间进行读写,有了iommu的存在os就可以为设备配置连续的dma地址而真正对应的非连续的物理地址