## Mainline kernel After your fresh CentOS 7 setup (make sure you install the QEMU/KVM virtualization tools and `virt-manager`), install the mainline kernel: ```bash sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org sudo rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm sudo yum --enablerepo=elrepo-kernel install kernel-ml sudo yum -y update ``` Reboot and be sure to select the mainline (4.0) kernel from the boot menu. Add the menu entry you selected to the `GRUB_DEFAULT` in `/etc/default/grub` in order to save your selection. You may also want to enable updates for the mainline kernel with `sudo yum-config-manager --enable elrepo-kernel` and disable kernel updates from the CentOS Base repository by adding `exclude=kernel*` to the bottom of the `[updates]` section in `/etc/yum.repos.d/CentOS-Base.repo`. ## UEFI firmware To install the OVMF firmware, create the file `kraxel.repo` at `/etc/yum.repos.d/` with the following contents: ``` include=https://www.kraxel.org/repos/firmware.repo ``` Then install the firmware with `yum install edk2.git-ovmf-x64`. To advertise UEFI in `libvirt`, add the following to `/etc/libvirt/qemu.conf`: ``` nvram = [ "/usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd:/usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd", "/usr/share/edk2.git/aarch64/QEMU_EFI-pflash.raw:/usr/share/edk2.git/aarch64/vars-template-pflash.raw", ] ``` Restart `libvirt` with `sudo systemctl restart libvirtd` for these changes to take effect. ## The latest `libvirt` and `qemu` Download the following packages from https://repos.fedorapeople.org/repos/openstack/.virt-upstream-el7/ to a folder called `qemu-2.2`: * libvirt-1.2.11-1.el7.centos.x86_64.rpm * libvirt-client-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-config-network-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-config-nwfilter-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-driver-interface-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-driver-lxc-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-driver-network-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-driver-nodedev-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-driver-nwfilter-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-driver-qemu-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-driver-secret-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-driver-storage-1.2.11-1.el7.centos.x86_64.rpm * libvirt-daemon-kvm-1.2.11-1.el7.centos.x86_64.rpm * libvirt-python-1.2.11-1.el7.centos.x86_64.rpm * qemu-guest-agent-2.2.0-1.el7.centos.test.x86_64.rpm * qemu-img-2.2.0-1.el7.centos.test.x86_64.rpm * qemu-kvm-2.2.0-1.el7.centos.test.x86_64.rpm * qemu-kvm-common-2.2.0-1.el7.centos.test.x86_64.rpm * qemu-kvm-tools-2.2.0-1.el7.centos.test.x86_64.rpm Change into your `qemu-2.2` directory and run the following command to install these packages: `sudo yum --nogpgcheck localinstall *.rpm`. You can verify that this worked by running `yum list installed | egrep '(libvirt|qemu)'` and making sure that the `libvirt` packages are listed as `1.2.11` and the `qemu` packages are listed as `2.2.0`. ## Setting up Networking Run the following to enable IP forwarding in your kernel: ```bash echo "net.ipv4.ip_forward = 1"|sudo tee /etc/sysctl.d/99-ipforward.conf sudo sysctl -p /etc/sysctl.d/99-ipforward.conf ``` Find the name of your network device with `ls -la /etc/sysconfig/network-scripts/` (the one that starts with `ifcfg`), then comment out all the IP-related lines, like so: ``` TYPE=Ethernet #BOOTPROTO=dhcp #DEFROUTE=yes #IPV4_FAILURE_FATAL=no #IPV6INIT=yes #IPV6_AUTOCONF=yes #IPV6_DEFROUTE=yes #IPV6_FAILURE_FATAL=no ## Your name, UUID, and device will probably be different from mine! NAME=enp8s0 UUID=a258d1da-cc97-4255-bd8e-dcbde55952be DEVICE=enp8s0 ONBOOT=yes #PEERDNS=yes #PEERROUTES=yes #IPV6_PEERDNS=yes #IPV6_PEERROUTES=yes #IPV6_PRIVACY=no BRIDGE=br0 ``` Notice that we added an extra line for a bridge, so now we create the bridge with `sudo vim /etc/sysconfig/network-scripts/ifcfg-br0`. It should contain something like this: ``` DEVICE=br0 TYPE=Bridge BOOTPROTO=static ONBOOT=yes ## Your IP address settings will probably be different from mine! IPADDR=192.168.0.2 NETMASK=255.255.255.0 GATEWAY=192.168.0.1 DNS1=75.75.75.75 ``` The Network Manager GUI is going to want to undo what you've done, so disable it: ```bash sudo systemctl stop NetworkManager sudo systemctl disable NetworkManager ``` ## Boot options for VGA passthrough I have an Nvidia card, so I did a `lspci -nn | grep -i nvidia` to figure out the host address and device ID for my graphics card and HD audio. The host address will look like this: `01:00.0`, and your device ID will look like this: `10de:0fc1`. Using your own device IDs, add `iommu=on pci-stub.ids=10de:0fc1,10de:0e1b` to the end of the `GRUB_CMDLINE_LINUX` in `/etc/default/grub`, regenerate the `grub` configuration with `sudo grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg`, then reboot. Note that if you don't use UEFI firmware on your host machine, the location of your `grub` configuration file may be different! We also need to disable the Nouveau drivers with `echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf`, then execute the following as `root`: ```bash mv /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).img.bak dracut -v /boot/initramfs-$(uname -r).img $(uname -r) ``` ## SELinux You might get security errors, so run this as `root`: ```bash grep qemu-kvm /var/log/audit/audit.log | audit2allow -M mypol semodule -i mypol.pp grep ebtables /var/log/audit/audit.log | audit2allow -M mypol semodule -i mypol.pp ``` ## Permission errors on home directory `libvirt` has a pretty strict security model, even when running as `root`. If you'd like to make disks in your home directory accessible, run `chmod go+x $HOME`. ## Virtual Machine configuration Before trying to install your guest OS, it's *very* important that you find a Windows 7 installation CD that supports UEFI. I spent 2 weeks trying to get VGA passthrough to work and probably a week of that was due to a bad Windows 7 ISO. Another thing to note is that the Tiano UEFI that we've configured probably doesn't have any useful drivers for recognizing disks. If you find yourself dumped on a strange UEFI command line that doesn't recognize any disks, download the [rEFInd](http://sourceforge.net/projects/refind/) CD image and load it into a virtual CDROM. On boot you can navigate into it, install some drivers, then remove the rEFInd CD and try again with your OS DVD. The last thing you should be aware of is that you *should not* attempt the VGA passthrough on your first install of the guest OS. Install the OS, make sure all your devices work (you will likely need [Windows Virtio Drivers](https://fedoraproject.org/wiki/Windows_Virtio_Drivers) for many of the virtual devices), and *then* you can reboot and add PCI Host devices to your virtual machine. To conclude, I've posted the contents of my virtual machine (accessible via `sudo virsh dumpxml `) below: ```xml win7 527f4b3d-deed-4c36-9858-6339b2703464 4194304 4194304 6 /machine hvm /usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd /var/lib/libvirt/qemu/nvram/win7_VARS.fd destroy restart restart /usr/libexec/qemu-kvm