KVM Passthrough

This post describes how to pass through the host operating system, in order to expose a real piece of hardware device to a KVM virtual machine.

1. Install Qemu-KVM[1]

1.1 Enable the virtualization settings in BIOS.

1.2 Check KVM installation environment.

1
2
3
4
5
$ sudo apt-get update
$ sudo apt-get install cpu-checker
$ sudo modprobe kvm_intel
$ sudo modprobe kvm
$ kvm-ok

1.3 If everything is okay, you can install the qemu-kvm packages.

1
2
3
4
5
$ sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils
$ sudo adduser `id -un` libvirtd
$ sudo chmod 777 /var/run/libvirt/libvirt-sock
$ sudo chown root:libvirtd /dev/kvm
$ virsh -c qemu:///system list 

1.4 If the command below shows you an empty list of virtual machines, the installation is successful. You may now install the virt-manager. which is the GUI tool for KVM.

1
$ sudo apt-get install virt-manager

2. Enable IOMMU support

1
$ sudo vi /etc/default/grub

and add intel_iommu=on in GRUB_CMDLINE_LINUX_DEFAULT parameter.

Regenerate the grub list:

1
$ sudo update-grub

After reboot, you can verify the IOMMU support by type in

1
$ dmesg | grep -e DMAR -e IOMMU

If you are using an Intel machine. For AMD, check here.

3. Modify KVM kernel [2]

I skipped this step.

4. Verify the PCI that you need to attach to the virtual machine.

In the host os, type:

1
$ lspci

Suppose we are interested in passing through this device:

1
20:00.0 VGA compatible controller: Advanced Micro Devices [AMD] nee ATI Caicos [Radeon HD 6450]

which is a PCI-Express Graphics Card. This PCI device 20:00.0 will be the example device in the following steps.

1
2
3
4
$ lspci -n
...
20:00.0 0300: 1002:6779
...

Note down the device ID 1002:6779 .

5. Unbind and bind

5.1 Load the PCI stub module.

1
$ sudo modprobe pci_stub

5.2 Unbind the device from the host kernel, and bind it to pci stub. (need root access)

1
2
3
# echo "1002 6779" > /sys/bus/pci/drivers/pci-stub/new_id 
# echo 0000:20:00.0 > /sys/bus/pci/devices/0000\:20\:00.0/driver/unbind
# echo 0000:20:00.0 > /sys/bus/pci/drivers/pci-stub/bind

6. Assign device

Add extra parameters as below after the usual kvm command.

1
$ kvm ... -device pci-assign,host=20:00.0

If you see errors, check the following section.

7. Necessary permission modifications [3]

According to my experience, you might encounter an error saying:

1
Device 'pci-assign' could not be initialized.

Before you try any solution, first make sure that modules such as kvm, kvm_intel, pci_stub are loaded. Also make sure that intel_iommu=on is in your grub configuration file (even if you see IOMMU from dmesg, it doesn’t ensure that INTEL_IOMMU is enabled). Then if the error is still there, try the following command:

1
# echo 1 > /sys/module/kvm/parameters/allow_unsafe_assigned_interrupts

But I did try something else before the command above, so I suppose that if this command doesn’t work, try the following:

1
# vi  /etc/libvirt/qemu.conf

Uncomment and set user and group to root. Set clear_emulator_capabilites = 0. Set relaxed_acs_check = 1.

Besides, if you are using a RPM-based system such as Fedora, you also need to set SELinux to permissive.

Then run kvm again as root.

1
# kvm ... -device pci-assign,host=20:00.0

8. Done.

In the guest OS, run lspci, and check if you can see the assigned pci device there.

References

[1] https://help.ubuntu.com/community/KVM/Installation

[2] http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM

[3] http://comments.gmane.org/gmane.comp.emulators.libvirt.user/2945