kvm硬件直通 核显 蓝牙 usb 板载声卡

现在完成了一个 macos+ win10的双系统 vm https://dev.leiyanhui.com/kvm/macos_add_win10/
并且 整理了一个可以基本启动的macos 和 win的脚本 start_bash_macos_win.sh

arch+kvm的安装 看文末链接

# usb 和蓝牙的直通

usb直通 是最简单的,所以先处理usb的直通

SPICE 可以把控制机的usb通过网络穿透给受控虚拟机,这个可以看arch的wike 这里主要是宿主机的直通

需要用 lsusb命令

1
sudo pacman -S usbutils 

运行 lsusb

Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 006: ID 05ac:821f Apple, Inc. Built-in Bluetooth 2.0+EDR HCI
Bus 001 Device 003: ID 0a5c:4500 Broadcom Corp. BCM2046B1 USB 2.0 Hub (part of BCM2046 Bluetooth)
Bus 001 Device 002: ID 093a:2510 Pixart Imaging, Inc. Optical Mouse
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

数字分别对应 标识“ host_bus host_addr vendor_id product_id”。
直通蓝牙 和 Mouse 给虚拟机,有两种方式,第一种是 按照设备id 第二种是直接把usb指定的接口直通给虚拟机。 建议用接口方式。这样指定的接口还可以热拔插
例如 usb 鼠标 是hostbus1 hostaddr:002 蓝牙是 hostbus1 hostaddr:006 编辑脚本

1
cp base-win.sh  base-win-usb.sh && nano base-win-usb.sh

-device usb-ehci,id=ehci 后添加行 id=qxhci 这个名字不能有重复的

1
-device qemu-xhci,id=qxhci -device usb-host,bus=qxhci.0,hostdevice=/dev/bus/usb/001/002 \

这样,无论当前插鼠标的usb接口插入什么设备 都会直通给虚拟机(注意 usb2 和 usb3 对应的host_addr 是不同的,如果分别插入分别获取一次host_addr都直通进去才可以同一个接口 同时支持usb2和usb3) 操作的时候 会有权限问题,可能需要 sudo sh base-win-usb.sh 不是很安全,如果要解决这个问题,可以查看arch关于udev的wiki

鼠标测试成功,用同样的方法添加的时候,我发现ID 05ac:821f Apple, Inc. Built-in Bluetooth 2.0+EDR HCI 这个设备的Device id/host_addr会变化 所以直接用设备的id

添加 port=XXX 参数,鼠标口直接绑定,蓝牙用vendorid 和 productid绑定

1
2
3
-device qemu-xhci,id=qxhci -device usb-host,port=1,bus=qxhci.0,hostdevice=/dev/bus/usb/001/002 \
-device usb-host,port=2,bus=qxhci.0,vendorid=0x0a5c,productid=0x4500 \
-device usb-host,port=3,bus=qxhci.0,vendorid=0x05ac,productid=0x821f \

最终完整文件 https://github.com/joyanhui/file.leiyanhui.com/blob/main/pve-unraid-kvm/base-win-usb-bluetooth.sh

因为是已经安装好的 win,所以一直动他主板设备,可能会遇到蓝屏问题。这个是win的问题,不用管他,正常启动过一次 以后不改这些参数 就不会有问题

# 核显 独显和其他pice设备的直通

# 启用IOMMU

确认宿主机BIOS里面打开了VT-d/VT-x/VT-i等所有硬件虚拟化支持开关 打开Linux操作系统的iommu开关,在grub启动命令行里面配置,Intel CPU和AMD CPU配置参数有区别:Intel CPU: intel_iommu=on;AMD CPU: amd_iommu=on 重启服务器,检查iommu配置是否生效(dmesg | grep -i iommu,输出“Intel-IOMMU: enabled”表示生效)

sudo nano /etc/default/grub 编辑GRUB_CMDLINE_LINUX_DEFAULT="... intel_iommu=on ..."

