UP | HOME

双显卡笔记本独显直通

目录

介绍

双显卡笔记本中直通独显(dGPU)到 win10 虚拟机。

环境:

  • 联想 Legion R7000P 2020 笔记本
  • RTX2060 笔记本显卡
  • libvirt+qemu
  • Host: Gentoo Linux
  • Guest: Windows 10 LTSC 2019

MUXed

MUXed 结构的笔记本才容易实现独立显卡直通,Legion R7000P 应该就是 MUXed 的。关于什么是 MUXed 的,可以看下图的解释。

muxed.jpg

关于如何检测笔记本是否是 MUXed 的,目前没有什么好的办法。有一种说法是运行 lspci,查找有关 Intel HD Graphics/AMD GPU 和 NVIDIA 的设备:

  • 如果独显设备名以 3D Controller 开头,那你的电脑就是第二种 MUXless(核显直连显示器)。
  • 如果独显设备名以 VGA Controller 开头,并且有一个 HD Graphics/AMD GPU 核显,那你的电脑是第三种 MUXed(核显、独显切换)。

启用 IOMMU 和 vfio 模块

IOMMU

  • intel CPU:添加内核参数 intel_iommu=on iommu=pt ,BIOS 开启 VT-d
  • amd CPU:添加内核参数 iommu=pt ,BIOS 开启 AMD-Vi

vfio

添加模块 vfio_pci vfio vfio_iommu_type1 vfio_virqfd 到 initramfs 中。如果是像我一样使用 dracut 生成 initramfs,则在 /etc/dracut.conf 中添加配置 add_drivers+=" vfio_pci vfio vfio_iommu_type1 vfio_virqfd " ,之后重新生成 initramfs。

隔离 GPU

#!/bin/bash
shopt -s nullglob
for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
    echo "IOMMU Group ${g##*/}:"
    for d in $g/devices/*; do
        echo -e "\t$(lspci -nns ${d##*/})"
    done;
done;

运行上述脚本,查看显卡所在的 IOMMU Group,并得到显卡相关设备的 device id。

IOMMU Group 10:
        01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU106M [GeForce RTX 2060 Mobile] [10de:1f15] (rev a1)
        01:00.1 Audio device [0403]: NVIDIA Corporation TU106 High Definition Audio Controller [10de:10f9] (rev a1)
        01:00.2 USB controller [0c03]: NVIDIA Corporation TU106 USB 3.1 Host Controller [10de:1ada] (rev a1)
        01:00.3 Serial bus controller [0c80]: NVIDIA Corporation TU106 USB Type-C UCSI Controller [10de:1adb] (rev a1)

如上所见,device id 分别为 10de:1f1510de:10f910de:1ada10de:1adb 。再将以上 deivce id 作为参数添加到内核参数或 /etc/modprobe.d/vfio.conf 中。

  • 内核参数:vfio-pci.ids=10de:1f15,10de:10f9,10de:1ada,10de:1adb
  • /etc/modprobe.d/vfio.conf :options vfio-pci ids=10de:1f15,10de:10f9,10de:1ada,10de:1adb

dracut 必须将 device id 添加到内核参数中,并且添加参数 rd.driver.pre=vfio_pci

最后重启电脑。开机后通过命令 lspci -k 确认上述 device id 对应的设备在使用 vfio-pci 驱动。如果有各别设备没有使用 vfio-pci 驱动,则可以通过手动 unbind 和 bind 驱动的方式加载 vfio-pci 驱动。比如如果 0000:01:00.2 仍在使用 xhci_hcd 驱动,则:

# run as root
echo -n "0000:01:00.2" > /sys/bus/pci/drivers/xhci_hcd/unbind
echo -n "0000:01:00.2" > /sys/bus/pci/drivers/vfio-pci/bind

创建虚拟机

首先使用 libvirt 创建一个非显卡直通的虚拟机,如果你有多余的显示器和键鼠,也可以直接创建显卡直通的虚拟机。这里我们假设没有多余的设备,并且之后使用 RDP 连接虚拟机。

首先下载windows 10 LTSC 2019virtio windows驱动镜像。

