VFIO硬件基础——IOMMU

文章目录

  • IOMMU动机
  • DMA Remapping
    • Root Table/Context Table
    • Second-Level Page Structure
  • IOMMU Group

  • VFIO是Linux下设备透传的主流解决方案,它的硬件基础是IOMMU。IOMMU提供了DMA重映射和中断重映射。本文主要介绍IOMMU的DMA重映射机制。

IOMMU动机

  • Intel提出IOMMU的主要目的,是解决IO虚拟化遇到的问题,因此首先介绍VMM实现IO虚拟化的主要几种方式,以KVM为例:
  1. 软件模拟方式。软件模拟方式实现IO虚拟化是常见的实现方案,比如qemu模拟pci设备,只要qemu做到模拟的pci设备和真实物理设备行为相同就可以。当guest初始化pci设备,读写设备配置空间,使用设备功能,qemu都能正确的反馈,就算做到了软件层面的设备模拟。软件模拟方式的优点是兼容性好,同时guest软件不需要任何适配,可移植性好。缺点是性能问题,因为都是通过软件模拟的。
  2. 新软件接口方式。这种方式和纯软件模拟类似,但它不会完全模拟设备,而是向guest提供一套高效的访问主机IO设备的新接口。常见的就是virito设备,guest想要访问qemu提供的virtio设备时需要按照virtio提供的方式来做,guest OS需要安装virtio驱动。软件接口的方式优点是性能好。但存在可移植性和兼容性问题。
  3. 分配方式。分配方式就是直接把主机上的设备分配给guest用。我们知道Linux系统下用户态进程不能直接访问设备,需要加载内核态驱动才能完成,qemu在主机看来也是一个用户态进程,如果把设备直接给qemu直接用,需要解决一个问题,就是qemu在访问设备的时候不能访问其它内核资源,否则会有安全问题。如果做到了这一点,就可以使用分配主机设备的方式实现IO虚拟化。分配方式就是我们常说的设备透传。比如以vfio-pci方式透传GPU设备,就是分配方式的IO虚拟化。透传方式性能好,设备兼容性和guest 软件移植性也好,但要求设备硬件具有资源隔离的能力。
  4. 分时复用方式。分时复用方式是分配方式的扩展,这种方式下要求设备本身有能力支持多个接口并行接收用户的请求,并且互不影响。分时复用方式兼具分配方式的优点,但对设备的硬件要求更高,它不仅需要资源隔离能力,还需要硬件具有并行处理请求的能力。virtio-gpu就是qemu利用GPU的并行处理能力,实现GPU在主机上的分时复用。然后将模拟的设备提供guest。
  • 分析了IO虚拟化的主要方案后,Intel提取了这些方案的主要需求,提供了硬件机制用来辅助IO虚拟化,这就是VT-d。它主要解决以下问题:
  1. IO设备分配。Intel提供将IO设备灵活分配给虚机的机制,同时保证虚机访问IO设备的安全性。
  2. 资源隔离。透传方式使用IO设备时,如果虚机使用设备DMA,那么它会访问到主机上的内存,这会产生安全风险,因此Intel要保证DMA访问的安全性,具体的硬件解决方案就是DMA重映射。和DMA一样,IO设备透传时,产生的中断也会投递到主机的CPU核,将器重映射到虚机,也是Intel硬件要解决的问题。
  3. 中断post。Intel支持中断以post的方式注入中断,这是一种高效的中断模拟方式,guest不需要退出。在IO虚拟化场景下,Intel需要解决透传设备怎么post中断到虚机的cpu问题。
  • 以上的种种,就是Intel的IO虚拟化方案要解决的问题,而IOMMU可以认为是Intel为解决这些问题提供的核心机制。本文主要参考intel的IO虚拟化手册。