另外一个参数 iommu=pt,这将防止Linux试图接触(touching)无法直通的设备。 不确定是否是必须的

更新一下 grub,

1
2
3
sudo grub-install /dev/nvme0n1    #(注意,不是efi分区,而且是整个磁盘)
sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo reboot

重启 后检查一下,如果没有下面的分组,信息,那就是 bios的 vt-d 没打开,去打开

cat /etc/default/grub

sudo dmesg | grep -i iommu
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-linux root=UUID=7ecb4d27-3d12-9d47-ab75-ba39b6fbe737 rw loglevel=3 quiet intel_iommu=on
[    0.038327] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-linux root=UUID=7ecb4d27-3d12-9d47-ab75-ba39b6fbe737 rw loglevel=3 quiet intel_iommu=on
[    0.038385] DMAR: IOMMU enabled
[    0.092270] DMAR-IR: IOAPIC id 2 under DRHD base  0xfed91000 IOMMU 1
[    0.292307] iommu: Default domain type: Translated
[    0.292309] iommu: DMA domain TLB invalidation policy: lazy mode
[    0.320110] DMAR: IOMMU feature fl1gp_support inconsistent
[    0.320111] DMAR: IOMMU feature pgsel_inv inconsistent
[    0.320112] DMAR: IOMMU feature nwfs inconsistent
[    0.320113] DMAR: IOMMU feature pasid inconsistent
[    0.320114] DMAR: IOMMU feature eafs inconsistent
[    0.320114] DMAR: IOMMU feature prs inconsistent
[    0.320115] DMAR: IOMMU feature nest inconsistent
[    0.320116] DMAR: IOMMU feature mts inconsistent
[    0.320116] DMAR: IOMMU feature sc_support inconsistent
[    0.320117] DMAR: IOMMU feature dev_iotlb_support inconsistent
[    0.320347] pci 0000:00:00.0: Adding to iommu group 0
[    0.320357] pci 0000:00:02.0: Adding to iommu group 1
[    0.320367] pci 0000:00:14.0: Adding to iommu group 2
[    0.320373] pci 0000:00:17.0: Adding to iommu group 3
[    0.320384] pci 0000:00:1c.0: Adding to iommu group 4
[    0.320392] pci 0000:00:1c.5: Adding to iommu group 5
[    0.320400] pci 0000:00:1c.6: Adding to iommu group 6
[    0.320408] pci 0000:00:1c.7: Adding to iommu group 7
[    0.320416] pci 0000:00:1d.0: Adding to iommu group 8
[    0.320431] pci 0000:00:1f.0: Adding to iommu group 9
[    0.320437] pci 0000:00:1f.2: Adding to iommu group 9
[    0.320444] pci 0000:00:1f.3: Adding to iommu group 9
[    0.320451] pci 0000:00:1f.4: Adding to iommu group 9
[    0.320460] pci 0000:01:00.0: Adding to iommu group 10
[    0.320468] pci 0000:02:00.0: Adding to iommu group 11
[    0.320476] pci 0000:05:00.0: Adding to iommu group 12
[    0.378552] AMD-Vi: AMD IOMMUv2 functionality not available on this system - This is not a bug.
[    2.573917] pci 0000:00:1f.1: Adding to iommu group 13
[    2.574294] pci 0000:00:1f.1: Removing from iommu group 13

# 查看pice情况

sudo nano /mnt/ssd/print_IOMMU.sh 内容

#!/bin/bash
shopt -s nullglob
for d in /sys/kernel/iommu_groups/*/devices/*; do 
    n=${d#*/iommu_groups/*}; n=${n%%/*}
    printf 'IOMMU Group %s ' "$n"
    lspci -nns "${d##*/}"
done;

sudo sh print_IOMMU.sh 查看所有pice设备

