diff --git a/README.md b/README.md index d5becd9..4466bad 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ A project to simplify setting up GPU passthrough on your Linux host for [QuickEMU](https://github.com/quickemu-project/quickemu)(vfio support not developed yet) and libvirt/virt-manager -Currently this project works with systems using initramfs-tools, if you want support for systems using other initrd image builders like dracut, consider contributing! - You can use it by simply running ```bash @@ -18,7 +16,7 @@ cd quickpassthrough * Enable and configure vfio modules * Configure 2nd GPU for GPU Passthrough * Dump the selected GPU rom (as some cards require a romfile for passthrough to work), however no rom patching support planned. -* Enable and configure the correct kernel modules and load them early (initramfs-tools only for now) +* Enable and configure the correct kernel modules and load them early (initramfs-tools, dracut and mkinitcpio) * Configure kernel arguments for systemd-boot (using kernelstub) * Configure kernel arguments for grub2 * Provides you with the correct kernel arguments to add to your bootloader entry if a supported bootloader is not found diff --git a/lib/apply_CHANGES.sh b/lib/apply_CHANGES.sh index 0bd5b0e..14f01e1 100755 --- a/lib/apply_CHANGES.sh +++ b/lib/apply_CHANGES.sh @@ -6,39 +6,108 @@ function make_BACKUP () { if [ ! -d "$BACKUPDIR" ]; then - # Make the backup directories - mkdir -p "$BACKUPDIR/etc/initramfs-tools" - mkdir -p "$BACKUPDIR/etc/modprobe.d" - mkdir -p "$BACKUPDIR/etc/default" - - # Backup system files - sudo cp -v "/etc/modules" "$BACKUPDIR/etc/modules" - sudo cp -v "/etc/initramfs-tools/modules" "$BACKUPDIR/etc/initramfs-tools/modules" - sudp cp -v "/etc/default/grub" "$BACKUPDIR/etc/default/grub" - - # If a vfio.conf file exists, backup that too - if [ -f "/etc/modprobe.d/vfio.conf" ]; + # Make the backup directories and backup the files + if [ -d "/etc/initramfs-tools" ]; then - sudo cp -v "/etc/modprobe.d/vfio.conf" "$BACKUPDIR/etc/modprobe.d/vfio.conf" + mkdir -p "$BACKUPDIR/etc/initramfs-tools" + cp -v "/etc/initramfs-tools/modules" "$BACKUPDIR/etc/initramfs-tools/modules" + cp -v "/etc/modules" "$BACKUPDIR/etc/modules" + + elif [ -d "/etc/dracut.conf" ]; + then + mkdir -p "$BACKUPDIR/etc/dracut.conf.d" + if [ -f "/etc/dracut.conf.d/10-vfio.conf" ]; + then + cp -v "/etc/dracut.conf.d/10-vfio.conf" "$BACKUPDIR/etc/dracut.conf.d/10-vfio.conf" + + fi + + elif [ -f "/etc/mkinitcpio.conf" ]; + then + mkdir -p "$BACKUPDIR/etc" + cp -v "/etc/mkinitcpio.conf" "$BACKUPDIR/etc/mkinitcpio.conf" + fi - - echo "Backup completed!" + + if [ -f "/etc/default/grub" ]; + then + mkdir -p "$BACKUPDIR/etc/default" + cp -v "/etc/default/grub" "$BACKUPDIR/etc/default/grub" + + fi + + if [ -d "/etc/modprobe.d" ]; + then + mkdir -p "$BACKUPDIR/etc/modprobe.d" + + # If a vfio.conf file exists, backup that too + if [ -f "/etc/modprobe.d/vfio.conf" ]; + then + cp -v "/etc/modprobe.d/vfio.conf" "$BACKUPDIR/etc/modprobe.d/vfio.conf" + + fi + + fi + + printf "Backup completed!\n" else - echo "A backup already exists! -backup skipped." + echo " +A backup already exists! +backup skipped. +" fi } function copy_FILES () { echo "Starting copying files to the system!" - sudo cp -v "$SCRIPTDIR/$ETCMODULES" "/etc/modules" - sudo cp -v "$SCRIPTDIR/$INITRAMFS/modules" "/etc/initramfs-tools/modules" - sudo cp -v "$SCRIPTDIR/$MODPROBE/vfio.conf" "/etc/modprobe.d/vfio.conf" - echo "" - echo "Rebuilding initramfs" - sudo update-initramfs -u + if [ -d "/etc/modprobe.d" ]; + then + sudo cp -v "$SCRIPTDIR/$MODPROBE/vfio.conf" "/etc/modprobe.d/vfio.conf" + + fi + + if [ -d "/etc/initramfs-tools" ]; + then + sudo cp -v "$SCRIPTDIR/$ETCMODULES" "/etc/modules" + sudo cp -v "$SCRIPTDIR/$INITRAMFS/modules" "/etc/initramfs-tools/modules" + echo " +Rebuilding initramfs" + sudo update-initramfs -u + + elif [ -f "/etc/dracut.conf" ]; + then + cp -v "$SCRIPTDIR/$DRACUT/10-vfio.conf" "/etc/dracut.conf.d/10-vfio.conf" + echo " +Rebuilding initramfs" + sudo dracut -f -v --kver "$(uname -r)" + + elif [ -f "/etc/mkinitcpio.conf" ]; + then + cp -v "$SCRIPTDIR/$MKINITCPIO" "/etc/mkinitcpio.conf" + echo " +Rebuilding initramfs" + sudo mkinitcpio -P + + else + echo " +Unsupported initramfs infrastructure +In order to make vfio work, please add these modules to your +initramfs and make them load early, then rebuild initramfs. + +vfio +vfio_iommu_type1 +vfio_pci +vfio_virqfd + + +Press ENTER to continue once you have done the above." + read -r + + fi + + } function apply_CHANGES () { @@ -55,18 +124,18 @@ By proceeding, a backup of your system's version of these files will be placed i $SCRIPTDIR/backup unless a backup already exist. -Then the files above will be copied to your system followed by running \"update-initramfs -u\" -to build your new initrd image (all of this will require sudo permissions!)" +Then the files above will be copied to your system followed by running followed by updating your +initramfs and then attempt adding new kernel arguments to your bootloader." - read -p "Do you want to proceed with the installation of the files? (no=skip) [Y/n]: " YESNO + read -p "Do you want to proceed with the installation of the files? (no=quit) [Y/n]: " YESNO case "${YESNO}" in - [Yy]*) - make_BACKUP - copy_FILES - exec "$SCRIPTDIR/lib/set_CMDLINE.sh" + [Nn]*) + exit 1 ;; *) + make_BACKUP + copy_FILES exec "$SCRIPTDIR/lib/set_CMDLINE.sh" ;; esac @@ -74,7 +143,8 @@ to build your new initrd image (all of this will require sudo permissions!)" function main () { - SCRIPTDIR=$(dirname "$(which $0)" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + apply_CHANGES } diff --git a/lib/get_GPU.sh b/lib/get_GPU.sh index cf8772c..e8a7633 100755 --- a/lib/get_GPU.sh +++ b/lib/get_GPU.sh @@ -15,14 +15,14 @@ does not belong to itself. Both cards must also have unique hardware ids [xxxx:y Press q to quit " - read -p "Which group number do you want to check?: " IOMMU_GROUP + read -r -p "Which group number do you want to check?: " IOMMU_GROUP case "${IOMMU_GROUP}" in [1-9]*) - exec "$SCRIPTDIR/lib/get_GPU_GROUP.sh" $IOMMU_GROUP + exec "$SCRIPTDIR/lib/get_GPU_GROUP.sh" "$IOMMU_GROUP" ;; [Qq]*) - printf "Aborted, your setup is incomplete! + echo "Aborted, your setup is incomplete! DO NOT use any of the files from $SCRIPTDIR/config ! " ;; @@ -33,7 +33,7 @@ DO NOT use any of the files from $SCRIPTDIR/config ! } function main () { - SCRIPTDIR=$(dirname "$(which $0)" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") get_GPU } diff --git a/lib/get_GPU_GROUP.sh b/lib/get_GPU_GROUP.sh index 917a6c5..208408a 100755 --- a/lib/get_GPU_GROUP.sh +++ b/lib/get_GPU_GROUP.sh @@ -1,6 +1,6 @@ #!/bin/bash -function get_GROUP () { +function get_GPU_GROUP () { clear # Get the config paths source "$SCRIPTDIR/lib/paths.sh" @@ -24,32 +24,49 @@ To use any of these devices for passthrough ALL of them has to be passed through To return to the previous page just press ENTER without typing in anything. " - read -p "Do you want to use these devices for passthrough? [y/N]: " YESNO + read -r -p "Do you want to use these devices for passthrough? [y/N]: " YESNO case "${YESNO}" in [Yy]*) # Get the hardware ids from the selected group local GPU_DEVID - GPU_DEVID=$($SCRIPTDIR/utils/ls-iommu | grep -i "group $1" | perl -pe "s/.+\[([0-9a-f]{4}:[0-9a-f]{4})\].+/\1/" | perl -pe "s/\n/,/" | perl -pe "s/,$/\n/") + GPU_DEVID=$("$SCRIPTDIR/utils/ls-iommu" | grep -i "group $1" | perl -pe "s/.+\[([0-9a-f]{4}:[0-9a-f]{4})\].+/\1/" | perl -pe "s/\n/,/" | perl -pe "s/,$/\n/") # Get the PCI ids local PCI_ID - PCI_ID=$($SCRIPTDIR/utils/ls-iommu | grep -i "group $1" | cut -d " " -f 4 | perl -pe "s/([0-9a-f]{2}:[0-9a-f]{2}.[0-9a-f]{1})\n/\"\1\" /" | perl -pe "s/\s$//") + PCI_ID=$("$SCRIPTDIR/utils/ls-iommu" | grep -i "group $1" | cut -d " " -f 4 | perl -pe "s/([0-9a-f]{2}:[0-9a-f]{2}.[0-9a-f]{1})\n/\"\1\" /" | perl -pe "s/\s$//") # Write the GPU_PCI_IDs to the config that quickemu might make use of in the future - printf "GPU_PCI_ID=($PCI_ID) + echo "GPU_PCI_ID=($PCI_ID) USB_CTL_ID=() " > "$SCRIPTDIR/$QUICKEMU/qemu-vfio_vars.conf" # Get the rom PCI_ID local ROM_PCI_ID - ROM_PCI_ID=$($SCRIPTDIR/utils/ls-iommu | grep -i "vga" | grep -i "group $1" | cut -d " " -f 4) + ROM_PCI_ID=$("$SCRIPTDIR/utils/ls-iommu" | grep -i "vga" | grep -i "group $1" | cut -d " " -f 4) # Get the GPU ROM "$SCRIPTDIR/lib/get_GPU_ROM.sh" "$ROM_PCI_ID" # Start setting up modules - exec "$SCRIPTDIR/lib/set_MODULES.sh" $GPU_DEVID + if [ -d "/etc/initramfs-tools" ]; + then + exec "$SCRIPTDIR/lib/set_INITRAMFSTOOLS.sh" "$GPU_DEVID" + + elif [ -d "/etc/dracut.conf" ]; + then + exec "$SCRIPTDIR/lib/set_DRACUT.sh" "$GPU_DEVID" + + elif [ -f "/etc/mkinitcpio.conf" ]; + then + exec "$SCRIPTDIR/lib/set_MKINITCPIO.sh" "$GPU_DEVID" + else + # Bind GPU to VFIO + "$SCRIPTDIR/lib/set_VFIO.sh" "$1" + + # Configure modprobe + "$SCRIPTDIR/lib/set_MODPROBE.sh" "$1" + fi ;; *) exec "$SCRIPTDIR/lib/get_GPU.sh" @@ -58,9 +75,9 @@ USB_CTL_ID=() } function main () { - SCRIPTDIR=$(dirname "$(which $0)" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") - get_GROUP $1 + get_GPU_GROUP "$1" } -main $1 +main "$1" diff --git a/lib/get_GPU_ROM.sh b/lib/get_GPU_ROM.sh index f4e6672..568d2af 100755 --- a/lib/get_GPU_ROM.sh +++ b/lib/get_GPU_ROM.sh @@ -6,7 +6,7 @@ function get_GPU_ROM () { source "$SCRIPTDIR/lib/paths.sh" VBIOS_PATH=$(find /sys/devices -name rom | grep "$1") - printf "We will now attempt to dump the vbios of your selected GPU. + echo "We will now attempt to dump the vbios of your selected GPU. Passing a VBIOS rom to the card used for passthrough is required for some cards, but not all. Some cards also requires you to patch your VBIOS romfile, check online if this is neccessary for your card. The VBIOS will be read from $VBIOS_PATH @@ -17,17 +17,19 @@ sudo cat $VBIOS_PATH > $SCRIPTDIR/$QUICKEMU/vfio_card.rom echo 0 | sudo tee $VBIOS_PATH " - read -p "Do you want to dump the VBIOS, choosing N will skip this step [y/N]: " YESNO + read -r -p "Do you want to dump the VBIOS, choosing N will skip this step [y/N]: " YESNO case "${YESNO}" in [Yy]*) echo 1 | sudo tee "$VBIOS_PATH" sudo cat "$VBIOS_PATH" > "$SCRIPTDIR/$QUICKEMU/vfio_card.rom" sudo md5sum "$VBIOS_PATH" | cut -d " " -f 1 > "$SCRIPTDIR/$QUICKEMU/vfio_card.rom.md5" - local ROM_MD5=$(sudo md5sum "$VBIOS_PATH" | cut -d " " -f 1) + local ROM_MD5 + ROM_MD5=$(sudo md5sum "$VBIOS_PATH" | cut -d " " -f 1) echo 0 | sudo tee "$VBIOS_PATH" - local ROMFILE_MD5=$(md5sum "$SCRIPTDIR/$QUICKEMU/vfio_card.rom" | cut -d " " -f 1) + local ROMFILE_MD5 + ROMFILE_MD5=$(md5sum "$SCRIPTDIR/$QUICKEMU/vfio_card.rom" | cut -d " " -f 1) - if [ -f "$SCRIPTDIR"/$QUICKEMU/vfio_card.rom ]; + if [ -f "$SCRIPTDIR/$QUICKEMU/vfio_card.rom" ]; then if [ "$ROM_MD5" == "$ROMFILE_MD5" ]; then @@ -35,14 +37,14 @@ echo 0 | sudo tee $VBIOS_PATH echo "Dumping of VBIOS successful!" echo 'GPU_ROMFILE="vfio_card.rom"' >> "$SCRIPTDIR/$QUICKEMU/qemu-vfio_vars.conf" - read -p "Press ENTER to continue." ENTER + read -r -p "Press ENTER to continue." else echo "Checksums does not match!" echo "Dumping of VBIOS failed, skipping romfile" mv "$SCRIPTDIR/$QUICKEMU/vfio_card.rom" "$SCRIPTDIR/$QUICKEMU/vfio_card.rom.fail" echo 'GPU_ROMFILE=""' >> "$SCRIPTDIR/$QUICKEMU/qemu-vfio_vars.conf" - read -p "Press ENTER to continue." ENTER + read -r -p "Press ENTER to continue." fi else echo 'GPU_ROMFILE=""' >> "$SCRIPTDIR/$QUICKEMU/qemu-vfio_vars.conf" @@ -59,9 +61,9 @@ echo 0 | sudo tee $VBIOS_PATH function main () { - SCRIPTDIR=$(dirname "$(which $0)" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") - get_GPU_ROM $1 + get_GPU_ROM "$1" } -main $1 \ No newline at end of file +main "$1" \ No newline at end of file diff --git a/lib/get_USB_CTL.sh b/lib/get_USB_CTL.sh index 9346c35..ccda58c 100755 --- a/lib/get_USB_CTL.sh +++ b/lib/get_USB_CTL.sh @@ -15,11 +15,11 @@ is only needed if you intend to use other devices than just mouse and keyboard w Press q to quit " - read -p "Which group number do you want to check?: " IOMMU_GROUP + read -r -p "Which group number do you want to check?: " IOMMU_GROUP case "${IOMMU_GROUP}" in [1-9]*) - exec "$SCRIPTDIR/lib/get_USB_CTL_GROUP.sh" $IOMMU_GROUP + exec "$SCRIPTDIR/lib/get_USB_CTL_GROUP.sh" "$IOMMU_GROUP" ;; [Qq]*) exec "$SCRIPTDIR/lib/apply_CHANGES.sh" @@ -31,7 +31,7 @@ Press q to quit } function main () { - SCRIPTDIR=$(dirname "$(which $0)" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") get_USB_CTL } diff --git a/lib/get_USB_CTL_GROUP.sh b/lib/get_USB_CTL_GROUP.sh index 6dcfedb..956e9bb 100755 --- a/lib/get_USB_CTL_GROUP.sh +++ b/lib/get_USB_CTL_GROUP.sh @@ -20,7 +20,7 @@ To use any of the devices shown for passthrough, all of them have to be passed t To return to the previous page just press ENTER. " - read -p "Do you want to use the displayed devices for passthrough? [y/N]: " YESNO + read -r -p "Do you want to use the displayed devices for passthrough? [y/N]: " YESNO case "${YESNO}" in [Yy]*) @@ -39,7 +39,7 @@ To return to the previous page just press ENTER. } function main () { - SCRIPTDIR=$(dirname "$(which $0)" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") get_USB_CTL_GROUP $1 } diff --git a/lib/paths.sh b/lib/paths.sh index 745426f..fb632ea 100755 --- a/lib/paths.sh +++ b/lib/paths.sh @@ -3,4 +3,6 @@ MODPROBE="config/etc/modprobe.d" INITRAMFS="config/etc/initramfs-tools" ETCMODULES="config/etc/modules" DEFAULT="config/etc/default" -QUICKEMU="config/quickemu" \ No newline at end of file +QUICKEMU="config/quickemu" +DRACUT="config/etc/dracut.conf.d" +MKINITCPIO="config/etc/mkinitcpio.conf" \ No newline at end of file diff --git a/lib/set_CMDLINE.sh b/lib/set_CMDLINE.sh index 3497532..0a3ef0b 100755 --- a/lib/set_CMDLINE.sh +++ b/lib/set_CMDLINE.sh @@ -48,17 +48,17 @@ function set_GRUB () { local GRUB_CMDLINE_LINUX # Check if there is a GRUB_CMDLINE_LINUX_DEFAULT line in grub config - if grep -q "GRUB_CMDLINE_LINUX_DEFAULT=" "$SCRIPTDIR/config/etc/default/grub" ; + if grep -q "GRUB_CMDLINE_LINUX_DEFAULT=" "$SCRIPTDIR/$DEFAULT/grub" ; then # Update the GRUB_CMDLINE_LINUX_DEFAULT line GRUB_CMDLINE=$(cat "/etc/default/grub" | grep -P "^GRUB_CMDLINE_LINUX_DEFAULT" | perl -pe "s/GRUB_CMDLINE_LINUX_DEFAULT=\"(.+)\"/\1/" | perl -pe "s/iommu=(pt|on)|amd_iommu=on|vfio_pci.ids=.+|vfio_pci.disable_vga=\d{1}//g" | perl -pe "s/(^\s+|\s+$)//g") GRUB_CMDLINE_LINUX=$(cat "/etc/default/grub" | grep -P "^GRUB_CMDLINE_LINUX_DEFAULT") - perl -pi -e "s/${GRUB_CMDLINE_LINUX}/GRUB_CMDLINE_LINUX_DEFAULT=\"${GRUB_CMDLINE} ${CMDLINE}\"/" "${SCRIPTDIR}/config/etc/default/grub" + perl -pi -e "s/${GRUB_CMDLINE_LINUX}/GRUB_CMDLINE_LINUX_DEFAULT=\"${GRUB_CMDLINE} ${CMDLINE}\"/" "${SCRIPTDIR}/$DEFAULT/grub" else # Update the GRUB_CMDLINE_LINUX line GRUB_CMDLINE=$(cat "/etc/default/grub" | grep -P "^GRUB_CMDLINE_LINUX" | perl -pe "s/GRUB_CMDLINE_LINUX=\"(.+)\"/\1/" | perl -pe "s/iommu=(pt|on)|amd_iommu=on|vfio_pci.ids=.+|vfio_pci.disable_vga=\d{1}//g" | perl -pe "s/(^\s+|\s+$)//g") GRUB_CMDLINE_LINUX=$(cat "/etc/default/grub" | grep -P "^GRUB_CMDLINE_LINUX") - perl -pi -e "s/${GRUB_CMDLINE_LINUX}/GRUB_CMDLINE_LINUX=\"${GRUB_CMDLINE} ${CMDLINE}\"/" "${SCRIPTDIR}/config/etc/default/grub" + perl -pi -e "s/${GRUB_CMDLINE_LINUX}/GRUB_CMDLINE_LINUX=\"${GRUB_CMDLINE} ${CMDLINE}\"/" "${SCRIPTDIR}/$DEFAULT/grub" fi @@ -69,7 +69,7 @@ $SCRIPTDIR/backup/etc/default/grub " read -r -p "Press ENTER to continue" - sudo cp -v "$SCRIPTDIR/config/etc/default/grub" "/etc/default/grub" + sudo cp -v "$SCRIPTDIR/$DEFAULT/grub" "/etc/default/grub" # Generate grub.cfg if [ -d "/boot/grub" ]; @@ -116,8 +116,8 @@ proceed to add it to your virtual machines. A backup the files we replaced on your system can be found inside $SCRIPTDIR/backup/ -In order to restore these files just copy them back to your system and run -\"sudo update-initramfs -u\" +In order to restore these files just copy them back to your system and +rebuild your initramfs image. You can remove the the vfio_pci kernel arguments from the linux line in your bootloader to disable/unbind the graphic card from the vfio driver on boot. @@ -125,7 +125,7 @@ to disable/unbind the graphic card from the vfio driver on boot. The files inside \"$SCRIPTDIR/$QUICKEMU\" are currently unused files, however they provide the required information that the QuickEMU project can hook into and use to add support for VFIO enabled VMs. -The PCI Devices with these IDs are what you should add to your VMs: +The PCI Devices with these IDs are what you should add to your VMs using Virt Manager: NOTE: Some AMD GPUs will require the vendor-reset kernel module from https://github.com/gnif/vendor-reset to be installed!" source "${SCRIPTDIR}/config/quickemu/qemu-vfio_vars.conf" @@ -139,7 +139,17 @@ NOTE: Some AMD GPUs will require the vendor-reset kernel module from https://git echo "* $dev" done - echo "For performance tuning and advanced configuration look at: +echo " +To add the graphic card to your VM using qemu directly, use the following arguments:" + for dev in "${GPU_PCI_ID[@]}" + do + + echo -n "-device vfio-pci,host=$dev " + done + printf "\n" + + echo " +For performance tuning and advanced configuration look at: https://github.com/HikariKnight/vfio-setup-docs/wiki" } @@ -149,7 +159,7 @@ function set_CMDLINE () { BOOTLOADER_AUTOCONFIG=0 # If kernelstub is detected (program to manage systemd-boot) - if which kernelstub ; + if which kernelstub > /dev/null 2>&1 ; then # Configure kernelstub set_KERNELSTUB @@ -157,7 +167,7 @@ function set_CMDLINE () { fi # If grub exists - if which grub-mkconfig ; + if which grub-mkconfig > /dev/null 2>&1 ; then # Configure grub set_GRUB @@ -169,7 +179,8 @@ function set_CMDLINE () { function main () { - SCRIPTDIR=$(dirname "$(which $0)" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + set_CMDLINE } diff --git a/lib/set_DRACUT.sh b/lib/set_DRACUT.sh new file mode 100755 index 0000000..4989f9a --- /dev/null +++ b/lib/set_DRACUT.sh @@ -0,0 +1,28 @@ +#!/bin/bash +function set_DRACUT () { + # Get the config paths + source "$SCRIPTDIR/lib/paths.sh" + + # Write the dracut config + echo "add_drivers+=\" vfio_pci vfio vfio_iommu_type1 vfio_virqfd \"" > "$SCRIPTDIR/$DRACUT/10-vfio.conf" + + # Get the kernel_args file content + CMDLINE=$(cat "$SCRIPTDIR/config/kernel_args") + + # Update kernel_args to load the vfio_pci module early in dracut (as dracut uses kernel arguments for early loading) + echo "$CMDLINE rd.driver.pre=vfio_pci" > "$SCRIPTDIR/config/kernel_args" + + # Bind GPU to VFIO + "$SCRIPTDIR/lib/set_VFIO.sh" "$1" + + # Configure modprobe + exec "$SCRIPTDIR/lib/set_MODPROBE.sh" "$1" +} + +function main () { + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + + set_DRACUT "$1" +} + +main "$1" \ No newline at end of file diff --git a/lib/set_INITRAMFSTOOLS.sh b/lib/set_INITRAMFSTOOLS.sh new file mode 100755 index 0000000..6210112 --- /dev/null +++ b/lib/set_INITRAMFSTOOLS.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +function insert_INITRAMFSTOOLS() { + # Get the header and enabled modules separately from the /etc/modules file + local MODULES_HEADER + local MODULES_ENABLED + local VENDOR_RESET + MODULES_HEADER=$(head -n $1 "$2" | grep -P "^#" | grep -v "# Added by quickpassthrough") + MODULES_ENABLED=$(cat "$2" | grep -vP "^#" | grep -v "vendor-reset") + VENDOR_RESET=0 + + # If vendor-reset is present + if grep -q "vendor-reset" "$2" ; + then + VENDOR_RESET=1 + fi + + # Write header + echo "$MODULES_HEADER" > "$2" + + # If vendor-reset existed from before + if [ $VENDOR_RESET == 1 ]; + then + # Write vendor-reset as the first module! + echo "vendor-reset" >> "$2" + fi + + # Append vfio + printf " +# Added by quickpassthrough # +vfio +vfio_iommu_type1 +vfio_pci +vfio_virqfd +############################# +" >> "$2" + + # Write the previously enabled modules under vfio in the load order + echo "$MODULES_ENABLED" >> "$2" +} + +function set_INITRAMFSTOOLS () { + # Get the config paths + source "$SCRIPTDIR/lib/paths.sh" + + # Insert modules in the correct locations as early as possible without + # conflicting with vendor-reset module if it is enabled + insert_INITRAMFSTOOLS 4 "$SCRIPTDIR/$ETCMODULES" + insert_INITRAMFSTOOLS 11 "$SCRIPTDIR/$INITRAMFS/modules" + + # Bind GPU to VFIO + "$SCRIPTDIR/lib/set_VFIO.sh" "$1" + + # Configure modprobe + exec "$SCRIPTDIR/lib/set_MODPROBE.sh" "$1" +} + + +function main () { + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + + set_INITRAMFSTOOLS "$1" +} + +main "$1" diff --git a/lib/set_MKINITCPIO.sh b/lib/set_MKINITCPIO.sh new file mode 100755 index 0000000..2a584ec --- /dev/null +++ b/lib/set_MKINITCPIO.sh @@ -0,0 +1,33 @@ +#!/bin/bash +function set_MKINITCPIO () { + # Get the config paths + source "$SCRIPTDIR/lib/paths.sh" + + # Grab the current modules but exclude vfio and vendor-reset + CURRENTMODULES=$(grep -P "^MODULES" "$SCRIPTDIR/$MKINITCPIO" | perl -pe "s/MODULES=\((.+)\)/\1/") + MODULES="$(grep -P "^MODULES" "$SCRIPTDIR/$MKINITCPIO" | perl -pe "s/MODULES=\((.+)\)/\1/" | perl -pe "s/\s?(vfio_iommu_type1|vfio_pci|vfio_virqfd|vfio|vendor-reset)\s?//g")" + + # Check if vendor-reset is present + if [[ $CURRENTMODULES =~ "vendor-reset" ]]; + then + # Inject vfio modules with vendor-reset + perl -pi -e "s/MODULES=\(${CURRENTMODULES}\)/MODULES=\(vendor-reset vfio vfio_iommu_type1 vfio_pci vfio_virqfd ${MODULES}\)/" "$SCRIPTDIR/$MKINITCPIO" + else + # Inject vfio modules + perl -pi -e "s/MODULES=\(${CURRENTMODULES}\)/MODULES=\(vfio vfio_iommu_type1 vfio_pci vfio_virqfd ${MODULES}\)/" "$SCRIPTDIR/$MKINITCPIO" + fi + + # Bind GPU to VFIO + "$SCRIPTDIR/lib/set_VFIO.sh" "$1" + + # Configure modprobe + exec "$SCRIPTDIR/lib/set_MODPROBE.sh" "$1" +} + +function main () { + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + + set_MKINITCPIO "$1" +} + +main "$1" \ No newline at end of file diff --git a/lib/set_MODPROBE.sh b/lib/set_MODPROBE.sh new file mode 100755 index 0000000..1c54229 --- /dev/null +++ b/lib/set_MODPROBE.sh @@ -0,0 +1,39 @@ +#!/bin/bash +function set_MODPROBE () { + # Get the config paths + source "$SCRIPTDIR/lib/paths.sh" + + # Assign the GPU device ids to a variable + GPU_DEVID="$1" + + # If VGA is disabled + if grep -q "vfio_pci.disable_vga=1" "$SCRIPTDIR/config/kernel_args" ; + then + # Modify our GPU_DEVID line to containe disable_vga=1 + GPU_DEVID="${GPU_DEVID} disable_vga=1" + fi + + # Write the vfio modprobe config + printf "## This is an autogenerated file that stubs your graphic card for use with vfio +## This file should be placed inside /etc/modprobe.d/ +# Uncomment the line below to \"hardcode\" your graphic card to be bound to the vfio-pci driver. +# In most cases this should not be neccessary, it will also prevent you from turning off vfio in the bootloader. +#options vfio_pci ids=%s + +# Make sure vfio_pci is loaded before these modules: nvidia, nouveau, amdgpu and radeon +softdep nvidia pre: vfio vfio_pci +softdep nouveau pre: vfio vfio_pci +softdep amdgpu pre: vfio vfio_pci +softdep radeon pre: vfio vfio_pci +" "${GPU_DEVID}" > "$SCRIPTDIR/$MODPROBE/vfio.conf" + + exec "$SCRIPTDIR/lib/get_USB_CTL.sh" +} + +function main () { + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + + set_MODPROBE "$1" +} + +main "$1" \ No newline at end of file diff --git a/lib/set_MODULES.sh b/lib/set_MODULES.sh deleted file mode 100755 index 1a839ae..0000000 --- a/lib/set_MODULES.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash - -function insert_MODULES() { - # Get the header and enabled modules separately from the /etc/modules file - local MODULES_HEADER - local MODULES_ENABLED - local VENDOR_RESET - MODULES_HEADER=$(head -n $1 "$2" | grep -P "^#" | grep -v "# Added by quickpassthrough") - MODULES_ENABLED=$(cat "$2" | grep -vP "^#" | grep -v "vendor-reset") - VENDOR_RESET=0 - - # If vendor-reset is present - if grep -q "vendor-reset" "$2" ; - then - VENDOR_RESET=1 - fi - - # Write header - echo "$MODULES_HEADER" > "$2" - - # If vendor-reset existed from before - if [ $VENDOR_RESET == 1 ]; - then - # Write vendor-reset as the first module! - echo "vendor-reset" >> "$2" - fi - - # Append vfio - printf " -# Added by quickpassthrough # -vfio -vfio_iommu_type1 -vfio_pci -vfio_virqfd -############################# -" >> "$2" - - # Write the previously enabled modules under vfio in the load order - echo "$MODULES_ENABLED" >> "$2" -} - -function set_MODULES () { - # Get the config paths - source "$SCRIPTDIR/lib/paths.sh" - - # Insert modules in the correct locations as early as possible without - # conflicting with vendor-reset module if it is enabled - insert_MODULES 4 "$SCRIPTDIR/$ETCMODULES" - insert_MODULES 11 "$SCRIPTDIR/$INITRAMFS/modules" - - # Assign the GPU device ids to a variable - GPU_DEVID="$1" - - # Get the kernel_args file content - CMDLINE=$(cat "$SCRIPTDIR/config/kernel_args") - - # Ask if we shall disable video output on this card - echo " -Disabling video output in Linux for the card you want to use in a VM -will make it easier to successfully do the passthrough without issues." - read -p "Do you want to force disable video output in linux on this card? [Y/n]: " DISABLE_VGA - case "${DISABLE_VGA}" in - [Yy]*) - # Update kernel_args file - echo "${CMDLINE} vfio_pci.ids=${GPU_DEVID} vfio_pci.disable_vga=1" > "$SCRIPTDIR/config/kernel_args" - - # Update GPU_DEVID - GPU_DEVID="$GPU_DEVID disable_vga=1" - ;; - [Nn]*) - echo "" - ;; - *) - # Update kernel_args file - echo "${CMDLINE} vfio_pci.ids=${GPU_DEVID} vfio_pci.disable_vga=1" > "$SCRIPTDIR/config/kernel_args" - - # Update GPU_DEVID - GPU_DEVID="$GPU_DEVID disable_vga=1" - ;; - esac - - # Write the vfio modprobe config - printf "## This is an autogenerated file that stubs your graphic card for use with vfio -## This file should be placed inside /etc/modprobe.d/ -# Uncomment the line below to \"hardcode\" your graphic card to be bound to the vfio-pci driver. -# In most cases this should not be neccessary, it will also prevent you from turning off vfio in the bootloader. -#options vfio_pci ids=%s - -# Make sure vfio_pci is loaded before these modules: nvidia, nouveau, amdgpu and radeon -softdep nvidia pre: vfio vfio_pci -softdep nouveau pre: vfio vfio_pci -softdep amdgpu pre: vfio vfio_pci -softdep radeon pre: vfio vfio_pci -" "${GPU_DEVID}" > "$SCRIPTDIR/$MODPROBE/vfio.conf" - - exec "$SCRIPTDIR/lib/get_USB_CTL.sh" -} - - -function main () { - SCRIPTDIR=$(dirname "$(which $0)" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") - - set_MODULES "$1" -} - -main "$1" diff --git a/lib/set_VFIO.sh b/lib/set_VFIO.sh new file mode 100755 index 0000000..18da794 --- /dev/null +++ b/lib/set_VFIO.sh @@ -0,0 +1,45 @@ +#!/bin/bash +function set_VFIO () { + # Get the config paths + source "$SCRIPTDIR/lib/paths.sh" + + # Assign the GPU device ids to a variable + GPU_DEVID="$1" + + # Get the kernel_args file content + CMDLINE=$(cat "$SCRIPTDIR/config/kernel_args") + + # Ask if we shall disable video output on this card + echo " +Disabling video output in Linux for the card you want to use in a VM +will make it easier to successfully do the passthrough without issues." + read -r -p "Do you want to force disable video output in linux on this card? [Y/n]: " DISABLE_VGA + case "${DISABLE_VGA}" in + [Yy]*) + # Update kernel_args file + echo "${CMDLINE} vfio_pci.ids=${GPU_DEVID} vfio_pci.disable_vga=1" > "$SCRIPTDIR/config/kernel_args" + + # Update GPU_DEVID + GPU_DEVID="$GPU_DEVID disable_vga=1" + ;; + [Nn]*) + # Update kernel_args file + echo "${CMDLINE} vfio_pci.ids=${GPU_DEVID}" > "$SCRIPTDIR/config/kernel_args" + ;; + *) + # Update kernel_args file + echo "${CMDLINE} vfio_pci.ids=${GPU_DEVID} vfio_pci.disable_vga=1" > "$SCRIPTDIR/config/kernel_args" + + # Update GPU_DEVID + GPU_DEVID="$GPU_DEVID disable_vga=1" + ;; + esac +} + +function main () { + SCRIPTDIR=$(dirname "$(realpath "$0")" | perl -pe "s/\/\.\.\/lib//" | perl -pe "s/\/lib$//") + + set_VFIO "$1" +} + +main "$1" \ No newline at end of file diff --git a/vfio-setup b/vfio-setup index e1c625f..7217262 100755 --- a/vfio-setup +++ b/vfio-setup @@ -1,15 +1,12 @@ #!/bin/bash # Get the scripts directory -SCRIPTDIR=$(dirname "$(which $0)") +SCRIPTDIR=$(dirname "$(realpath "$0")") cd "$SCRIPTDIR" # Get the config paths source "$SCRIPTDIR/lib/paths.sh" -# Make sure all the scripts are executable -chmod +x "$SCRIPTDIR/lib/*" - # Get the CPU Vendor CPU_VENDOR=$(cat /proc/cpuinfo | grep vendor | head -1 | cut -f 2 | cut -d " " -f 2) CMDLINE="iommu=pt" @@ -91,35 +88,48 @@ fi # Make the directories mkdir -p "$SCRIPTDIR/$MODPROBE" -mkdir -p "$SCRIPTDIR/$DEFAULT" -mkdir -p "$SCRIPTDIR/$INITRAMFS" mkdir -p "$SCRIPTDIR/$QUICKEMU" # Write the cmdline file echo "$CMDLINE" > "$SCRIPTDIR/config/kernel_args" -# Copy system configs into our config folder so we can safely edit them - +# Copy system configs that exists into our config folder so we can safely edit them if [ -f "/etc/modules" ]; then # This copies /etc/modules without the vfio module lines grep -v "vfio" "/etc/modules" > "$SCRIPTDIR/$ETCMODULES" -else - touch "$SCRIPTDIR/$ETCMODULES" fi if [ -f "/etc/default/grub" ]; then + # Create the default folder + mkdir -p "$SCRIPTDIR/$DEFAULT" + # Copy grub config cp "/etc/default/grub" "$SCRIPTDIR/$DEFAULT/grub" fi if [ -f "/etc/initramfs-tools/modules" ]; then + # Create the initramfs folder + mkdir -p "$SCRIPTDIR/$INITRAMFS" + # This copies /etc/initramfs-tools/modules without the vfio modules grep -v "vfio" "/etc/initramfs-tools/modules" > "$SCRIPTDIR/$INITRAMFS/modules" -else - touch "$SCRIPTDIR/$INITRAMFS" +fi + +if [ -f "/etc/mkinitcpio.conf" ]; +then + # Copy mkinitcpio.conf to our config folder + cp "/etc/mkinitcpio.conf" "$SCRIPTDIR/$MKINITCPIO" +fi + +if [ -f "/etc/dracut.conf" ]; +then + # Create the dracut folder + mkdir -p "$SCRIPTDIR/$DRACUT" + # Create a dracut.conf.d file + touch "$SCRIPTDIR/$DRACUT/10-vfio.conf" fi # Run ls-iommu so we can verify that IOMMU properly working