DMA Remapping

  • DMA重映射,它的意思是,当IO设备发起DMA访问请求时,IOMMU会将请求的地址进行一次转换,通过这样的方式,将guest的物理地址映射到host上真实的物理地址上去。DMA重映射的核心就是地址转换。
  • 提到地址转换,我们第一反映就是MMU,它是Intel的硬件内存管理单元,接收虚拟地址作为输入,根据其页表转换成物理地址,读写物理内存上的内容。总结,MMU的使用者是CPU,它完成的工作是HVA到HPA之前的转换。IOMMU的功能与MMU类似,不同的是它的使用这者不是CPU,而是IO设备,IOMMU因此得名,它完成的工作也是虚拟地址到HPA之前的转换,这里的虚拟地址可以包含很多种。在虚拟化的场景下,使用vfi-pci透传的方式,它的虚拟地址是GPA。
  • IOMMU要实现地址转换功能,需要满足以下条件:
  1. 首先,如果IOMMU需要地址转换,那么和MMU一样,需要提供页表机制。当IOMMU接受到IO设备的DMA请求时,首先将请求读写的虚拟内存地址IOVA,通过页表转换成物理地址IOPA,然后读写物理内存的内容。
  2. 其次,针对IO虚拟化的场景,需要把IO设备分配给虚机,而虚机在主机上只有一部分内存可以访问,因此IO设备的内存访问也只能局限与这部分内存。IOMMU要提供一种机制,来保证IO设备只能访问它所属的那个虚机拥有的物理空间。
  • 针对第一种情况,IOMMU提供了次级页表(Second-Level Page Table Structures)来存储一个IO设备所在虚机的I内存映射。
  • 针对第二种情况,IOMMU要求发送内存访问请求的IO设备表明自己的source-id,对于pci设备source-id就是BDF,IOMMU用这个东西作为索引,就能查找到IO设备所在虚机拥有的页表结构。因此还需要以BDF为关键字的表,用来存放页表的物理地址。IOMMU将这个页表分为两级,分别是Root Table和Context Table。
  • 总结一下,IOMMU为实现DMA Remapping实现了两类表:Root Table/Context Table和Second-Level Page Table。同时要求访问物理内存的IO设备表明自己的source-id BDF。下面分别介绍:

Root Table/Context Table

VFIO硬件基础——IOMMU_第1张图片

  • Root Table有256个条目,可以索引所有的0-255总线号的pci设备,IOMMU从source-id中取出bus号,根据总线号在Root Table中索引对应的条目。找到Context Table。
  • Context Table以Device/Fuction号为索引,device范围0-31,fuction范围0-7,因此Context Table表的总条目数为32*8 = 256。IOMMU从source-id中取出device和fuction号,据此查找到IO设备所在虚机的IO地址空间页表结构,Second-Level Page Table。
  • 从上面可以看出,只要在IO设备发出地址空间访问时,根据BDF号查找到的Second-Level Page Table相同,就可以实现多个IO设备分配给同一个虚机,因此他们访问的物理地址空间都是一样的,同属于一个虚拟机。从上图中也能看到,Second-Level Page Table Structures在逻辑上关联了一个虚机的IO物理地址空间。

Second-Level Page Structure

  • Second-Level Page Structure和MMU的页表结构非常类似,下图是一个物理地址为48位,页表大小为4K的IOMMU 4级页表结构。当IOMMU进行地址转换时,48位物理地址的高9位物理地址作为PML4 Table的索引,确认PDPT的物理地址,找到PDPT之后,取48位物理地址的次9位物理地址作为PDPT的索引,确认PD的物理地址,以此类推,最终找到IO设备要访问的内存页,再用低12位作为偏移访问物理页的具体内容。
    VFIO硬件基础——IOMMU_第2张图片

IOMMU Group

  • 从IOMMU地址转换的机制可以知道,IOMMU根据source-id从Root Table/Context Table中查找页表,当两个IO设备都透传给虚机时,IOMMU根据这两个IO设备的source-id查找到的页表是同一个。
  • 有这么一种情况,如下图所示。两个不同的IO设备在DMA请求时有相同的source-id。PCIe-PCI桥下的设备就属于这种情况。在发送DMA请求时,PCIe-PCI桥统一为它下面的设备生成Bus为总线号,device和function为0的source-id。这种情况下所有PCIe-PCI下的设备,在DMA请求的时候IOMMU查找到的Context Table Entry和页表都是相同的,因此它们只能被透传给同一个虚拟机,没有办法透传给不同虚机,因此做不到DMA访问的隔离。
    VFIO硬件基础——IOMMU_第3张图片
  • 因为以上的硬件问题,Intel的IOMMU没有办法做到device级别的DMA隔离。因此IOMMU定义了一个Group的概念,它表示IOMMU能够进行DMA隔离的最小单位,一个Group可能包含一个或者多个device。这和设备的硬件拓扑相关。当我们要透传设备给虚机使用时,只能以IOMMU Group为单位进行透传,保证DMA的隔离。

你可能感兴趣的:(VFIO硬件基础——IOMMU)