IOMMU Group 0 00:00.0 Host bridge [0600]: Intel Corporation 8th Gen Core Processor Host Bridge/DRAM Registers [8086:3ec4] (rev 07)
IOMMU Group 1 00:02.0 VGA compatible controller [0300]: Intel Corporation CoffeeLake-H GT2 [UHD Graphics 630] [8086:3e9b]
IOMMU Group 10 01:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 0c)
IOMMU Group 11 02:00.0 Network controller [0280]: Broadcom Inc. and subsidiaries BCM43224 802.11a/b/g/n [14e4:4353] (rev 01)
IOMMU Group 12 05:00.0 Non-Volatile memory controller [0108]: KIOXIA Corporation NVMe SSD [1e0f:0009] (rev 01)
IOMMU Group 2 00:14.0 USB controller [0c03]: Intel Corporation 100 Series/C230 Series Chipset Family USB 3.0 xHCI Controller [8086:a12f] (rev 31)
IOMMU Group 3 00:17.0 SATA controller [0106]: Intel Corporation Q170/Q150/B150/H170/H110/Z170/CM236 Chipset SATA Controller [AHCI Mode] [8086:a102] (rev 31)
IOMMU Group 4 00:1c.0 PCI bridge [0604]: Intel Corporation 100 Series/C230 Series Chipset Family PCI Express Root Port #5 [8086:a114] (rev f1)
IOMMU Group 5 00:1c.5 PCI bridge [0604]: Intel Corporation 100 Series/C230 Series Chipset Family PCI Express Root Port #6 [8086:a115] (rev f1)
IOMMU Group 6 00:1c.6 PCI bridge [0604]: Intel Corporation 100 Series/C230 Series Chipset Family PCI Express Root Port #7 [8086:a116] (rev f1)
IOMMU Group 7 00:1c.7 PCI bridge [0604]: Intel Corporation 100 Series/C230 Series Chipset Family PCI Express Root Port #8 [8086:a117] (rev f1)
IOMMU Group 8 00:1d.0 PCI bridge [0604]: Intel Corporation 100 Series/C230 Series Chipset Family PCI Express Root Port #9 [8086:a118] (rev f1)
IOMMU Group 9 00:1f.0 ISA bridge [0601]: Intel Corporation B150 Chipset LPC/eSPI Controller [8086:a148] (rev 31)
IOMMU Group 9 00:1f.2 Memory controller [0580]: Intel Corporation 100 Series/C230 Series Chipset Family Power Management Controller [8086:a121] (rev 31)
IOMMU Group 9 00:1f.3 Audio device [0403]: Intel Corporation 100 Series/C230 Series Chipset Family HD Audio Controller [8086:a170] (rev 31)
IOMMU Group 9 00:1f.4 SMBus [0c05]: Intel Corporation 100 Series/C230 Series Chipset Family SMBus [8086:a123] (rev 31)

我这里需要直通 核显 [UHD Graphics 630] [8086:3e9b] wifi BCM43224 802.11a/b/g/n [14e4:4353] 声卡 HD Audio Controller [8086:a170]

# 隔离设备

为了将设备分配给虚拟机,直通的设备和同在一个IOMMU组的所有设备必须将驱动程序更换为 stub 或是 vfio ,以防止宿主机尝试与其交互。对于大多数设备,在虚拟机启动时就可以完成这项工作。 但是核显不行,独显也不行,所以需要隔离掉。

# 通过设备ID绑定vfio-pci

如果是独显可能需要同时绑定独显上的HDMI声卡和gpu ,但是我没有独显,也没有支持HDMI音频的显示器,所以我这里只绑定核显[8086:3e9b]

1
2
3
sudo nano /etc/modprobe.d/vfio.conf
#============
options vfio-pci ids=8086:3e9b

如果还要直通wifi,声卡不打算直通,改为穿透

1
options vfio-pci ids=8086:3e9b,14e4:4353

重新生成initramfs sudo mkinitcpio -P

