GPU passtrough QEMU/KVM

Hello everyone, first of all, thank you to anyone willing to help me with this question. I’m trying to perform a GPU passthrough (GTX 860M) on my Lenovo Y50-70 Laptop using QEMU/KVM (with guest Win10 pro). I’ve followed various guides and tried two approaches:

  1. Script

    In this case, I considered “GPU passthrough via OVMF” and a script created by a user on Reddit which I used as a basis to understand what needed to be done.
    I managed to create the following script:

    #!/bin/sh
    
    sudo modprobe vfio-pci
    sudo modprobe vfio
    sudo modprobe vfio-iommu-type1
    #sudo modprobe kvmfr
    
    sudo chown fra:kvm /dev/vfio/*
    sudo chmod 0660 /dev/vfio/*
    #sudo chown fra:kvm /dev/kvmfr0
    #sudo chmod 0660 /dev/kvmfr0
    
    qemu-system-x86_64 
    -enable-kvm 
    -machine type=q35,accel=kvm 
    -cpu host,kvm=off,hv_vendor_id=null,hv_relaxed,hv_vapic,hv_time,hv_spinlocks=0x1fff,-hypervisor,+invtsc 
    -smp 6,sockets=1,cores=6,threads=1 
    -m 8G 
    
    -device vfio-pci,host=01:00.0,romfile=/home/fra/qemu-vfio-win10/GTX860M.rom,rombar=0,x-pci-sub-vendor-id=0x17aa,x-pci-sub-device-id=0x3978 
    
    -drive file=OVMF_CODE.fd,if=pflash,readonly=on,format=raw 
    -drive file=OVMF_VARS.fd,if=pflash,format=raw 
    
    -cdrom /home/fra/Documenti/Win10VM/Win10_22H2_Italian_x64v1.iso 
    -drive file=/home/fra/Documenti/Win10VM/virtio-win-0.1.285.iso,media=cdrom 
    
    -drive file=/home/fra/VMs/hdd.qcow2,if=none,id=disk,format=qcow2 
    -device ich9-ahci,id=ahci 
    -device ide-hd,bus=ahci.0,drive=disk 
    
    -netdev user,id=nic,hostfwd=tcp::3389-:3389 
    -device virtio-net-pci,netdev=nic 
    
    -device qemu-xhci,id=usb 
    
    -device usb-host,vendorid=0x03f0,productid=0x734a 
    -device usb-host,vendorid=0x258a,productid=0x002a 
    
    -vga std 
    -display none 
    -vnc 0.0.0.0:0 
    
    -device ivshmem-plain,memdev=shm0,id=ivshmem0 
    -object memory-backend-file,id=shm0,size=128M,share=yes,mem-path=/dev/shm/looking-glass 
    
    -acpitable file=/home/fra/qemu-vfio-win10/ssdt2.dat 
    -acpitable file=/home/fra/qemu-vfio-win10/ssdt3.dat 
    -acpitable file=/home/fra/qemu-vfio-win10/ssdt4.dat 
    -acpitable file=/home/fra/qemu-vfio-win10/ssdt5.dat 
    -acpitable file=/home/fra/qemu-vfio-win10/ssdt6.dat 
    -acpitable file=/home/fra/qemu-vfio-win10/ssdt7.dat 
    -acpitable file=/home/fra/qemu-vfio-win10/ssdt8.dat 
    
    -boot order=d
    

    As you can see, I did my best to hide the virtual machine by passing information about the video card and the ACPI tables.

    Thanks to this script, I managed to boot the VM and install the NVIDIA drivers. Unfortunately, I keep running into the GPU error Code 43, which prevents me from opening Looking Glass and utilizing the dedicated GPU.
    Furthermore, you can see that the ACPI tables are missing SSDT1.dat and DSDT.dat because using them causes Win10 to fail to boot, showing error 0xc0000225. Regarding the GPU VBIOS, it was obtained by using a live version of Win10 on USB in combination with SIV (System Information Viewer).
    I have tried various combinations, with and without the VBIOS passed through, using an external display, but I can’t effectively “wake up” the GPU. Error 43 seems to disappear by disabling/enabling the GPU in Win 10’s Device Manager, but it’s still as if it’s dormant.

  2. GUI

    The same thing happens using the QEMU GUI. In this case, I followed the guide of this guy on YouTube and set up the virtual machine in a very similar way, but without success. The linked video shows passthrough being performed on a desktop PC, but a few videos later, it is shown that the same procedure, with some precautions, was also successful on a laptop with a dedicated GPU.

Naturally, in both cases, I started Linux with a dedicated GRUB profile for the GPU passthrough, in which I enabled IOMMU:

#! /bin/sh
set -e

grub-mkconfig helper script.

Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.



GRUB is free software: you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation, either version 3 of the License, or

(at your option) any later version.



GRUB is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

GNU General Public License for more details.



You should have received a copy of the GNU General Public License

along with GRUB.  If not, see http://www.gnu.org/licenses/.

prefix=“/usr”
exec_prefix=“/usr”
datarootdir=“/usr/share”

. “$pkgdatadir/grub-mkconfig_lib”

export TEXTDOMAIN=grub
export TEXTDOMAINDIR=“${datarootdir}/locale”

CLASS=“–class gnu-linux --class gnu --class os”

if [ “x${GRUB_DISTRIBUTOR}” = “x” ] ; then
OS=Linux
else
OS=“${GRUB_DISTRIBUTOR} Linux”
CLASS=“–class $(echo ${GRUB_DISTRIBUTOR} | tr ‘A-Z’ ‘a-z’ | cut -d’ ’ -f1|LC_ALL=C sed ‘s,[

:alnum:],,g’) ${CLASS}”
fi

loop-AES arranges things so that /dev/loop/X can be our root device, but

the initrds that Linux uses don’t like that.

case ${GRUB_DEVICE} in
/dev/loop/*|/dev/loop[0-9])
GRUB_DEVICE=losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"
;;
esac

: ${GRUB_CMDLINE_LINUX_RECOVERY:=single}

Default to disabling partition uuid support to maintian compatibility with

older kernels.

: ${GRUB_DISABLE_LINUX_PARTUUID=true}

btrfs may reside on multiple devices. We cannot pass them as value of root= parameter

and mounting btrfs requires user space scanning, so force UUID in this case.

if ( [ “x${GRUB_DEVICE_UUID}” = “x” ] && [ “x${GRUB_DEVICE_PARTUUID}” = “x” ] ) 
|| ( [ “x${GRUB_DISABLE_LINUX_UUID}” = “xtrue” ] 
&& [ “x${GRUB_DISABLE_LINUX_PARTUUID}” = “xtrue” ] ) 
|| ( ! test -e “/dev/disk/by-uuid/${GRUB_DEVICE_UUID}” 
&& ! test -e “/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}” ) 
|| ( test -e “${GRUB_DEVICE}” && uses_abstraction “${GRUB_DEVICE}” lvm ); then
LINUX_ROOT_DEVICE=${GRUB_DEVICE}
elif [ “x${GRUB_DEVICE_UUID}” = “x” ] 
|| [ “x${GRUB_DISABLE_LINUX_UUID}” = “xtrue” ]; then
LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID}
else
LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
fi

case x"$GRUB_FS" in
xbtrfs)
rootsubvol=“make_system_path_relative_to_its_root /”
rootsubvol=“${rootsubvol#/}”
if [ “x${rootsubvol}” != x ]; then
GRUB_CMDLINE_LINUX=“rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}”
fi;;
xzfs)
rpool=${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || zdb -l ${GRUB_DEVICE} | awk -F \' '/ name/ { print $2 }'
bootfs=“make_system_path_relative_to_its_root / | sed -e "s,@$,,"”
LINUX_ROOT_DEVICE=“ZFS=${rpool}${bootfs%/}”
;;
esac

title_correction_code=

linux_entry ()
{
os=“$1”
version=“$2”
type=“$3”
args=“$4”

if [ -z “$boot_device_id” ]; then
boot_device_id=“$(grub_get_device_id “${GRUB_DEVICE}”)”
fi
if [ x$type != xsimple ] ; then
case $type in
booster)
title=“$(gettext_printf “%s, with Linux %s (booster initramfs)” “${os}” “${version}”)” ;;
fallback)
title=“$(gettext_printf “%s, with Linux %s (fallback initramfs)” “${os}” “${version}”)” ;;
recovery)
title=“$(gettext_printf “%s, with Linux %s (recovery mode)” “${os}” “${version}”)” ;;
*)
title=“$(gettext_printf “%s, with Linux %s” “${os}” “${version}”)” ;;
esac
if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
replacement_title=“$(echo “Advanced options for ${OS}” | sed ‘s,>,>>,g’)>$(echo “$title” | sed ‘s,>,>>,g’)”
quoted=“$(echo “$GRUB_ACTUAL_DEFAULT” | grub_quote)”
title_correction_code=“${title_correction_code}if [ "x$default" = ‘$quoted’ ]; then default=‘$(echo “$replacement_title” | grub_quote)’; fi;”
grub_warn “$(gettext_printf “Please don’t use old title `%s’ for GRUB_DEFAULT, use `%s’ (for versions before 2.00) or `%s’ (for 2.00 or later)” “$GRUB_ACTUAL_DEFAULT” “$replacement_title” “gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id”)”
fi
echo “menuentry ‘$(echo “$title” | grub_quote)’ ${CLASS} $menuentry_id_option ‘gnulinux-$version-$type-$boot_device_id’ {” | sed “s/^/$submenu_indentation/”
else
echo “menuentry ‘$(echo “$os” | grub_quote)’ ${CLASS} $menuentry_id_option ‘gnulinux-simple-$boot_device_id’ {” | sed “s/^/$submenu_indentation/”
fi
if [ x$type != xrecovery ] ; then
save_default_entry | grub_add_tab
fi

Use ELILO’s generic “efifb” when it’s known to be available.

FIXME: We need an interface to select vesafb in case efifb can’t be used.

if [ “x$GRUB_GFXPAYLOAD_LINUX” = x ]; then
echo "	load_video" | sed “s/^/$submenu_indentation/”
if grep -qx “CONFIG_FB_EFI=y” “${config}” 2> /dev/null 
&& grep -qx “CONFIG_VT_HW_CONSOLE_BINDING=y” “${config}” 2> /dev/null; then
echo "	set gfxpayload=keep" | sed “s/^/$submenu_indentation/”
fi
else
if [ “x$GRUB_GFXPAYLOAD_LINUX” != xtext ]; then
echo "	load_video" | sed “s/^/$submenu_indentation/”
fi
echo "	set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed “s/^/$submenu_indentation/”
fi

echo "	insmod gzio" | sed “s/^/$submenu_indentation/”

if [ x$dirname = x/ ]; then
if [ -z “${prepare_root_cache}” ]; then
prepare_root_cache=“$(prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab)”
fi
printf ‘%s\n’ “${prepare_root_cache}” | sed “s/^/$submenu_indentation/”
else
if [ -z “${prepare_boot_cache}” ]; then
prepare_boot_cache=“$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)”
fi
printf ‘%s\n’ “${prepare_boot_cache}” | sed “s/^/$submenu_indentation/”
fi
message=“$(gettext_printf “Loading Linux %s …” ${version})”
sed “s/^/$submenu_indentation/” << EOF
echo	‘$(echo “$message” | grub_quote)’
linux	${rel_dirname}/${basename} root=${linux_root_device_thisversion} rw ${args}
EOF
if test -n “${initrd}” ; then
# TRANSLATORS: ramdisk isn’t identifier. Should be translated.
message=“$(gettext_printf “Loading initial ramdisk …”)”
initrd_path=
for i in ${initrd}; do
initrd_path=“${initrd_path} ${rel_dirname}/${i}”
done
sed “s/^/$submenu_indentation/” << EOF
echo	‘$(echo “$message” | grub_quote)’
initrd	$(echo $initrd_path)
EOF
fi
sed “s/^/$submenu_indentation/” << EOF
}
EOF
}

machine=uname -m
case “x$machine” in
xi?86 | xx86_64)
list=
for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do
if grub_file_is_not_garbage “$i” ; then list=“$list $i” ; fi
done ;;
)
list=
for i in /boot/vmlinuz- /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do
if grub_file_is_not_garbage “$i” ; then list=“$list $i” ; fi
done ;;
esac

case “$machine” in
i?86) GENKERNEL_ARCH=“x86” ;;
mips|mips64) GENKERNEL_ARCH=“mips” ;;
mipsel|mips64el) GENKERNEL_ARCH=“mipsel” ;;
arm*) GENKERNEL_ARCH=“arm” ;;
*) GENKERNEL_ARCH=“$machine” ;;
esac

prepare_boot_cache=
prepare_root_cache=
boot_device_id=
title_correction_code=

Extra indentation to add to menu entries in a submenu. We’re not in a submenu

yet, so it’s empty. In a submenu it will be equal to ‘\t’ (one tab).

submenu_indentation=“”

Perform a reverse version sort on the entire list.

Temporarily replace the ‘.old’ suffix by ’ 1’ and append ’ 2’ for all

other files to order the ‘.old’ files after their non-old counterpart

in reverse-sorted order.

reverse_sorted_list=$(echo $list | tr ’ ’ ‘\n’ | sed -e ‘s/.old$/ 1/; / 1$/! s/$/ 2/’ | version_sort -r | sed -e ‘s/ 1$/.old/; s/ 2$//’)

if [ “x$GRUB_TOP_LEVEL” != x ]; then
reverse_sorted_list=$(grub_move_to_front “$GRUB_TOP_LEVEL” ${reverse_sorted_list})
fi

is_top_level=true
for linux in ${reverse_sorted_list}; do
gettext_printf “Found linux image: %s\n” “$linux” >&2
basename=basename $linux
dirname=dirname $linux
rel_dirname=make_system_path_relative_to_its_root $dirname
version=echo $basename | sed -e "s,vmlinuz-,,g"
alt_version=echo $version | sed -e "s,\.old$,,g"
linux_root_device_thisversion=“${LINUX_ROOT_DEVICE}”

initrd_early=
for i in ${GRUB_EARLY_INITRD_LINUX_STOCK} 
${GRUB_EARLY_INITRD_LINUX_CUSTOM}; do
if test -e “${dirname}/${i}” ; then
initrd_early=“${initrd_early} ${i}”
fi
done

initrd_real=
for i in “initrd.img-${version}” “initrd-${version}.img” 
“initrd-${alt_version}.img.old” “initrd-${version}.gz” 
“initrd-${alt_version}.gz.old” “initrd-${version}” 
“initramfs-${version}.img” “initramfs-${alt_version}.img.old” 
“initrd.img-${alt_version}” “initrd-${alt_version}.img” 
“initrd-${alt_version}” “initramfs-${alt_version}.img” 
“initramfs-genkernel-${version}” 
“initramfs-genkernel-${alt_version}” 
“initramfs-genkernel-${GENKERNEL_ARCH}-${version}” 
“initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}”; do
if test -e “${dirname}/${i}” ; then
initrd_real=“${i}”
break
fi
done

initrd=
if test -n “${initrd_early}” || test -n “${initrd_real}”; then
initrd=“${initrd_early} ${initrd_real}”

initrd_display=
for i in ${initrd}; do
  initrd_display="${initrd_display} ${dirname}/${i}"
done
gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2

fi

config=
for i in “${dirname}/config-${version}” “${dirname}/config-${alt_version}” “/etc/kernels/kernel-config-${version}” ; do
if test -e “${i}” ; then
config=“${i}”
break
fi
done

initramfs=
if test -n “${config}” ; then
initramfs=grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"
fi

if test -z “${initramfs}” && test -z “${initrd_real}” ; then
# “UUID=” and “ZFS=” magic is parsed by initrd or initramfs.  Since there’s
# no initrd or builtin initramfs, it can’t work here.
if [ “x${GRUB_DEVICE_PARTUUID}” = “x” ] 
|| [ “x${GRUB_DISABLE_LINUX_PARTUUID}” = “xtrue” ]; then

linux_root_device_thisversion=${GRUB_DEVICE}
else
linux_root_device_thisversion=PARTUUID=${GRUB_DEVICE_PARTUUID}
fi

fi

The GRUB_DISABLE_SUBMENU option used to be different than others since it was

mentioned in the documentation that has to be set to ‘y’ instead of ‘true’ to

enable it. This caused a lot of confusion to users that set the option to ‘y’,

‘yes’ or ‘true’. This was fixed but all of these values must be supported now.

if [ “x${GRUB_DISABLE_SUBMENU}” = xyes ] || [ “x${GRUB_DISABLE_SUBMENU}” = xy ]; then
GRUB_DISABLE_SUBMENU=“true”
fi

if [ “x$is_top_level” = xtrue ] && [ “x${GRUB_DISABLE_SUBMENU}” != xtrue ]; then
linux_entry “${OS} (VFIO Passthrough)” “${version}” simple 
“${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} intel_iommu=on iommu=pt vfio-pci.ids=10de:1392 pcie_port_pm=off tsc=reliable kvm.ignore_msrs=1 pcie_acs_override=downstream,multifunction rd.driver.blacklist=nouveau modprobe.blacklist=nouveau”

# Termina lo script qui per non creare il sottomenù
exit 0

submenu_indentation="$grub_tab"

if [ -z "$boot_device_id" ]; then
boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
fi
# TRANSLATORS: %s is replaced with an OS name
echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {"
is_top_level=false

fi

linux_entry “${OS}” “${version}” advanced 
“${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}”

if test -e “${dirname}/initramfs-${version}-fallback.img” ; then
initrd=“${initrd_early} initramfs-${version}-fallback.img”

if test -n "${initrd}" ; then
  gettext_printf "Found fallback initrd image(s) in %s:%s\n" "${dirname}" "${initrd_extra} ${initrd}" >&2
fi

linux_entry "${OS}" "${version}" fallback \
            "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"

fi

if test -e “${dirname}/booster-${version}.img” ; then
initrd=“${initrd_early} booster-${version}.img”

if test -n "${initrd}" ; then
  gettext_printf "Found booster initrd image(s) in %s:%s\n" "${dirname}" "${initrd_extra} ${initrd}" >&2
fi

linux_entry "${OS}" "${version}" booster \
            "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"

fi

if [ “x${GRUB_DISABLE_RECOVERY}” != “xtrue” ]; then
linux_entry “${OS}” “${version}” recovery 
“${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}”
fi
done

If at least one kernel was found, then we need to

add a closing ‘}’ for the submenu command.

if [ x"$is_top_level" != xtrue ]; then
echo ‘}’
fi

echo “$title_correction_code”

Finally, here is my inxi output:


```text
System:
  Kernel: 6.17.7-zen1-1-zen arch: x86_64 bits: 64 compiler: gcc v: 15.2.1 clocksource: tsc
    avail: hpet,acpi_pm parameters: BOOT_IMAGE=/@/boot/vmlinuz-linux-zen
    root=UUID=d100dc58-e2b3-48aa-87c9-3a39daae2e5b rw rootflags=subvol=@ quiet
    resume=UUID=42caf84a-f00b-48dd-bb40-dafe886e8a3d loglevel=3
  Desktop: KDE Plasma v: 6.5.2 tk: Qt v: N/A info: frameworks v: 6.19.0 wm: kwin_x11 vt: 2
    dm: SDDM Distro: Garuda base: Arch Linux
Machine:
  Type: Laptop System: LENOVO product: 20378 v: Lenovo Y50-70 serial: <superuser required> Chassis:
    type: 10 v: Lenovo Y50-70 serial: <superuser required>
  Mobo: LENOVO model: Lenovo Y50-70 v: 31900058WIN serial: <superuser required>
    part-nu: LENOVO_MT_20378_BU_idea_FM_Lenovo Y50-70 uuid: <superuser required> UEFI: LENOVO
    v: 9ECN40WW(V3.00) date: 07/22/2015
Battery:
  ID-1: BAT1 charge: 46.4 Wh (100%) condition: 46.4/54.8 Wh (84.6%) volts: 8.21 min: 7.4
    model: LENOVO PABAS0241231 type: Li-ion serial: <filter> charging: status: full type: standard
    avail: long_life,standard cycles: N/A
CPU:
  Info: model: Intel Core i7-4710HQ bits: 64 type: MT MCP arch: Haswell gen: core 4 level: v3
    note: check built: 2013-15 process: Intel 22nm family: 6 model-id: 0x3C (60) stepping: 3
    microcode: 0x28
  Topology: cpus: 1x dies: 1 clusters: 4 cores: 4 threads: 8 tpc: 2 smt: enabled cache:
    L1: 256 KiB desc: d-4x32 KiB; i-4x32 KiB L2: 1024 KiB desc: 4x256 KiB L3: 6 MiB desc: 1x6 MiB
  Speed (MHz): avg: 3500 min/max: 800/3500 scaling: driver: intel_cpufreq governor: performance
    cores: 1: 3500 2: 3500 3: 3500 4: 3500 5: 3500 6: 3500 7: 3500 8: 3500 bogomips: 39909
  Flags-basic: avx avx2 ht lm nx pae sse sse2 sse3 sse4_1 sse4_2 ssse3 vmx
  Vulnerabilities: <filter>
Graphics:
  Device-1: Intel 4th Gen Core Processor Integrated Graphics vendor: Lenovo driver: i915 v: kernel
    arch: Gen-7.5 process: Intel 22nm built: 2013 ports: active: eDP-1 empty: HDMI-A-1
    bus-ID: 00:02.0 chip-ID: 8086:0416 class-ID: 0300
  Device-2: NVIDIA GM107M [GeForce GTX 860M] vendor: Lenovo driver: nvidia v: 580.105.08
    alternate: nouveau,nvidia_drm non-free: 550-580.xx+ status: current (as of 2025-08;
    EOL~2026-12-xx) arch: Maxwell code: GMxxx process: TSMC 28nm built: 2014-2019 pcie: gen: 1
    speed: 2.5 GT/s lanes: 16 link-max: gen: 3 speed: 8 GT/s bus-ID: 01:00.0 chip-ID: 10de:1392
    class-ID: 0302
  Device-3: Bison Lenovo EasyCamera driver: uvcvideo type: USB rev: 2.0 speed: 480 Mb/s lanes: 1
    mode: 2.0 bus-ID: 1-6:2 chip-ID: 5986:055e class-ID: 0e02 serial: <filter>
  Display: x11 server: X.Org v: 21.1.20 with: Xwayland v: 24.1.9 compositor: kwin_x11 driver: X:
    loaded: modesetting,nvidia unloaded: nouveau alternate: fbdev,intel,nv,vesa dri: crocus gpu: i915
    display-ID: :0 screens: 1
  Screen-1: 0 s-res: 1920x1080 s-dpi: 96 s-size: 508x285mm (20.00x11.22") s-diag: 582mm (22.93")
  Monitor-1: eDP-1 model: LG Display 0x0470 built: 2014 res: mode: 1920x1080 hz: 60
    scale: 100% (1) dpi: 141 gamma: 1.2 size: 345x194mm (13.58x7.64") diag: 396mm (15.6") ratio: 16:9
    modes: 1920x1080
  API: EGL v: 1.5 hw: drv: intel crocus drv: nvidia platforms: device: 0 drv: nvidia device: 1
    drv: crocus device: 3 drv: swrast gbm: drv: crocus surfaceless: drv: nvidia x11: drv: crocus
    inactive: wayland,device-2
  API: OpenGL v: 4.6.0 compat-v: 4.5 vendor: intel mesa v: 25.2.6-arch1.1 glx-v: 1.4
    direct-render: yes renderer: Mesa Intel HD Graphics 4600 (HSW GT2) device-ID: 8086:0416
    memory: 1.46 GiB unified: yes
  API: Vulkan v: 1.4.328 layers: 15 device: 0 type: integrated-gpu name: Intel HD Graphics 4600
    (HSW GT2) driver: mesa intel v: 25.2.6-arch1.1 device-ID: 8086:0416 surfaces: N/A device: 1
    type: discrete-gpu name: NVIDIA GeForce GTX 860M driver: nvidia v: 580.105.08
    device-ID: 10de:1392 surfaces: N/A device: 2 type: cpu name: llvmpipe (LLVM 21.1.4 256 bits)
    driver: mesa llvmpipe v: 25.2.6-arch1.1 (LLVM 21.1.4) device-ID: 10005:0000 surfaces: N/A
  Info: Tools: api: clinfo, eglinfo, glxinfo, vulkaninfo de: kscreen-console,kscreen-doctor
    gpu: corectrl, nvidia-settings, nvidia-smi wl: wayland-info x11: xdpyinfo, xprop, xrandr
Audio:
  Device-1: Intel Xeon E3-1200 v3/4th Gen Core Processor HD Audio vendor: Lenovo
    driver: snd_hda_intel v: kernel bus-ID: 00:03.0 chip-ID: 8086:0c0c class-ID: 0403
  Device-2: Intel 8 Series/C220 Series High Definition Audio vendor: Lenovo driver: snd_hda_intel
    v: kernel bus-ID: 00:1b.0 chip-ID: 8086:8c20 class-ID: 0403
  API: ALSA v: k6.17.7-zen1-1-zen status: kernel-api with: aoss type: oss-emulator tools: N/A
  Server-1: sndiod v: N/A status: off tools: aucat,midicat,sndioctl
  Server-2: PipeWire v: 1.4.9 status: active with: 1: pipewire-pulse status: active
    2: wireplumber status: active 3: pipewire-alsa type: plugin 4: pw-jack type: plugin
    tools: pactl,pw-cat,pw-cli,wpctl
Network:
  Device-1: Intel Wireless 3160 driver: iwlwifi v: kernel pcie: gen: 1 speed: 2.5 GT/s lanes: 1
    bus-ID: 08:00.0 chip-ID: 8086:08b4 class-ID: 0280
  IF: wlp8s0 state: up mac: <filter>
  Device-2: Realtek RTL8111/8168/8211/8411 PCI Express Gigabit Ethernet vendor: Lenovo
    driver: r8169 v: kernel pcie: gen: 1 speed: 2.5 GT/s lanes: 1 port: 3000 bus-ID: 09:00.0
    chip-ID: 10ec:8168 class-ID: 0200
  IF: eth0 state: down mac: <filter>
  IF-ID-1: virbr0 state: down mac: <filter>
  Info: services: NetworkManager, smbd, systemd-timesyncd, wpa_supplicant
Bluetooth:
  Device-1: Intel Bluetooth wireless interface driver: btusb v: 0.8 type: USB rev: 2.0
    speed: 12 Mb/s lanes: 1 mode: 1.1 bus-ID: 1-7:3 chip-ID: 8087:07dc class-ID: e001
  Report: btmgmt ID: hci0 rfk-id: 2 state: down bt-service: enabled,running rfk-block:
    hardware: no software: yes address: <filter> bt-v: 4.0 lmp-v: 6 status: discoverable: no
    pairing: no
Drives:
  Local Storage: total: 465.76 GiB used: 163.78 GiB (35.2%)
  SMART Message: Unable to run smartctl. Root privileges required.
  ID-1: /dev/sda maj-min: 8:0 vendor: Crucial model: CT500MX500SSD1 size: 465.76 GiB block-size:
    physical: 512 B logical: 512 B speed: 6.0 Gb/s tech: SSD serial: <filter> fw-rev: 023 scheme: GPT
Partition:
  ID-1: / raw-size: 448.38 GiB size: 448.38 GiB (100.00%) used: 163.78 GiB (36.5%) fs: btrfs
    dev: /dev/sda2 maj-min: 8:2
  ID-2: /boot/efi raw-size: 300 MiB size: 299.4 MiB (99.80%) used: 664 KiB (0.2%) fs: vfat
    dev: /dev/sda1 maj-min: 8:1
  ID-3: /home raw-size: 448.38 GiB size: 448.38 GiB (100.00%) used: 163.78 GiB (36.5%) fs: btrfs
    dev: /dev/sda2 maj-min: 8:2
  ID-4: /var/log raw-size: 448.38 GiB size: 448.38 GiB (100.00%) used: 163.78 GiB (36.5%)
    fs: btrfs dev: /dev/sda2 maj-min: 8:2
  ID-5: /var/tmp raw-size: 448.38 GiB size: 448.38 GiB (100.00%) used: 163.78 GiB (36.5%)
    fs: btrfs dev: /dev/sda2 maj-min: 8:2
Swap:
  Kernel: swappiness: 133 (default 60) cache-pressure: 100 (default) zswap: no
  ID-1: swap-1 type: zram size: 15.52 GiB used: 0 KiB (0.0%) priority: 100 comp: zstd
    avail: lzo-rle,lzo,lz4,lz4hc,deflate,842 dev: /dev/zram0
  ID-2: swap-2 type: partition size: 17.09 GiB used: 0 KiB (0.0%) priority: -2 dev: /dev/sda3
    maj-min: 8:3
Sensors:
  System Temperatures: cpu: 54.0 C mobo: N/A
  Fan Speeds (rpm): N/A
Info:
  Memory: total: 16 GiB available: 15.52 GiB used: 5.92 GiB (38.2%)
  Processes: 332 Power: uptime: 1h 17m states: freeze,mem,disk suspend: deep avail: s2idle
    wakeups: 0 hibernate: platform avail: shutdown, reboot, suspend, test_resume image: 6.13 GiB
    services: org_kde_powerdevil, power-profiles-daemon, upowerd Init: systemd v: 258
    default: graphical tool: systemctl
  Packages: pm: pacman pkgs: 2274 libs: 533 tools: octopi,pamac,paru Compilers: clang: 21.1.5
    gcc: 15.2.1 alt: 14 Client: shell wrapper v: 5.3.3-release inxi: 3.3.39
Garuda (2.11.1-1):
  System install date:     2024-02-16
  Garuda release:          231029
  Last full system update: 2025-11-13
  Is partially upgraded:   No
  Relevant software:       snapper NetworkManager dracut nvidia-utils nvidia-dkms garuda-hardware-profile-nvidia-closed garuda-hardware-profile-nvidia-prime-closed garuda-hardware-profile-standard garuda-hardware-profile-st
andard-x11
  Windows dual boot:       No/Undetected
  Failed units:            
--- System Health Check Report ---
24/25 checks run in 1.32 seconds ⌛
Powered by garuda-health 🦅
✅ System health check passed. No issues found.
```

I hope I haven’t forgotten anything, thank you in advance for your support.

please post the full garuda-inxi

I have edited the post, this is what is shown to me via the garuda-inxi command.

It seems like you may have skipped a few steps from the archwiki link you provided. Start at step 1 and don’t skip to step 3 until you’ve satisfied all the requirements.

1 Like

I used the same page to try and get mine working, what I finally did was the following

  1. Install gpu-passthrough- manager AUR (en) - gpu-passthrough-manager
  2. Install linux-vfio kernel
  3. Run GPU Passthrough manager and load the drivers for my non primary video card and reboot to vfio kernel

Check your garuda-inxi for a driver like this

Graphics:
  Device-1: NVIDIA GP107 [GeForce GTX 1050 Ti] vendor: ASUSTeK
    driver: vfio-pci v: N/A alternate: nouveau,nvidia_drm,nvidia
    non-free: 550-580.xx+ status: current (as of 2025-08; EOL~2026-12-xx)
    arch: Pascal code: GP10x process: TSMC 16nm built: 2016-2021 pcie: gen: 3
    speed: 8 GT/s lanes: 4 link-max: lanes: 16 bus-ID: 04:00.0
    chip-ID: 10de:1c82 class-ID: 0300

After that you should be able to add your graphics card from virt manager using the add hardware and PCI Host device

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.