创建虚拟机:

  • Overview :Firmware 选择 UEFI x86_64:/usr/share/edk2-ovmf/OVMF_CODE.fd
  • CPUs :选择 Topology,Manually set CPU topology,Sockets 设为 1,Cores 按需要来,我设为 4,Threads 设置为 2。这样一共就分配了 4 核 8 线程的 CPU
  • Memory :内存我设置为 32G
  • SATA Disk :Disk Bus 选择 Virtio,可以最小化磁盘性能损耗
  • NIC :Device model 也选择 virtio
  • 之后再添加一个 Stroage ,选择 Select custom storage 并选中之前下载的 virtio windows 驱动镜像,然后 Device type 选择 CDROM device
  • 最后在 Boot Options 中选中需要启动的设备

开始安装,在 windows 安装进行到选择硬盘的时候,通过之前加载的 virtio win 驱动的 CDROM,安装 virtio 的磁盘和网络驱动。具体参考可见视频 https://www.bilibili.com/video/BV1dQ4y1o78R 的 29 分 35 秒。安装完毕进入 windows,开启远程桌面并记下 IP,之后通过 RDP 连接虚拟机。

配置和优化 RemoteFX

配置 RemoteFX

  1. 通过 Win+R 运行 gpedit.msc
  2. 定位到 计算机配置 -> 管理模板 -> Windows组件 -> 远程桌面服务 -> 远程桌面会话主机 -> 远程会话环境
    • 开启 对 RemoteApp 使用高级 RemoteFX 图形
    • (可选)开启 配置 RemoteFX 自适应图形的图像质量 ,设置为高
    • 开启 为专门针对 Windows Server 2008 R2 SP1 设计的 RemoteFX 客户端启动 RemoteFX 编码
    • 开启 配置 RemoteFX 数据的压缩 ,并设置为不需使用 RDP 压缩算法
      • 连接压缩会导致编码和解码时产生额外的延迟
  3. 定位到 计算机配置 -> 管理模板 -> Windows组件 -> 远程桌面服务 -> 远程桌面会话主机 -> 远程会话环境 -> RemoteFX for Windows Server 2008 R2
    • 开启 配置RemoteFX
    • (可选)开启 使用RemoteFX时优化视觉体验 ,并都设置为最高

解除 30-ish fps 限制

  1. 启动注册表编辑器
  2. 定位并单击以下注册表子键: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations
  3. 编辑 菜单中选择 新建 ,然后再选择 DWORD(32位)值
  4. 输入 DWMFRAMEINTERVAL 并回车
  5. 右键 DWMFRAMEINTERVAL ,选择 修改
  6. 选择十进制,并输入 15。该设置将最大帧率设置为每秒 60 帧 (FPS)。

显卡直通

先关闭虚拟机。首先我们需要确认 host 和 guest 中的 GPU 硬件 ID 一致的,然而 Legion R7000P 中两者不一致,准确的来说是其中的 Sub ID 部分不一致,所以需要手动修改一下。首先通过命令 lspci -nnk | egrep -A3 "VGA|3D" 查看显卡的 Vendor ID 和 Device ID。

➜ lspci -nnk | egrep -A3 "VGA|3D"
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU106M [GeForce RTX 2060 Mobile] [10de:1f15] (rev a1)
        Subsystem: Lenovo TU106M [GeForce RTX 2060 Mobile] [17aa:3a43]
        Kernel driver in use: vfio-pci
        Kernel modules: nouveau
--
06:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Renoir [1002:1636] (rev c6)
        Subsystem: Lenovo Renoir [17aa:3a47]
        Kernel driver in use: amdgpu
        Kernel modules: amdgpu

其中 NVIDIA 独显的 Vendor ID 为 10de,Device ID 为 1f15。再用命令 grep "PCI_SUBSYS_ID=" /sys/bus/pci/devices/0000:01:00.0/uevent 查看 Sub Vendor ID 和 Sub Device ID。

➜ grep "PCI_SUBSYS_ID=" /sys/bus/pci/devices/0000:01:00.0/uevent
PCI_SUBSYS_ID=17AA:3A47

其中 Sub Vendor ID 为 17AA,Sub Device ID 为 3A47。将 17AA 和 3A47 转换为十进制 6058 和 14919,并在虚拟机的 XML 中添加配置:

<domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0" type="kvm">
  ...
  <qemu:commandline>
    <qemu:arg value='-set'/>
    <qemu:arg value='device.hostdev0.x-pci-sub-vendor-id=6058'/>
    <qemu:arg value='-set'/>
    <qemu:arg value='device.hostdev0.x-pci-sub-device-id=14919'/>
  </qemu:commandline>
</domain>

注意 XML 的第一行一定要添加 xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0" ,否则后面的配置无法成功添加。