# 可能还需要 提前加载vfio-pci

因为Arch的linux内核将vfio-pci作为一个模块,我们需要强迫vfio-pci在显卡驱动抢占硬件之前加载。为了达成这一目的,我们向mkinitcpio中添加 vfio_pci, vfio, vfio_iommu_type1, vfio_virqfd: 这步 和 pve的黑名单差不多 意思

# mkinitcpio

sudo nano /etc/mkinitcpio.conf

1
MODULES=(... vfio_pci vfio vfio_iommu_type1 vfio_virqfd ...)

# 黑名单

sudo nano /etc/modprobe.d/blacklist.conf
1
2
3
blacklist i915
blacklist snd_hda_intel
blacklist snd_hda_codec_hdmi

snd_hda_intel 是声卡,如果不要直通这个地方 不要添加,snd_hda_codec_hdmi是核显的hdmi声卡

# booster

sudo nano /etc/booster.yaml

modules_force_load: vfio_pci,vfio,vfio_iommu_type1,vfio_virqfd

# dracut

1
2
sudo mkdir /etc/dracut.conf.d
sudo nano  /etc/dracut.conf.d/10-vfio.conf
1
force_drivers+=" vfio_pci vfio vfio_iommu_type1 vfio_virqfd "

# 防止部分游戏蓝屏,以及macos无限重启

1
2
3
sudo nano  /etc/modprobe.d/kvm.conf
-------
options kvm ignore_msrs=Y

重新生成initramfs sudo mkinitcpio -P 提示几个 WARNING: Possibly missing firmware for module 不用管他,大致是物理机器缺少驱动的问题

然后重启

# 重启后检查

重启后屏幕 过了grub后,显示startging versinon XXX.X-X-arch 后 屏幕就不再有输出,有时候 还可能会黑屏或者提示没信号,这是正常的,因为 我们没让arch接触显卡了

重启后重新检查 sudo dmesg | grep -i iommu

应该有 IOMMU enabled

sudo dmesg | grep -i vfio

[    1.324935] VFIO - User Level meta-driver version: 0.3
[    1.344914] vfio-pci 0000:00:02.0: vgaarb: deactivate vga console
[    1.344917] vfio-pci 0000:00:02.0: vgaarb: changed VGA decodes: olddecodes=io+mem,decodes=io+mem:owns=io+mem
[    1.345002] vfio_pci: add [8086:3e9b[ffffffff:ffffffff]] class 0x000000/00000000
[    1.345117] vfio_pci: add [14e4:4353[ffffffff:ffffffff]] class 0x000000/00000000

lspci -k 检查一下 或者 lspci -k | grep -i -e Intel -A 3 lspci -k | grep -i -e Audio -A 3

lspci -nnk -d 8086:3e9b

00:02.0 VGA compatible controller [0300]: Intel Corporation CoffeeLake-H GT2 [UHD Graphics 630] [8086:3e9b]
DeviceName:  Onboard IGD
Subsystem: Gigabyte Technology Co., Ltd Device [1458:d000]
Kernel driver in use: vfio-pci
Kernel modules: i915

# 尝试直通 核显

cd  /mnt/ssd/vm-shell/

cp base-win-usb.sh gpu-win-usb.sh && nano gpu-win-usb.sh

添加行-device vfio-pci,host=0000:00:02.0,addr=0x02,x-igd-opregion=on \ 屏幕有反应,但是一会还是无信号,不确定是否需要vbios先登录到win,用系统更新自动安装驱动试试看看,驱动装完后 依旧黑屏。

去弄vbois文件,因为我这个uhd630 很常见,有人弄好了,之前在kvm和unraid 都测试过没问题,所以直接拿来用

cd  /mnt/ssd/
wget https://file.leiyanhui.com/pve-unraid-kvm/vbios_gvt_uefi.rom

