##Ubuntu19.10のKVMでシングルGPU構成でGPUパススルーが出来る手順について掲載します。
##環境
マザー:Biostar X570GT8
CPU:Ryzen3600
OS:ubuntu 19.10
GPU:RADEON RX580
###1. grubの設定
# vi /etc/defalut/grub
GRUB_CMDLINE_LINUX="amd_iommu=on iommu=pt pcie_aspm=off acpi_enforce_resources=lax thermal.off=1 video=1920x1080"
amd_iommu : iommuの有効化
iommu : PCIパススルーのパフォーマンス改善
pcie_aspm : PCI-Expressの省電力機能の無効化
GRUB_GFXMODE="1920x1080-24"
# update-grub2
###2. initramfs設定
# vi /etc/modules-load.d/modules.conf
vfio
vfio_iommu_type1
vfio_virqfd
options kvm_amd avic=1
###3. カーネルモジュールの設定
####3.1 KVMモジュールの設定
# vi /etc/modprobe.d/kvm.conf
options kvm ignore_msrs=1
options kvm allow_unsafe_assigned_interrupts=1
options kvm report_ignored_msrs=0
####3.2 QEMUモジュールの設定
# vi /etc/modprobe.d/qemu-system-x86.conf
options kvm_intel nested=1
options kvm_amd avic=1
####3.3 VFIOモジュールの設定
# vi /etc/modprobe.d/vfio-pci.conf
options vfio-pci disable_vga=1
# vi /etc/modprobe.d/vfio_iommu_type1.conf
options vfio_iommu_type1 allow_unsafe_interrupts=1
####3.4 AMD GPUドライバー設定
# vi /etc/modprobe.d/amd.conf
blacklist radeon
options amdgpu pcie_gen_cap=0x2
オプションはシングルGPU構成の時に、ドライバー再ロード後にVMが起動出来なくなるのを防ぐ設定。
ただし、ドライバーのアンロード、ロードをパススルーを挟まずに行うとOSがクラッシュする。
###4. initramfsの再作成
# update-initramfs -k all -u
###5. libvirtdの設定
####5.1 QEMU HOOKスクリプトの作成(シングルGPU用、ホストとゲストでGPUを分けるなら不要)
# vi /etc/libvirt/hooks/qemu
#!/bin/bash
SHELL_PATH=/etc/libvirt/hooks
NAME=${1}
OPERATION=${2}
SUB_OPERATION=${3}
SCRIPT=${SHELL_PATH}/qemu_${NAME}.sh
LOG_FILE=/tmp/qemu.log
echo `date "+%Y-%m-%d %H:%M:%S.%N"` $* >> ${LOG_FILE}
if [ -x ${SCRIPT} ] ;then
echo `date "+%Y-%m-%d %H:%M:%S.%N"` $SCRIPT ${OPERATION} ${SUB_OPERATION} >> ${LOG_FILE}
$SCRIPT ${OPERATION} ${SUB_OPERATION}
fi
# vi /etc/libvirt/hooks/qemu_VM名.sh
#!/bin/bash
MODULE_FILE=/var/tmp/gpu_module
OPERATION=${1}
SUB_OPERATION=${2}
SCRIPT=$0
MAX_WAIT_COUNT=5
LOG_FILE=/tmp/qemu.log
case ${OPERATION} in
"prepare")
case ${SUB_OPERATION} in
"begin")
# display-manager.service Stop
#systemctl isolate multi-user.target
systemctl stop display-manager.service
# kill lxqt-panel(In lightdm, lxqt environment, process may remain)
killall lxqt-panel
# vtconsole Unbind
echo 0 > /sys/class/vtconsole/vtcon1/bind
# VGA Device List Up
DEVICE_ID=`lspci -nn | grep VGA | awk '{print $1}'`
# Boot VGA Check
for device in `echo ${DEVICE_ID}`; do
# Boot VGA Flag Check
if [ "`cat /sys/bus/pci/devices/0000:${device}/boot_vga`" = "1" ]; then
# PCI Vender ID Get
VENDER_ID=`cat /sys/bus/pci/devices/0000:${device}/vendor`
# Use Kernel Driver Name Get
DRIVER_NAME=`lspci -k -s 0000:${device} | grep "Kernel driver in use" | awk '{print $5}'`
fi
done
# Kernel Module List Up
lsmod | grep ^${DRIVER_NAME} | awk '{print $1}' > ${MODULE_FILE}
# Kernel GPU Module Check
if [ -s ${MODULE_FILE} ]; then
# AMD GPU Driver Clashes
# Runs only with NVIDIA Driver
if [ "${DRIVER_NAME}" = "nvidia" ]; then
# Unbind EFI-Framebuffer
echo efi-framebuffer.0 > /sys/bus/platform/drivers/efi-framebuffer/unbind
fi
# Failure to sleep results in an error
sleep 2
# Unload All GPU drivers
for module in `cat ${MODULE_FILE}`; do
# Unload Kernel Module
modprobe -s -r ${module}
# Return Code Setting
rc=$?
# Running Log Output
echo "${SCRIPT} modprobe -r rc=${rc}" >> $LOG_FILE
done
fi
exit $rc
;;
esac
;;
"release")
case ${SUB_OPERATION} in
"end")
# GPU Kernel Module Check
if [ -s ${MODULE_FILE} ]; then
# Load All GPU drivers
for module in `cat ${MODULE_FILE}`; do
# Load Kernel Module
modprobe ${module}
done
# GPU Kernel Module List File Remove
# rm -f ${MODULE_FILE}
# Sleep for the time being
sleep 1
# efi-framebuffer.0 File not exist check
if [ ! -e /sys/bus/platform/drivers/efi-framebuffer/efi-framebuffer.0 ]; then
# Bind EFI-Framebuffer
echo "efi-framebuffer.0" > /sys/bus/platform/drivers/efi-framebuffer/bind
fi
fi
# display-manager.service Start
#systemctl isolate graphical.target
systemctl start display-manager.service
;;
esac
;;
esac
####5.2 VMの作成
####5.2.1 virt-managerで新規VMを作成
・GPUを追加
・USB(キーボード、マウス)のPCIデバイスを追加
・ディスプレイ Spiceを削除
・チャンネル qemu-gaを削除
・チャンネル spiceを削除
・ビデオQXLを削除
####5.2.2 VMのxmlファイル編集
# vi /etc/libvirt/qemu/VM名.xml
####5.2.2.1 schema拡張
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
####5.2.2.2 VIDEO BIOSファイル設定
※VIDEO BIOSファイルはTechPowerUpサイトからGPUに合ったファイルをダウンロードするかGPU-Zで吸い出す。
NVIDIAのBIOSは先頭から0x600バイト削除する。("55 AA 7B"の前を削除)
<hostdev mode='subsystem' type='pci' managed='yes'>
<source>
<address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
</source>
<rom bar='on' file='/etc/libvirt/qemu/vbios/vbios.rom'/>
<address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
</hostdev>
####5.2.2.3 QEMU VGAの無効化
<qemu:commandline>
<qemu:arg value='-vga'/>
<qemu:arg value='none'/>
<qemu:arg value='-nographic'/>
</qemu:commandline>
####5.2.2.4 NVIDIAのCode43対応
<features>
<hyperv>
<vendor_id state='on' value='123456789ab'/>
</hyperv>
<kvm>
<hidden state='on'/>
</kvm>
</features>
####5.2.2.5 QEMU4.0のNVIDIAのバグを回避
<features>
<ioapic driver='kvm'/>
</features>
####5.2.2.6 RYZENのCPU機能の有効化
<cpu mode='host-passthrough' check='none'>
<feature policy='require' name='topoext'/>
<feature policy='require' name='invtsc'/>
</cpu>
###5.2.2.7 CPU,iothreadを固定することで映像と音声のずれを防ぐ設定。
<iothreads>1</iothreads>
<cputune>
<vcpupin vcpu='0' cpuset='2'/>
<vcpupin vcpu='1' cpuset='8'/>
<vcpupin vcpu='2' cpuset='3'/>
<vcpupin vcpu='3' cpuset='9'/>
<vcpupin vcpu='4' cpuset='4'/>
<vcpupin vcpu='5' cpuset='10'/>
<emulatorpin cpuset='5'/>
<iothreadpin iothread='1' cpuset='11'/>
</cputune>
####5.2.3 libvirtdの再起動