在 libvirt 中添加硬件,选择 PCI Host Device,然后将 0000:01:00.0 NVIDIA Corporation GeForce RTX 2060 Mobile0000:01:00.1 NVIDIA Corporation High Definition Audio Controller 等都添加进去。

最后再在 libvirt 中删除虚拟机的 Display SpiceVideo QXL ,在 CPUs 中取消 Copy host CPU configuration 并将 Model 选择为 host passthrough。如果你需要直通鼠标和键盘,也可以在这个时候添加。

创建网桥

有线网卡的网桥创建起来较为简单,这里就不详细介绍了,有需要的可以查看我上一篇软路由虚拟机的 BLOG。因为是笔记本,所以这里主要介绍无线网卡的桥接方法。

先开启 proxy_arp 和 ip_forward,修改配置文件 /etc/sysctl.conf ,添加下述配置:

net.ipv4.ip_forward = 1
net.ipv4.conf.all.proxy_arp = 1

再点击 libvirt 菜单栏上的 Edit -> Connection Details ,假设 host 的 ip 为 192.168.3.12,无线网卡为 wlp4s0,新建一个 Network, Name 设置为 proxyArp, Mode 选择 Routed, Forward to 选择 Physical device, Device 设置为 wlp4s0, IPv4 的 Network 设置为 192.168.3.100/28,完成创建。

然后修改 win10 虚拟机的 NIC 配置,将 Network source 改为 Virtual network 'proxyArp': Route to wlp4s0,最后重新启动虚拟机与物理机。

远程连接

重新启动虚拟机后,使用 RDP 连接到虚拟机中。到 nvidia 官网下载驱动,并进行安装。如果安装过程中并未出现问题,则至此显卡直通配置完成。另外如果不外接显示器的话,windows 的分辨率似乎会被限制在 640x480,不知道会不会对游戏有影响,所以有条件还是买一个 HDMI 欺骗器接到独显连接的显示接口上。

远程连接方式一共有三种,分别可以适用于不同的情况。

RDP

简单使用方法:

  • 确保使用 FreeRDP 2.0
  • 获取 windows 虚拟机 IP,比如 192.168.3.108
  • xfreerdp /v:192.168.3.108:3389 /w:1600 /h:900 /bpp:32 +clipboard +fonts /gdi:hw /rfx /rfx-mode:video /sound:sys:pulse +menu-anims +window-drag

对于使用 xfreedp 的 RemoteFX 连接的一些问题:

  • 只有窗口化的游戏可以运行,全屏将会触发 d3d11 0x087A0001 不能设置分辨率等问题。媒体播放器不受其影响。
    • 作为解决方案,使用无边框模式游戏,或其他等效方案
    • windows 客户端似乎没有该问题
  • 由于 RDSH/RDVH 连接不支持“相对”鼠标,鼠标会乱跑
    • 重定向 XBOX 手柄或 USB 摇杆可能会解决这个问题?
    • 使用 Synergy (v1) 并启用相对鼠标模式
    • 通过 RDP RemoteFX 运行 3D 游戏鼠标不稳定

Looking glass

Looking glass 的优点是低延迟,其并不是通过网络与虚拟机通信,而是直接使用一块共享内存。缺点是只能本地连接,而且似乎需要外接一个显示设备(或 HDMI 欺骗器)才能让键盘、鼠标正常工作,并且似乎不能使用 spice 套娃远程操作 looking glass。

安装 client

首先在 host 系统上安装 looking glass client,在 gentoo 上可以通过如下步骤直接安装我打包的 looking glass。

sudo eselect repository enable gig
sudo emerge --sync gig
sudo emerge -avt looking-glass

计算内存大小

通过以下公式,根据你期望的最大分辨率来计算内存大小。

width x height x 4 x 2 = total bytes

total bytes / 1024 / 1024 = total megabytes + 10

比如,我想要最大使用 4K 分辨率(3840x2160):

3840 x 2160 x 4 x 2 = 66355200 bytes

66355200 / 1024 / 1024 = 63.28 MB + 10 = 73.28

最后要注意内存的大小要上向取整到最接近的 2 的幂,在上面的例子中则应为 128。

配置 libvirt

...
<devices>
    ...
  <shmem name='looking-glass'>
    <model type='ivshmem-plain'/>
    <size unit='M'>128</size>
  </shmem>
</devices>
...

将以上内容添加到虚拟机的 XML 配置中,其中 128 即为上面计算出来的大小。

