文章目录

  • IOMMU动机
  • DMA Remapping
    • Root Table/Context Table
    • Second-Level Page Structure
  • IOMMU Group
  • DMA Map
  • VFIO是Linux下设备透传的主流解决方案,它的硬件基础是IOMMU。IOMMU提供了DMA重映射和中断重映射。本文主要介绍IOMMU的基本概念。

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设备所在虚机的IO内存映射。次级页表描述了一个虚机包含的IO设备可访问的物理页。如果两个IO设备都使用一个次级页表,那么他们必然属于同一个虚机。
  • 针对第二种情况,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

  • 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位作为偏移访问物理页的具体内容。

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访问的隔离。
  • 因为以上的硬件问题,Intel的IOMMU没有办法做到device级别的DMA隔离。因此IOMMU定义了一个Group的概念,它表示IOMMU能够进行DMA隔离的最小单位,一个Group可能包含一个或者多个device。这和设备的硬件拓扑相关。当我们要透传设备给虚机使用时,只能以IOMMU Group为单位进行透传,保证DMA的隔离。

DMA Map

  • 当实现PCI设备的透传时,它最核心的工作就是限制PCI设备可访问的内存区域,对于具有DMA能力的PCI设备,在通用场景下它是可以访问主机内存的,比如GPU设备,它的显存就是一块主机上的内存,它对显存可以进行DMA操作。对于透传的GPU设备,当它需要进行DMA操作时,我们不允许它直接访问主机上的内存,原因就是上面提到的安全隐患。怎么办呢?方法就是为透传的GPU设备提前分配好它需要进行DMA操作的内存,当它进行DMA操作时,告诉它只能访问这块内存。整个流程步骤如下:
  1. 当Qemu要将PCI设备透传给虚机使用时,如果这个PCI设备有DMA的能力,Qemu需要提前分配一块内存。得到这块内存的起始虚拟地址(HVA)和大小。
  2. Qemu分配这块内存的目的是给PCI设备用,它想要达到的目的是,当虚机访问PCI设备的DMA内存区域时,它使用GPA最终经IOMMU页表转换,访问到的是Qemu提前分配好的这块内存,因此IOMMU的页表需要建立这样的映射关系:GPA通过IOMMU转换指向的内存页,和Qemu分配的内存指向的内存页是同一个。即GPA通过IOMMU转换得到的HPA和HVA通过MMU转换得到的HPA相同。
  3. 为了实现2中的功能,KVM模块提供了一个IOCTL命令字VFIO_IOMMU_MAP_DMA,它的功能是,根据IOCTL传入的一段已分配好的内存的HVA和一个GPA,KVM创建一条IOMMU页表项。最终的效果它是,输入GPA查询页表,得到的页表项存放的物理地址是HVA指向的内存页的物理地址。这样,虚机中PCI设备DMA访问的内存都是Qemu提前分配好的。

VFIO硬件依赖——IOMMU机制相关推荐

  1. 如何在 Web Forms 中引入依赖注入机制

    依赖注入技术就是将一个对象注入到一个需要它的对象中,同时它也是控制反转的一种实现,显而易见,这样可以实现对象之间的解耦并且更方便测试和维护,依赖注入的原则早已经指出了,应用程序的高层模块不依赖于低层模 ...

  2. .NET平台依赖注入机制及IoC的设计与实现

    我们设计的分层架构,层与层之间应该是松散耦合的.因为是单向单一调用,所以,这里的"松散耦合"实际是指上层类不能具体依赖于下层类,而应该依赖于下层提供的一个接口.这样,上层类不能直接 ...

  3. Maven---学习心得---maven的Dependency Mechanism(依赖关系机制)

    1.概述: dependency management是maven所擅长的东西之一,是maven的特色功能. 参考资料:1)maven官网documentation 2) 2.maven的依赖机制 1 ...

  4. 固态硬盘硬件全盘加密机制绕过漏洞论文分析(Self-Encrypting Deception: Weaknesses in the Encryption of Solid State Drives)

    论文传送门:<Self-Encrypting Deception: Weaknesses in the Encryption of Solid State Drives> 本文内容: 一. ...

  5. Angular 通过依赖注入机制注入一个对象的例子,什么是 ElementInjector

    假设我在app.config.ts里定义了一个interface AppConfig和一个对象HERO_DI_CONFIG, 我想将后者注入到一个类的构造函数里去: export interface ...

  6. Angular依赖注入机制的一个错误消息:Error Cannot instantiate cyclic dependency!

    例子: import { Injectable } from '@angular/core';@Injectable({providedIn: 'root',}) export abstract cl ...

  7. Angular 依赖注入机制根据providers定义生成注入实例的框架代码

    /*** Converts a `SingleProvider` into a factory function.** @param {?} provider provider to convert ...

  8. Linux驱动:VFIO概述(vfio/iommu/device passthrough)

    <ARM SMMU原理与IOMMU技术("VT-d" DMA.I/O虚拟化.内存虚拟化)> <提升KVM异构虚拟机启动效率:透传(pass-through).DM ...

  9. vfio概述(vfio/iommu/device passthrough)

    文章目录 1.IOMMU 1.1 IOMMU功能简介 1.2 IOMMU作用 1.3 IOMMU工作原理 1.4 Source Identifier 2.VFIO 2.1 概念介绍 2.2 使用示例 ...

最新文章

  1. 根据CPU核数合理设置线程池大小
  2. PHP TP5入门 二:写接口,添加控制器并访问
  3. ASP.NET Core 数据保护(Data Protection)【中】
  4. no.4 数据和C 07
  5. 远程断开远程桌面会话之方法
  6. python 树结构三方包_python第三方库---BeautifulSoup库(搬运)
  7. EntityFramework Core不得不注意的性能优化意外收获,你会用错?
  8. 设计模式 迪米特法则
  9. MySQL中distinct和group by性能比较
  10. python面向对象代码_两百行代码搞定!使用Python面向对象做个小游戏
  11. 树莓派Raspberry pi 4B 运行 WuKong-Robot 智能语音对话机器人
  12. ISIS-三类路由器区域路由
  13. VirtualBox 常用设置说明
  14. Microsoft Defender SmartScreen 阻止了无法识别的应用启动
  15. 电脑不能安装linux,解决部分电脑不能安装Linux问题
  16. 计算机网络时有时无,电脑WiFi时有时无不稳定的解决方法 | 我爱分享网
  17. 所有的伟大,源于一个勇敢的开始
  18. 11 块钱的惠灵顿牛排!
  19. 20210526 SDH
  20. 厉害了!推荐一个 Web 端自动化神器 - Automa

热门文章

  1. Linux搭建TFTP服务
  2. 前端代码深浅拷贝四种方式
  3. 23、IP地址的表示及分类
  4. 第三章 人类社会及其发展规律
  5. Android开发定位
  6. ec2 安装mysql_亚马逊云EC2安装Mysql5.6.41
  7. 迁移率 计算方法及用途 风控建模系列 02
  8. rap2安装以及启动
  9. java多线程面试题总结,java程序员面试宝典第五版
  10. Unity3d UGUI基础控件使用(一)