欢迎光临
我们一直在努力

linux QEMU 的PCI设备直通(pass through)

VFIO(Virtual Function I/O)是一个现代化的、安全的内核框架,用于在用户空间实现设备直通,例如在 QEMU/KVM 虚拟化环境中。vfio-pci 是该框架下的 PCI 设备驱动。

1. 核心概念:设备直通

设备直通允许虚拟机独占并直接访问宿主机上的一个物理硬件设备。对于虚拟机来说,这个设备就像直接插在它自己的主板上一样,从而可以获得近乎原生的性能。

  • 传统模拟:QEMU 完全通过软件模拟一个设备(如 e1000 网卡),性能较差。

  • 半虚拟化:使用 virtio 等驱动,在宿主机和虚拟机之间使用高效的通信机制,性能很好,但仍然是虚拟设备。

  • 设备直通:虚拟机直接使用物理设备,绕过 VMM 的大部分干预,性能最高。vfio-pci 就是实现 PCI/PCIe 设备直通的关键。

2. 配置 VFIO-PCI 直通

配置步骤如下,下面我们来详细讲解每个步骤。

2.1 确认硬件和 BIOS 支持

  • IOMMU 支持

    • 对于 Intel CPU:需要支持 VT-d (Virtualization Technology for Directed I/O)。

    • 对于 AMD CPU:需要支持 AMD-Vi。

    • 如何确认:在 BIOS/UEFI 中确保这些功能已开启。然后在 Linux 中执行:

      dmesg | grep -e DMAR -e IOMMU

      如果看到 DMAR 表或 IOMMU 被初始化的相关信息,则表示支持。

  • OMMU 分组检查 执行以下命令检查 IOMMU 分组情况:

    shopt -s nullglob
    for g in /sys/kernel/iommu_groups/*; do
    echo "IOMMU Group ${g##*/}:"
    for d in $g/devices/*; do
    echo -e "\\t$(lspci -nns ${d##*/})"
    done
    done

  • 2.2 配置 Linux 内核以使用 VFIO

  • 启用内核模块: 确保 vfio_pci、vfio、vfio_iommu_type1 和 vfio_virqfd 模块已加载。通常需要修改 initramfs 来在早期启动时加载它们。

  • 配置内核参数: 在 GRUB 引导器中,修改 /etc/default/grub 文件中的 GRUB_CMDLINE_LINUX 行。

    • 对于 Intel:

      GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt"

    • 对于 AMD:

      GRUB_CMDLINE_LINUX="amd_iommu=on iommu=pt"

    • iommu=pt 表示只为需要直通的设备启用 IOMMU,有助于提升性能。

  • 让 VFIO 提前接管设备(推荐): 为了防止宿主机系统抢先占用你想要直通的设备,可以在内核参数中指定 vfio-pci 来绑定它们。首先,获取设备的 Vendor ID 和 Device ID:

    lspci -n -s <设备PCI地址,如 01:00.0>
    # 输出示例:01:00.0 0300: 10de:1b80 (rev a1)

    然后,同样在 /etc/default/grub 的内核参数中添加:

    GRUB_CMDLINE_LINUX="… vfio-pci.ids=10de:1b80,8086:100e"

    多个设备 ID 用逗号分隔。

  • 更新配置: 修改后,更新 GRUB 并重建 initramfs,然后重启。

    sudo update-grub
    sudo update-initramfs -u
    sudo reboot

  • 2.3 验证并手动绑定设备(可选)

    重启后,验证设备是否已被 vfio-pci 驱动绑定:

    lspci -kn -s <设备PCI地址>

    在输出中,你应该看到 Kernel driver in use: vfio-pci。

    如果未能自动绑定,你可以手动操作:

    # 1. 解绑原有驱动
    echo <设备PCI地址> | sudo tee /sys/bus/pci/devices/<设备PCI地址>/driver/unbind
    # 2. 绑定到 vfio-pci
    echo <vendor id> <device id> | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id
    # 或者直接使用 PCI ID
    echo <设备PCI地址> | sudo tee /sys/bus/pci/drivers/vfio-pci/bind

    2.4 在 QEMU 命令行中添加设备

    最后,在启动 QEMU 虚拟机时,使用 -device vfio-pci 来将设备传递给虚拟机。

    -device vfio-pci,host=<BB:DD.F>[,…其他选项]

    3. 典型示例

  • 直通一个 GPU

    qemu-system-x86_64 \\
    … # 其他参数(内存、CPU等)
    -device vfio-pci,host=01:00.0,multifunction=on \\
    -device vfio-pci,host=01:00.1 \\
    …

    • host=01:00.0:指定要直通的设备在宿主机上的 PCI 地址。

    • multifunction=on:如果设备是多功能设备(如 GPU 通常带一个音频控制器 01:00.1),需要此参数,并且必须同时传递所有功能设备。

  • 直通一个网卡

    qemu-system-x86_64 \\
    … # 其他参数
    -net none \\ # 确保不为此设备创建默认网络
    -device vfio-pci,host=06:00.0 \\
    …

  • 4. 重要注意事项

    • 安全性:VFIO 设计上是安全的,它利用 IOMMU 进行 DMA 隔离,防止设备直接访问任意内存。

    • GPU 直通:这是最常见的用途(也称为 "VGA Passthrough" 或 "GPU Passthrough")。通常还需要在 QEMU 参数中隐藏虚拟化状态、使用特定的 BIOS 设置(如 vgabios 转储)等,过程更为复杂。

    • 驱动程序冲突:最大的挑战是确保宿主机没有占用设备。使用内核参数提前绑定是最可靠的方法。

    • IOMMU 分组:如果设备所在的 IOMMU 组中有其他不想直通的设备,你将无法单独直通该设备。解决此问题可能需要使用支持 ACS override 的内核参数(pci=acs_override=on)或特定的 PCIe 插槽,但这可能会降低系统安全性。

      IOMMU Group 10:
      01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP106 [GeForce GTX 1060 6GB] [10de:1c03] (rev a1)
      01:00.1 Audio device [0403]: NVIDIA Corporation GP106 High Definition Audio Controller [10de:10f1] (rev a1)

      • 独立分组:理想的直通设备应该位于独立的 IOMMU 组中。

      • 多功能设备:如上面的 Group 10,包含 GPU (01:00.0) 和其音频控制器 (01:00.1),它们必须一起直通。

      • 问题分组:如果一个组包含不相关的设备(如 GPU + 网卡),则无法单独直通其中一个。

    VFIO-PCI 驱动是实现高性能 PCI/PCIe 设备直通的工业标准方法。虽然配置过程稍显复杂,但它能让你在虚拟机中获得最佳的硬件性能,尤其适用于图形工作站、游戏虚拟机和需要低延迟网络的应用场景。


    技术交流,欢迎加入社区:GPUers。

    赞(0)
    未经允许不得转载:171主机测评 » linux QEMU 的PCI设备直通(pass through)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址