如果想要通过 spice 实现键盘和鼠标输入与剪贴板共享,则必须添加 spice 设备。

  • 在 libvirt 中,选择 Add Hardware ,然后再选择 Graphics ,使用默认的 spice 配置即可,最后完成添加
  • 选择 Video 设备,然后在 Model 栏中输入 none,注意必须要完成这一步,否则可能会造成虚拟机不使用直通的显卡渲染
  • 如果有 tablet 设备,则删除
  • 如果没有 Mouse 设备,则添加一个
  • 如果没有 Keyboard 设备,则添加一个
    • 这里使用 Virtio 的键盘可以更好的提高性能,然而 PS/2 的键盘没办法删掉,不知道被哪个设备依赖了,所以就使用 PS/2 的键盘了
    • 还有如果使用 Virtio 的键盘,则需要通过上面加载的 virtio windows 驱动 的 CDROM,以安装驱动

创建共享内存文件

新建文件 /etc/tmpfiles.d/10-looking-glass.conf ,其内容为:

#Type Path               Mode UID  GID Age Argument
f /dev/shm/looking-glass 0660 user kvm -

将其中的 user,改为你自己的用户名。最后使用命令 systemd-tmpfiles --create /etc/tmpfiles.d/10-looking-glass.conf 创建共享内存文件,无需等待下次重启。

安装 host

首先需要在 windows 中安装 IVSHMEM 驱动,windows 不会自己安装 IVSHMEM 设备,相反它只会为该设备安装一个假驱动。先下载需要安装的驱动程序,https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/upstream-virtio/ ,注意必须下载 0.1.161 或更高的版本,最后将其解压。

安装 IVSHMEM 驱动需要打开 设备管理器 ,然后在 系统设备 下,找到 PCI标准内存控制器 ,然后选择 更新驱动程序 ,再选择手动更新,选择我们之前下载并解压好的驱动目录,然后安装驱动即可。

host 需要在 windows 虚拟机中安装,先下载与 client 版本对应的 host 安装文件:https://looking-glass.io/downloads 。下载完成后解压、安装即可,完成后重启虚拟机,然后通过 log 文件查看其是否正常启动,log 在开始菜单里就有。

最后再安装一下 spice guest tools, https://www.spice-space.org/download.html#windows-binaries ,以更好的支持鼠标与剪贴板共享。

配置 client

我使用的配置如下,将配置文件放在 ~/.looking-glass-client.ini/etc/looking-glass-client.ini

[app]
renderer=egl
shmFile=/dev/shm/looking-glass

[win]
borderless=yes
fullScreen=yes
size=1920x1080

[input]
grabKeyboard=yes
escapeKey=97

[spice]
captureOnStart=yes

由于我的笔记本没有 ScrLk 按键,所以将 escape 键设置为了 右 Ctrl 按键。

至此 looking glass 配置完成,运行命令 looking-glass-client 连接到虚拟机。

配置 Scream

由于 looking glass 不支持传递音频,所以我们还需要使用 Scream 将 VM 的音频传递给 host。

首先,编辑 windows 虚拟机的 XML,添加以下部分:

...
<devices>
    ...
  <shmem name='scream-ivshmem'>
    <model type='ivshmem-plain'/>
    <size unit='M'>2</size>
  </shmem>
</devices>
...

然后再如 looking glass 一样,添加配置文件 /etc/tmpfiles.d/11-scream-ivshmem.conf ,并运行命令 systemd-tmpfiles --create /etc/tmpfiles.d/11-scream-ivshmem.conf

f   /dev/shm/scream-ivshmem 0660    user    kvm -

如果没有安装 IVSHMEM 驱动,则需要安装一下,跟上面一样。然后下载 scream 的 windows 驱动,地址: https://github.com/duncanthrax/scream/releases ,解压并进行安装。

再以管理员权限在 CMD 中运行 REG ADD HKLM\SYSTEM\CurrentControlSet\Services\Scream\Options /v UseIVSHMEM /t REG_DWORD /d 2

在 Linux 物理机中安装 scream,然后创建配置文件 ~/.config/systemd/user/scream-ivshmem-pulse.service

[Unit]
Description=Scream IVSHMEM pulse receiver
After=pulseaudio.service
Wants=pulseaudio.service

[Service]
Type=simple
ExecStartPre=/usr/bin/truncate -s 0 /dev/shm/scream-ivshmem
ExecStartPre=/bin/dd if=/dev/zero of=/dev/shm/scream-ivshmem bs=1M count=2
ExecStart=/usr/bin/scream -m /dev/shm/scream-ivshmem

