---
title: Proxmox 5.4 上的 PCI(e) 直通
date: 2019-05-31 12:49:43
tags:
---
{% blockquote %}
本文根据 {% link Proxmox 官方文档 https://pve.proxmox.com/wiki/PCI(e)_Passthrough %} 翻译而成。
{% endblockquote %}

## 一般需求 ##

由于直通是一种需要硬件支持的功能，所以这里有些要求并且需要做一些准备工作。

<!-- more -->

### 硬件 ###

CPU 和主板需要支持 `IOMMU` (I/O Memory Management Unit) 中断重映射。

通常带有 VT-d 的 Intel 平台和带有 AMD-Vi 的 AMD 平台支持此功能。但由于硬件不规范或者没有高质量驱动程序，并不能保证一切都能开箱即用。

此外，服务器级硬件通常比消费级硬件更好的支持这点，但即使如此，许多现代系统也都可以支持这个功能。

请咨询你的硬件供应商，以确定他们是否在 Linux 下支持此功能。

### 配置 ###

一旦确保硬件支持直通，你还需要做一些配置来启用 PCI(e) 直通功能。

#### IOMMU ####

必须在内核命令上激活 IOMMU。最简单的方法是通过 grub 来启用，编辑 `/etc/default/grub`，在 `GRUB_CMDLINE_LINUX_DEFAULT` 变量中加入以下参数：

* Intel 处理器：
{% codeblock %}
intel_iommu=on
{% endcodeblock %}

* AMD 处理器:
{% codeblock %}
amd_iommu=on
{% endcodeblock %}

执行以下命令使修改生效：
```shell
# update-grub
```

#### 内核模块 ####

必须确保加载以下模块，添加以下行到 `/etc/modules` 中来实现。
```
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd
```

{% raw %}<p id="update_initramfs">修改模块后需要刷新 <code>initramfs</code>，在 Proxmox VE 中执行以下命令完成：</p>{% endraw %}
```shell
# update-initramfs -u -k all
```

#### 完成设置 ####

重启服务器使设置生效，并用以下命令检查：
```shell
# dmesg | grep -e DMAR -e IOMMU -e AMD-Vi
```

应该显示 `IOMMU, Directed I/O` 或者 `Interrupt Remapping` 已启用，取决于硬件和内核，详细的消息可能会有所不同。

想要直通的设备位于**单独的** `IOMMU` 组中也很重要。可以通过以下命令检查：
```shell
# find /sys/kernel/iommu_groups/ -type l
```

有些设备（例如带有 HDMI 音频设备的显卡）需要在同一分组以正常工作。

{% blockquote %}
**PCI(e) 插槽**
有些平台处理 PCI(e) 插槽的方式有所不同，如果没有取得想要的 `IOMMU` 分组的话可以尝试把设备插在不同的插槽上。
{% endblockquote %}

{% blockquote %}
**非安全中断**
对于一些平台，有可能需要允许非安全中断。可以在 `/etc/modprobe.d/` 下创建一个以 `.conf` 为扩展名的文件：
{% codeblock %}
options vfio_iommu_type1 allow_unsafe_interrupts=1
{% endcodeblock %}请注意，此选项可能会导致系统不稳定。
{% endblockquote %}

### 显卡直通说明 ###

无法在 Proxmox VE 网页界面上通过 NoVNC 或者 SPICE 来显示显卡的帧缓冲区。

当你直通了显卡并且想获得图形输出时，可以直接把显示器物理连接到显卡上，或者在客户机配置远程桌面工具（例如 VNC 和 RDP）。

而如果你只是用显卡来作为硬件加速器，例如使用 OpenCL 或者 CUDA 的话，就不必须连接到显示器。

## 主机设备直通 ##

最常用的方式是直通一整张 PCI(e) 卡，例如显卡或者网卡。

### 主机配置 ###

这种方式下，主机不可以占用这张。有两种方式来实现：

* 传递设备 IDs 到 `vfio-pci` 模块的选项中，把以下代码
{% codeblock %}
options vfio-pci ids=1234:5678,4321:8765
{% endcodeblock %}
添加到 `/etc/modprobe.d/` 下的一个 `.conf` 为扩展名的文件中。其中设备 IDs 通过以下命令获得：
{% codeblock lang:shell %}
# lspci -nn
{% endcodeblock %}

* 将驱动程序列入主机的黑名单以确保设备可以自由绑定直通，把以下代码
{% codeblock %}
blacklist DRIVERNAME
{% endcodeblock %}
添加到 `/etc/modprobe.d/` 下的一个 `.conf` 为扩展名的文件中。

这两种方式都需要再次 [更新 `initramfs`](#update_initramfs) 并重启主机。

### 虚拟机配置 ###

切换到虚拟机 **硬件** 选项卡，点击 **添加** - **PCI 设备**。
{% asset_img 01-insert-pcie.png 添加 PCI(e) 设备 %}配置好需要的选项，点击 **添加**。

{% raw %}<p id="option_readme">以下是选项说明：</p>{% endraw %}

* 所有功能
如果该设备具有多个功能（例如显卡 `01:00.0` 和 `01:00.1`），勾选此选项会一起传递。

* 主 GPU (`x-vga=on|off`)
标记该设备为虚拟机主显卡，勾选后虚拟机将会忽略配置中的 **显示** 选项。

* PCI-Express (`pcie=on|off`)
告诉 Proxmox VE 使用 PCIe 还是 PCI 端口。一些设备组合需要 PCIe 而非 PCI。PCIe 只在 `q35` 机型上有效。

* ROM-Bar (`rombar=on|off`)
使固件 ROM 对客户机可见。默认已勾选，有些 PCI(e) 设备需要禁用。

也可以通过命令行，在虚拟机配置中设置 `hostpciX` 选项：
```shell
# qm set <VMID> -hostpci0 01:00.0
```
有些参数可能需要设置，见上述 [选项说明](#option_readme)，额外有一个 `romfile=<path>` 参数，可以指定设备使用的 ROM 文件，参数值为 `/usr/share/kvm/` 的相对路径。

#### 举例 ####

以下是把显卡直通为虚拟机主显卡的设置：
```shell
# qm set <VMID> -hostpci0 01:00,x-vga=1,pcie=1
```

### 注意事项 ###

当直通显卡时，为了达到最高兼容性，请使用 `q35` 作为机器类型，BIOS 使用 `OVMF (EFI)` 替换 `SeaBIOS`，并勾选 PCI-Express。注意，如果想使用 `OVMF` 来直通显卡，那么显卡需要有一个 EFI 兼容的 ROM，否则请选择 `SeaBIOS`。