修改上面的参数,同时发现 插槽01 和02 01被VMware显卡用 02被网卡用了 所以把 网卡的改到04 显卡继续用02 02这个位置 就是多数电脑的核显的固定位置

1
-device vfio-pci,host=0000:00:02.0,addr=0x02,x-igd-opregion=on,romfile=/mnt/ssd/vbios_gvt_uefi.rom \

顺利点亮,qemu有提示 “IGD device 0000:00:02.0 cannot support legacy mode due to existing devices at address 1f.0” 说明是用了UPT 直通模式而不是Legacy

主机类型用pc 也就是 pc-i440fx-7.1 然后vnc那个设置为none 就没有这个提示,可以用Legacy 模式输出 ,但是物理显示屏也是没法显示出来 用户登录之前的画面。

但是我看了qemu的源码 好像 是q35禁用了Legacy 模式

vnc/spice 在登录的时候黑屏,但登录后,两个屏幕都可以显示。 但是因为前面加了鼠标穿透,导致vnc的屏幕鼠标 穿透到物理屏幕导致 vnc屏幕只能观看 无法用控制机的鼠标操作。这个问题后来发现可以通过调整设备的顺序解决 实例代码:查看我的

# 核显和其他pci直通的另外一个写法
1
2
3
-device pcie-root-port,bus=pcie.0,multifunction=on,port=1,chassis=1,id=port.1 \
-device vfio-pci,host=0000:00:02.0,bus=port.1,addr=0x02,x-igd-opregion=on,x-igd-gms=1,romfile=/mnt/ssd/vbios_gvt_uefi.rom \
-device vfio-pci,host=0000:02:00.0,bus=port.1 \

# 添加直通wifi

这个很简单,前面vfio之后这里添加一行 就可以了

1
-device vfio-pci,host=02:00.0 \

# 声卡直通

声卡和其他一堆设备在一个组里面 还是比较麻烦的。单独记录 查看这里:https://dev.leiyanhui.com/kvm/sound-pass/

# 直通了 核显 wifi usb 蓝牙 的一个win虚拟机启动脚本

注意 smb功能需要宿主机安装samba sudo pacman -S samba https://github.com/joyanhui/file.leiyanhui.com/blob/main/pve-unraid-kvm/win-gpu-usb-wifi-bt-vnc-no-sound.md

存在的问题

  • vnc显卡的鼠标不可以用,会穿透到物理屏幕。键盘也穿透过去了。因为vnc屏幕定位还是调试用,后期也尝试macos所以 此问题可能以后才会去研究(已经解决看后面的脚本)
  • 物理屏幕不会显示kvm的bois引导界面,要等到Windows登录界面之前 才会点亮。
  • Q35 机型会提醒IGD核显不能用传统模式 换到pc-i440fx-7.1 模式,vnc 设置none 没有提醒。物理屏依旧不会显示kvm的启动信息,所以没啥区别。
  • 声卡直通和映射有坑没解决,没有pve下那么容易,远程用的话 Windows 下 rdp协议可以直接把声音传递到控制机。 macos下还没研究xrdp和其他协议。

# 另外一个解决了vnc鼠标问题的脚本

https://github.com/joyanhui/file.leiyanhui.com/blob/main/pve-unraid-kvm/win-gpu-usb-wifi-bt-vnc-spice-smb-no-sound.sh

# macos efi

  • 蓝牙可用
  • 鼠标键盘 usb 也可以用
  • 以太网可用
  • smb 到宿主机 可用
  • 但是有别的一点问题 需要自定义oc的efi
  • spice 声卡不可用
  • 没有直通核显

留个坑,慢慢填

本文参考:https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87) https://github.com/patmagauran/i915ovmfPkg/issues/8

# kvm 进阶和相关小问题处理

查看这里 https://dev.leiyanhui.com/kvm/all_list/

# 我的kvm脚本参考

https://github.com/joyanhui/file.leiyanhui.com/tree/main/pve-unraid-kvm

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计