[Install]
WantedBy=default.target

最后运行以下命令即可:

systemctl start --user scream-ivshmem-pulse
systemctl enable --user scream-ivshmem-pulse

这样就配置完成了,在 looing glass 里就可以听到声音了。

steam 远程畅玩(流式传输)

因为 RDP 的限制,像 steam 家庭串流或 Geforce Experience 的方式对游戏来说更为推荐。

如果不想每次串流游戏都输入密码解锁屏幕,则可以通过 RDP 以管理员权限运行 cmd,然后运行以下命令,也可以将其保存为脚本,方便以后使用。注意运行完该命令会立马断开 RDP。

@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$sessionid=((quser $env:USERNAME | select -Skip 1) -split '\s+')[2]; tscon $sessionid /dest:console" 2> UnlockErrors.log

benchmark

简单运行了一下 3dmark 的 Time Spy,做虚拟机的图形性能测试。测试了以下几种情况:

  • win10 + 物理机直接运行,3dmark 得分 6900
  • win10 + 虚拟机显卡直通 + 外接显示器,3dmark 得分 6000
  • win10 + 虚拟机显卡直通 + steam 串流,3dmark 得分 5600
  • win10 + 虚拟机显卡直通 + looking glass,3dmark 得分 5000,并且在加载的时候,画面延迟近 10 秒

由此可见,想要玩游戏,还是最好外接显示器,或者起码使用 steam 串流吧,个人感觉 looking glass 的性能甚至可能没有 RDP 高,但 RDP 无法运行 3dmark,所以无法比较测试。另外这几种情况中,CPU 得分的差距更大,但一般游戏也不会占用过多 CPU 资源,所以这里并没有记录。

PS:win10 + 虚拟机显卡直通 + looking glass + HDMI 欺骗器,3dmark 得分也是 5600,looking glass 的性能有待进一步测试。

参考链接

附录:XML 配置

最后附上我的虚拟机的 XML 配置。

