GPU passthrough for bhyve on FreeBSD 14
21-05-2024
Table of Contents
We recently purchased a GPU for our University computer club [1] for Machine Learning tasks. Being most comfortable on a FreeBSD system I decided that running a VM through bhyve would be most suitable. Especially as I expect that several students will connect to this machine concurrently using harmful software such as Visual Studio Codes remote development over SSH extension.
Why even bother
From experience I know that VSCode launches a gazillion processes and wont kindly terminate them. It also downloads binaries from microsoft servers and runs a little node session remote on the server for each user and doesnt reuse old ones. A bonus is that it doesnt run naively on FreeBSD (You can get this working using linuxulator [2] but dont bother).
But the problem is that meanwhile Bhyve does support PCI-e passthrough its GPU support is lacking according to people online. [3]
bhyve supports passing of host PCI devices to a virtual machine for its exclusive use of them.
Note: VGA / GPU pass-through devices are not currently supported.
That last part is not really true, the problem lies within some drivers (NVIDIA) only supporting hypervisors with the KVM signature, so we need to patch Bhyve.
Luckily patches are already available [4], and the instructions are as simple as following the FreeBSD developers handbook [5].
Lets get started!
First get the sources for FreeBSD, you probably only care about the branch with the patches applied. They reside on github from the Beckhoff github account under the tag phab/corvink/14.0/nvidia-wip.
cd /where/you/want/to/build
git clone --depth 1 --branch phab/corvink/14.0/nvidia-wip https://github.com/Beckhoff/freebsd-src
buildkernel
Now we can either use the script provided by corvink@ [6] or just follow the handbook.
cd freebsd-src
make -j64 buildkernel
make installkernel
Now the new kernel is installed, the previous kernel is located at
/boot/kernel.old/kernel
make bhyve
Now its time to build bhyve with our patches, this will go quick. The provided script automates this for you. (really, use the script [6])
cd include
make -j64
make install
cd lib/libvmmapi
make -j64
make install
cd sys/modules/vmm
make -j64
make install
cd usr.sbin/bhyve
make -j64
make install
cd usr.sbin/bhyvectl
make -j64
make install
cd usr.sbin/bhyveload
make -j64
make install
Really, just use the script. But now you should be ready to reboot into your freshly patches system!
For future FreeBSD releases you can simply go in and apply the patch manually if necessary.
Bhyve passthrough
Now to have our pci device to passthrough to bhyve we first figure out what id its assigned. This is basically following the wiki page at [3].
$ pciconf -v -l | grep -B 1 -A 3 NVIDIA
ppt0@pci0:193:0:0: class=0x030000 rev=0xa1 hdr=0x00 vendor=0x10de device=0x2204 subvendor=0x1028 subdevice=0x3880
vendor = 'NVIDIA Corporation'
device = 'GA102 [GeForce RTX 3090]'
class = display
subclass = VGA
ppt1@pci0:193:0:1: class=0x040300 rev=0xa1 hdr=0x00 vendor=0x10de device=0x1aef subvendor=0x1028 subdevice=0x3880
vendor = 'NVIDIA Corporation'
device = 'GA102 High Definition Audio Controller'
class = multimedia
subclass = HDA
Now note down those numbers and insert them into /boot/loader.conf as following
# echo pptdevs="193/0/0 193/0/1" >> /boot/loader.conf
Now the host wont steal them when the system is started, now to map them into
Bhyve. If you want to passthrough another device, such as an USB hub to the VM
you can specify more devices by appending N
to pptdevs such as pptdevs2="194/0/0"
.
We use the excellent bhyve-vm [7] utility to simplify vm management.
Simply add the following to the end of your $VM.conf file, they will now show up in pci slots 9:0 and 9:1 on the VM. You might want to make sure that you dont make them to a spot thats already occupied, if so just go higher.
passthru0="193/0/0=9:0"
passthru1="193/0/1=9:1"
And presto!
Now you can reboot your FreeBSD host and your VM will have access to the GPU.
On a linux VM you can verify that the patches were applied correctly by checking
your hypervisor signator by running dmesg
# dmesg | grep KVM
Update for newer releases
The patch still works on 14.1 it just needed some tiny refactoring as
read_config
was renamed to pci_host_read_config
.
A patch file is provided nvidia.patch.
Apply it by running git apply -v nvidia.patch
after cloning 14.1 by running
git clone --depth 1 --branch releng/14.1 https://github.com/freebsd/freebsd-src
References
[1] https://df.lth.se/
[2] https://wiki.freebsd.org/Linuxulator
[3] https://wiki.freebsd.org/bhyve/pci_passthru
[4] https://github.com/Beckhoff/freebsd-src/tree/phab/corvink/14.0/nvidia-wip
[5] https://docs.freebsd.org/en/books/developers-handbook/kernelbuild/
[6] http://okturing.com/src/19931/body
[7] https://github.com/churchers/vm-bhyve