Project HEDT
首发于Project HEDT
将双系统塞入A4主机:OSX-KVM 显卡直通教程

将双系统塞入A4主机:OSX-KVM 显卡直通教程

原文: luvletter.moe/dual-syst

KVM 是 Linux 上最成熟的虚拟化框架, 结合了 qemu 的虚拟化功能并且充分利用半虚拟化技术, 提供了很强的 IO 性能.
常见的用法有直接调用 qemu commnad, 基于 libvirt(virt manager)/Proxmox 等虚拟化框架即可实现对 KVM 虚拟机的管理.
而常见的黑苹果方法基本都是基于物理硬件进行安装, 这种方案好在原生级别的性能, 但是缺点是对于个别主板硬件的兼容性不佳, 如板载网卡, 声卡等. 特别如果是 CPU 特性存在不兼容情况, 如 ryzen 和 SLK-X 系列, 则需要修改内核, 存在诸多麻烦. 并且目前安装方法教程繁多而且不是很统一, 特别是调教固件这一步问题非常多.
而传统虚拟机黑苹果仅仅只是用了 CPU 虚拟化而未使用 IO 虚拟化, 这就意味着无法在虚拟机中获得显卡加速, 这就让 macOS 的实用性大打折扣.
而随着 vt-d 技术的普及, 外加 Apple 对于 AMD GPU 越来越好的支持(当然也有 eGPU 的更好支持), 并且由于最近两年矿潮大量涌入市场的 Polaris 10/11 和 Vega 显卡, 这就让基于显卡直通的虚拟化特别有性价比.
当然 vt-d 的一个宗旨就是 iommu group 越多越好, 翻译成硬件玩家的术语就是最好有更多的独立 PCIe 接口. 传统的 IO 软件虚拟化, 如 PS/2 USB 键盘和音频这种模拟效率较低, 需要在用户态进行系统调用读取数据, 再通过系统调用输入到 guest OS. 这种缺点就是效率低, 实时性差, 同理基于 libusb 的 USB 重定向也是一样的. 如果你有了独立的 PCIe USB 扩展卡, 那么就能将这整个 PCIe 设备丢进虚拟机, 能获得最高的效率和避开一些问题(如 Hub 是不能被重定向的, 或者 PCH 集成的几个控制器不能被拆分).
所以我的配置如下:

  • Intel Core i7-4860HQ(配置 eDRAM 和 iris pro 5200, 能够缓解 DDR3 带宽较低的影响)
  • 蓝宝石 Z87 Pure Black(有特殊的 mPCIe 的设计, 稍后再提)
  • 蓝宝石 RX470D 4GB ITX (性能基本够用, 主要是能塞进机箱而且便宜)
  • DDR3 1600 8GB2(SODIMM 16GB 单条试过了, 转接不靠谱;专用条上不了, 更不用说 16GB 专用条的稳定性了, 千万别买, 只能说凑合用了)
  • 台达 500W Flex 电源
  • iMac 原装 BCM 3x3 1300Mbps ac 网卡(支持 BT4.1 和 Hand Off)

前期准备

a.准备安装介质

所谓安装介质, 就是安装 U 盘或者光盘, 更抽象的说是安装用的块设备文件. 通常情况下最好是通过现有的 macOS 进行准备, 在 App Store 下载当前版本的 Installer.app 即可进行安装. 参考脚本

准备完成后会获得一个块设备文件, 通常为 .iso/.cdr, 均为 CD 标准的块设备文件. 将这个文件保存下来.

b.准备安装平台

很显然你不能装在空气上. macOS Mojave 的最低需求是 SSE4.2, 这个对于目前到 AVX512 的平台来说已经是十年前的事情了. 一般来说 SNB 之后的 CPU 平台都没问题.

第二个事情是需要主板和 CPU 支持 vt-d(IOMMU) 技术. 虽然99%平台都支持 vt-x, 但是由于芯片组或者固件的原因, vt-d 可能未被启用. 请务必检查平台兼容性, 不然无法做到 PCIe 设备穿透.

内存大于 4GB 即可, 推荐 16GB-32GB.

显卡由于一波矿潮下来, 目前有大量支持良好的 A 卡. 虽然一些 N 卡能够免驱使用, 但是我这里还是强烈不建议使用 N 卡, 实用性和麻烦太多, 即便能用也比 A 卡麻烦. 最新的 Radeon RX590 和 Radeon VII 同样支持. 但是 Ryzen APU 的 Vega 8/10 等不被支持.

存储方面, 如果你的主板支持 NVMe, 那么最好, 这就意味着通过 IOMMU 你的 macOS 虚拟机就获得了一个真实的 PCIe 存储设备, 完全绕过了 Linux 内核, 不过务必要注意 NVMe 设备兼容性, 常见支持最好的是 Samsung 970 Pro/EVO(注意步进). 如果没有, 那么也建议上SATA SSD, 毕竟 SATA SSD 如此便宜.