<domain type='kvm' id='1' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
  <name>win10</name>
  <uuid>d5da831a-c1eb-4668-a864-0731557d80a0</uuid>
  <metadata>
    <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
      <libosinfo:os id="http://microsoft.com/win/10"/>
    </libosinfo:libosinfo>
  </metadata>
  <memory unit='KiB'>33554432</memory>
  <currentMemory unit='KiB'>33554432</currentMemory>
  <vcpu placement='static'>8</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64' machine='pc-q35-6.0'>hvm</type>
    <loader readonly='yes' type='pflash'>/usr/share/edk2-ovmf/OVMF_CODE.fd</loader>
    <nvram>/var/lib/libvirt/qemu/nvram/win10_VARS.fd</nvram>
    <bootmenu enable='no'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <hyperv>
      <relaxed state='on'/>
      <vapic state='on'/>
      <spinlocks state='on' retries='8191'/>
    </hyperv>
    <vmport state='off'/>
  </features>
  <cpu mode='host-passthrough' check='partial' migratable='on'>
    <topology sockets='1' dies='1' cores='4' threads='2'/>
  </cpu>
  <clock offset='localtime'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
    <timer name='hypervclock' present='yes'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <pm>
    <suspend-to-mem enabled='no'/>
    <suspend-to-disk enabled='no'/>
  </pm>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/win10.qcow2' index='3'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <boot order='1'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
    </disk>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <source file='/home/petrus/Downloads/iso/cn_windows_10_enterprise_ltsc_2019_x64_dvd_9c09ff24.iso' index='2'/>
      <backingStore/>
      <target dev='sdb' bus='sata'/>
      <readonly/>
      <boot order='2'/>
      <alias name='sata0-0-1'/>
      <address type='drive' controller='0' bus='0' target='0' unit='1'/>
    </disk>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <source file='/home/petrus/Downloads/iso/virtio-win-0.1.185.iso' index='1'/>
      <backingStore/>
      <target dev='sdc' bus='sata'/>
      <readonly/>
      <alias name='sata0-0-2'/>
      <address type='drive' controller='0' bus='0' target='0' unit='2'/>
    </disk>
    <controller type='usb' index='0' model='qemu-xhci' ports='15'>
      <alias name='usb'/>
      <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
    </controller>
    <controller type='sata' index='0'>
      <alias name='ide'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pcie-root'>
      <alias name='pcie.0'/>
    </controller>
    <controller type='pci' index='1' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='1' port='0x10'/>
      <alias name='pci.1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/>
    </controller>
    <controller type='pci' index='2' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='2' port='0x11'/>
      <alias name='pci.2'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/>
    </controller>
    <controller type='pci' index='3' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='3' port='0x12'/>
      <alias name='pci.3'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x2'/>
    </controller>
    <controller type='pci' index='4' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='4' port='0x13'/>
      <alias name='pci.4'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x3'/>
    </controller>
    <controller type='pci' index='5' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='5' port='0x14'/>
      <alias name='pci.5'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x4'/>
    </controller>
    <controller type='pci' index='6' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='6' port='0x15'/>
      <alias name='pci.6'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x5'/>
    </controller>
    <controller type='pci' index='7' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='7' port='0x8'/>
      <alias name='pci.7'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
    </controller>
    <controller type='pci' index='8' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='8' port='0x9'/>
      <alias name='pci.8'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='pci' index='9' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='9' port='0xa'/>
      <alias name='pci.9'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='pci' index='10' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='10' port='0xb'/>
      <alias name='pci.10'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x3'/>
    </controller>
    <controller type='pci' index='11' model='pcie-to-pci-bridge'>
      <model name='pcie-pci-bridge'/>
      <alias name='pci.11'/>
      <address type='pci' domain='0x0000' bus='0x0a' slot='0x00' function='0x0'/>
    </controller>
    <controller type='pci' index='12' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='12' port='0xc'/>
      <alias name='pci.12'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x4'/>
    </controller>
    <controller type='virtio-serial' index='0'>
      <alias name='virtio-serial0'/>
      <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
    </controller>
    <interface type='network'>
      <mac address='52:54:00:9c:b1:61'/>
      <source network='proxyArp' portid='dea4d995-d8d9-408d-ac30-ac45bfd5627e' bridge='virbr1'/>
      <target dev='vnet0'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/0'/>
      <target type='isa-serial' port='0'>
        <model name='isa-serial'/>
      </target>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/0'>
      <source path='/dev/pts/0'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <channel type='spicevmc'>
      <target type='virtio' name='com.redhat.spice.0' state='connected'/>
      <alias name='channel0'/>
      <address type='virtio-serial' controller='0' bus='0' port='1'/>
    </channel>
    <input type='mouse' bus='ps2'>
      <alias name='input0'/>
    </input>
    <input type='keyboard' bus='ps2'>
      <alias name='input1'/>
    </input>
    <graphics type='spice' port='5900' autoport='yes' listen='127.0.0.1'>
      <listen type='address' address='127.0.0.1'/>
      <image compression='off'/>
      <gl enable='no'/>
    </graphics>
    <sound model='ich9'>
      <alias name='sound0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/>
    </sound>
    <audio id='1' type='spice'/>
    <video>
      <model type='none'/>
      <alias name='video0'/>
    </video>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
      </source>
      <alias name='hostdev0'/>
      <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x1'/>
      </source>
      <alias name='hostdev1'/>
      <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x2'/>
      </source>
      <alias name='hostdev2'/>
      <address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x3'/>
      </source>
      <alias name='hostdev3'/>
      <address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/>
    </hostdev>
    <redirdev bus='usb' type='spicevmc'>
      <alias name='redir0'/>
      <address type='usb' bus='0' port='2'/>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
      <alias name='redir1'/>
      <address type='usb' bus='0' port='3'/>
    </redirdev>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
    </memballoon>
    <shmem name='looking-glass'>
      <model type='ivshmem-plain'/>
      <size unit='M'>128</size>
      <alias name='shmem0'/>
      <address type='pci' domain='0x0000' bus='0x0b' slot='0x01' function='0x0'/>
    </shmem>
    <shmem name='scream-ivshmem'>
      <model type='ivshmem-plain'/>
      <size unit='M'>2</size>
      <alias name='shmem1'/>
      <address type='pci' domain='0x0000' bus='0x0b' slot='0x02' function='0x0'/>
    </shmem>
  </devices>
  <seclabel type='dynamic' model='dac' relabel='yes'>
    <label>+77:+77</label>
    <imagelabel>+77:+77</imagelabel>
  </seclabel>
  <qemu:commandline>
    <qemu:arg value='-set'/>
    <qemu:arg value='device.hostdev0.x-pci-sub-vendor-id=6058'/>
    <qemu:arg value='-set'/>
    <qemu:arg value='device.hostdev0.x-pci-sub-device-id=14919'/>
  </qemu:commandline>
</domain>

作者: Petrus.Z

Created: 2021-09-01 Wed 00:38