diff --git a/machines/mynix/default.nix b/machines/mynix/default.nix index 98d9e0c..79a2793 100644 --- a/machines/mynix/default.nix +++ b/machines/mynix/default.nix @@ -9,6 +9,15 @@ width = 3440; height = 1440; refresh = 100; + vm.passthrough = { + enable = true; + driver = "amdgpu"; + guest = "myndows"; + id = "1002:73df"; + init = true; + intel = true; + node = "pci_0000_03_00_0"; + }; }; boot = { diff --git a/options/custom/desktops/hyprland/settings.nix b/options/custom/desktops/hyprland/settings.nix index e00e65b..9b6ef2f 100644 --- a/options/custom/desktops/hyprland/settings.nix +++ b/options/custom/desktops/hyprland/settings.nix @@ -9,14 +9,17 @@ with lib; let audio = config.home-manager.users.${config.custom.username}.home.file.".local/bin/audio".source; clipse = "${pkgs.clipse}/bin/clipse"; firefox-esr = "${config.home-manager.users.${config.custom.username}.programs.firefox.finalPackage}/bin/firefox-esr"; + grep = "${pkgs.gnugrep}/bin/grep"; left = config.home-manager.users.${config.custom.username}.home.file.".local/bin/left".source; loupe = "${pkgs.loupe}/bin/loupe"; + modprobe = "${pkgs.kmod}/bin/modprobe"; nautilus = "${pkgs.nautilus}/bin/nautilus"; pkill = "${pkgs.procps}/bin/pkill"; rm = "${pkgs.coreutils}/bin/rm"; sleep = "${pkgs.coreutils}/bin/sleep"; sway-audio-idle-inhibit = "${pkgs.sway-audio-idle-inhibit}/bin/sway-audio-idle-inhibit"; systemctl = "${pkgs.systemd}/bin/systemctl"; + virsh = "${config.virtualisation.libvirtd.package}/bin/virsh"; waybar = "${config.home-manager.users.${config.custom.username}.programs.waybar.package}/bin/waybar"; cfg = config.custom.desktops.hyprland.settings; @@ -66,8 +69,7 @@ in { # https://wiki.hyprland.org/Configuring/Keywords/#executing exec-once = - optionals config.custom.wallpaper ["wallpaper"] - ++ [ + [ sway-audio-idle-inhibit # Inhibit idle while audio is playing "${audio} --init" # Enforce audio profile state "${rm} ~/.cache/walker/clipboard.gob" # Clear clipboard history @@ -77,6 +79,13 @@ in { # HACK: Launch hidden GTK windows to reduce startup time "[workspace special:hidden silent] ${loupe}" "[workspace special:hidden silent] ${nautilus}" +] + ++ optionals config.custom.wallpaper [ + "wallpaper" + ] + # HACK: Delay driver initialization to work around reset issues + ++ optionals config.custom.settings.vm.passthrough.init [ + "${virsh} list | ${grep} ${config.custom.settings.vm.passthrough.guest} || sudo ${modprobe} ${config.custom.settings.vm.passthrough.driver}" ]; # https://wiki.hyprland.org/Configuring/Variables/#xwayland diff --git a/options/custom/settings/vm.nix b/options/custom/settings/vm.nix index 64ebf97..1e3a01c 100644 --- a/options/custom/settings/vm.nix +++ b/options/custom/settings/vm.nix @@ -6,12 +6,24 @@ ... }: with lib; let + virsh = "${config.virtualisation.libvirtd.package}/bin/virsh"; + cfg = config.custom.settings.vm; in { options.custom.settings.vm = { enable = mkOption {default = false;}; libvirt = mkOption {default = true;}; virtualbox = mkOption {default = false;}; + + passthrough = { + enable = mkOption {default = false;}; + driver = mkOption {default = null;}; #?? lspci -k + guest = mkOption {default = null;}; #?? virsh list --all + id = mkOption {default = null;}; #?? lspci -nn + init = mkOption {default = false;}; + intel = mkOption {default = false;}; + node = mkOption {default = null;}; #?? virsh nodedev-list + }; }; config = mkIf cfg.enable { @@ -23,12 +35,37 @@ in { onBoot = "ignore"; onShutdown = "shutdown"; + # https://libvirt.org/hooks.html + hooks.qemu = { + # Attach/detach GPU for passthrough + passthrough = mkIf cfg.passthrough.enable (pkgs.writeShellScript "passthrough" '' + if [[ "$1" == "${cfg.passthrough.guest}" ]]; then + case "$2" in + prepare) + ${virsh} nodedev-detach ${cfg.passthrough.node} + ;; + release) + ${virsh} nodedev-reattach ${cfg.passthrough.node} + ;; + *) + exit + ;; + esac + fi + ''); + }; + qemu = { swtpm.enable = true; # TPM emulation + # BUG: Windows requires global mountpoint for some applications (\\.\*: instead of *:) + # https://github.com/virtio-win/kvm-guest-drivers-windows/issues/950 + # https://virtio-win.github.io/Knowledge-Base/Virtiofs:-Shared-file-system + #// vhostUserPackages = with pkgs; [virtiofsd]; # virtiofs support + # Build OVMF with Windows 11 support - ovmf.packages = [ - (pkgs.OVMF.override { + ovmf.packages = with pkgs; [ + (OVMF.override { secureBoot = true; tpmSupport = true; }) @@ -77,24 +114,42 @@ in { ++ lib.optionals cfg.virtualbox ["vboxusers"]; systemd = mkIf cfg.libvirt { - # Fix resume messages polluting tty - services.libvirt-guests.serviceConfig.StandardOutput = "journal"; + services = { + # Fix resume messages polluting tty + libvirt-guests.serviceConfig = { + StandardOutput = "journal"; + }; + }; + + tmpfiles.settings."10-vm" = { + # HACK: Manually link image to default directory + "/var/lib/libvirt/images/virtio-win.iso" = { + "L+" = { + argument = "${inputs.virtio-win}"; + }; + }; - tmpfiles.rules = let - firmware = pkgs.runCommandLocal "qemu-firmware" {} '' - mkdir $out - cp ${pkgs.qemu}/share/qemu/firmware/*.json $out - substituteInPlace $out/*.json --replace ${pkgs.qemu} /run/current-system/sw - ''; - in [ # HACK: Fix libvirt not automatically locating firmware # https://github.com/NixOS/nixpkgs/issues/115996#issuecomment-2224296279 # https://libvirt.org/formatdomain.html#bios-bootloader - "L+ /var/lib/qemu/firmware - - - - ${firmware}" + "/var/lib/qemu/firmware" = { + "L+" = { + argument = "${pkgs.runCommandLocal "qemu-firmware" {} '' + mkdir $out + cp ${pkgs.qemu}/share/qemu/firmware/*.json $out + substituteInPlace $out/*.json --replace ${pkgs.qemu} /run/current-system/sw + ''}"; + }; + }; + }; + }; - # HACK: Manually link image to default directory - "L+ /var/lib/libvirt/images/virtio-win.iso - - - - ${inputs.virtio-win}" - ]; + boot = mkIf cfg.passthrough.enable { + # https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF#Isolating_the_GPU + blacklistedKernelModules = mkIf cfg.passthrough.init [cfg.passthrough.driver]; + + # https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF#Enabling_IOMMU + kernelParams = mkIf cfg.passthrough.intel ["intel_iommu=on"]; }; }; }