Handoff/AirDrop 强烈依赖于 BCM 特定(Apple 定制)的网卡, 特别是 Apple Watch 解锁功能. 因此主板上需要一个 mini PCIe/M.2 接口. 注意接口上一定要有 PCIe 链路, mSATA 是不被支持的;其二是最好有 USB(来自 PCIe 1x 的 mPCIe 是没有 USB 的)支持, 通常现在的主板 M.2 x4 接口只有 SATA 和 PCIe. M.2 普通网卡接口/mPCIe 网卡接口一般能正常使用. 特别注意 Z390 等 Intel 最新平台的网卡 M.2 接口采用了 CNVi 链路层, 虽然接口与普通网卡兼容, 但是不能支持普通 PCIe 网卡, 这种设备只能走 PCIe 转接板+USB连线启动. 如果你的主板有独立于网卡且不可拆卸的蓝牙 USB dongle, 请在固件设置中禁用, 不然会让 BCM 蓝牙被禁用.

如果你不在意 handoff, macOS 能驱动一大堆 BCM 网卡和 BCM 芯片的蓝牙, 包括一些 BCM 芯片的万兆网卡. macOS 有标准蓝牙 dongle 驱动的支持, 不过即便能用也有一些问题.

有线网卡上默认的 e1000 就能自动驱动, Realtek 的网卡则需要 patch. 不建议直通千兆网卡. macOS 曾经在 Sierra 之前有 virtio 的支持, 但是现在已经不可用. 万兆网卡务必检查兼容性, 包括对于 SR-IOV 的支持.

同时为了最好的性能, 强烈建议直通 USB 控制器而不是 USB 设备重定向(延迟会大很多). 但是要注意 Intel 平台的 XHCI/EHCI 虽然可以分在不同 IOMMU, 但是实际上都是牵一发动全身, 你为了网卡上的蓝牙(特别是 ITX 平台), 就可能得将所有 USB 接口通入虚拟机中. AMD 的 Ryzen 和 PCH 都有 USB, 所以能够独立转发. 这里的解决方案是通过 PCIe 增加网卡, 比如 PCIe/mPCIe 转 USB 3.0. 但是 mPCIe 转 USB 2.0 和 M.2 转 USB 3.0 均依赖于 PCH 的 USB Bus. 如果需要同时接多个虚拟机可以考虑再添加 USB 扩展卡, 如 ASMedia 的 USB 3.1 gen2 PCIe 扩展卡(USB 3.1 bus 可以直通进 macOS).

声卡上如果你有正常的 A/N/I 卡, 进入系统打 kext patch 就能够获得不错的 HDMI/DP 音频. VoodoHDA 可以用来支持基于 qemu 虚拟的 ich9-hda 声卡, 或者是来自 PCIe 直通的声卡设备. USB redirect 的音频质量比较一般, 和 qemu 模拟的声卡同样有延迟较大的问题. 有的较新的主板配置了 PCIe to PCI bridge, 可以直通以通过 PCI 接入 USB/1394(Firewire)设备, 从而兼容老音频介面.

雷电直通我暂未尝试, 这个需要后续探索.

安装宿主系统

参考教程

宿主系统选择上尽可能选择内核新, 软件包新, 且比较稳定的发行版, 如 Arch Linux(文档多), OpenSUSE, Ubuntu. 一般不建议安装图形界面, 因为当你 USB 设备全部直通, 显卡直通了之后宿主的操作性就差很多.

配置完毕系统后就要安装 qemu 和 vfio(用于穿透), 以及 qemu 的管理框架 libvirt(virt-manager), Proxmox 理论上也是可用的, 但是我不是特别想用.

启用 IOMMU

首先确保在固件设置中开启 IOMMU. 由于一般情况下直通的是 A/N 卡, 将默认显卡设置为 IGD(iGPU), 并开启 igdmultimonitor. 这通常在 chipset 选项:


然后修改 /etc/default/grub, 找到 GRUB_CMDLINE_LINUX_DEFAULT 或者 GRUB_CMDLINE_LINUX, 加入 intel_iommu=on 或者 amd_iommu=on. 保存文件, 并通过 update-grub 或者 grub2-mkconfig -o <你的 grub.cfg 的位置> 保存.

配置 vfio

由于我们需要让设备直通虚拟机, 那就不能让宿主机的驱动去接管这些硬件, 我们需要一个 dummy 驱动模块去接管这些要被直通的硬件.
首先执行 lspci --nnk, 找到你想要直通的设备的 ID, 并且注意每个设备所在组的其他设备(编辑文件 /etc/modprobe.d/vfio.conf.

options vfio-pci ids=<PCI 地址,...> disable_vga=1

但是为了避免 initrd 引入的内核模块中 vfio 位于物理驱动的后面, 这里有两套方案:
1.根据 lspci --nnk 的内容, 找到每个设备对应的驱动, 如 RX470D 及其 HDMI 音频设备:

01:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] [1002:67df] (rev ff)  
    Kernel driver in use: amdgpu
    Kernel modules: amdgpu
01:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere HDMI Audio [Radeon RX 470/480 / 570/580/590] [1002:aaf0] (rev ff)  
    Kernel driver in use: snd_hda_intel
    Kernel modules: snd_hda_intel

修改 /etc/blacklist.conf, 加入你不想要的驱动:

blacklist i915  
blacklist amdgpu  
...

2.修改 /etc/mkinitcpio.conf, 这里参考 archliux wiki, 因为操作比较复杂, 但是相对于直接屏蔽, 能够实现更复杂的配置.
随后执行 update-initramfsmkinitrd, 重新生成 initrd, 随后重启.
启动后检查配置lspci --nnk :

01:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] [1002:67df] (rev ff)  
    Kernel driver in use: vfio-pci
    Kernel modules: amdgpu
01:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere HDMI Audio [Radeon RX 470/480 / 570/580/590] [1002:aaf0] (rev ff)  
    Kernel driver in use: vfio-pci
    Kernel modules: snd_hda_intel

这说明被 vfio-pci 接管.
随后即可在 virt-manager/qemu 中穿透该设备.

macOS 系统安装

在初步测试环境下, 不建议使用 libvirt 管理虚拟机.

此时建议透过 VNC 或者在有 XFoward 的环境下 ssh 到目标宿主机.
通过 qemu-img create -f qcow2 mac_hdd.img 128G 创建一个 128GB 声明容量的 qcow2 块设备文件.
将先前准备的安装介质 ISO 复制到 OSX-KVM 的目录. 修改 boot-macOS-Mojave.sh, 对应好各个块设备的文件名:
-drive id=MacDVD,if=none,snapshot=on,media=cdrom,file=./'<刚才的安装介质.iso>' \ 启动这个脚本, 你就能看到 qemu 的视频回传窗口, 此时 USB 鼠标驱动能够正常启动. 进入 Clover 之后选择进入 macOS installer. 进入安装环境后先进入 disk utility 格式化刚才准备的 128GB 块设备为 APFS 格式. 完成后完成系统安装. 安装之后重启, 理论上正常能够进入系统.

同样的方法, 修改 boot-passthrough.sh, 注意 PCIe 设备的 ID 需要和你的显卡和 HDMI 音频设备一致. 由于这个 qemu 脚本中不包含 VGA 输出设备, 所以不输出到 qemu 窗口是正常的.如果你的显卡并没有输出画面到显示器, Clover 固件阶段可以通过提供的 serial console 进行操作. 正常情况下启动的时候会出现 tianocore 的欢迎 logo.

很多 AMD 矿卡修改了 VBIOS, 这会在没有 CSM 支持和强制 SecureBoot 的环境下无法在固件界面点亮. 在 Windows 系统下可能会碰到 error code 43 问题, 需要通过 patch driver 解决.
OVMF 没有提供任何 CSM 支持, 所以修改 VBIOS 的矿卡是无输出的. techpowerup 能找到很多 GPU 的 VBIOS, 但是刷入前一定要备份原有 VBIOS, 并注意显存颗粒兼容情况.
Linux/macOS 系统内的驱动对于 mod VBIOS 能够兼容

正常情况下能够进入 macOS. 由于该脚本内没有包含任何输入设备(OSX-KVM 的 clover 块设备内不包含 PS/2 驱动), 所以是无法进行操作的, 除非进行 USB 设备重定向或者穿透 PCIe 上的 USB 控制器. 前者性能较差, 后者通常会失去对于宿主的控制, 除非你的设备有多个完全独立的 USB bus.
成功进入 macOS 后可以开始根据之前的参数修改 macOS-libvirt.xml. 参考 核心绑定调整 vCPU 和 CPU 的对应关系, 并且正确的传递 CPU 的拓扑(即 socket/core/thread), 以达到最大性能.
随后: virsh --connect qemu:///system define macOS-libvirt.xml
此时可以通过 virt-manager 启动虚拟机. 注意此时在图形界面下添加 PCIe 穿透更加方便. 需要添加的设备有:

  • AMD 显卡及附属音频设备
  • BCM PCIe 无线网卡
  • USB 控制器(需要包含 PCIe 网卡的 USB 蓝牙部分)
  • ...

进入系统后就是给一些驱动打 patch、洗白等操作, 这里不再赘述.

编辑于 2019-03-26

文章被以下专栏收录

    Code/Hardware/ACG/Production

    敝专栏主要为那些无法被 Apple 产品满足需求的用户陈列一些与「自行组建 mac 兼容机」有关的文章、方便其中自力更生者解决各自遇到的问题。 这不是一门对好吃懒做而言非常友好的学问,你在金钱方面所省下来的、必定会占去你等价的时间来用以钻研相关的技术(借此解决各自的所遇到问题)。 敝专栏内容不得用于商业营利用途、不提倡无断转载。同时该专栏没有稿费、作者们也不会有「对自己文章的技术内容导致的任何对他人的损失做担保」的法律义务。