2024-09-09 00:22:14 +00:00
|
|
|
{
|
|
|
|
config,
|
|
|
|
inputs,
|
|
|
|
lib,
|
|
|
|
pkgs,
|
|
|
|
...
|
|
|
|
}:
|
2024-09-13 01:50:53 +00:00
|
|
|
with lib; let
|
2024-12-07 01:51:19 +00:00
|
|
|
virsh = "${config.virtualisation.libvirtd.package}/bin/virsh";
|
|
|
|
|
2024-09-09 00:22:14 +00:00
|
|
|
cfg = config.custom.settings.vm;
|
2024-09-13 01:50:53 +00:00
|
|
|
in {
|
2024-09-09 00:22:14 +00:00
|
|
|
options.custom.settings.vm = {
|
2024-09-13 01:50:53 +00:00
|
|
|
enable = mkOption {default = false;};
|
|
|
|
libvirt = mkOption {default = true;};
|
|
|
|
virtualbox = mkOption {default = false;};
|
2024-12-07 01:51:19 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
};
|
2024-09-09 00:22:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
2024-12-23 17:59:31 +00:00
|
|
|
age.secrets = let
|
|
|
|
secret = filename: {
|
|
|
|
file = "${inputs.self}/secrets/${filename}";
|
|
|
|
owner = config.custom.username;
|
|
|
|
group = "users";
|
|
|
|
};
|
|
|
|
in {
|
|
|
|
"desktop/vm/myndows.pass" = secret "desktop/vm/myndows.pass";
|
|
|
|
};
|
|
|
|
|
2024-09-09 00:22:14 +00:00
|
|
|
virtualisation = {
|
|
|
|
# https://wiki.nixos.org/wiki/Libvirt
|
|
|
|
# https://libvirt.org
|
|
|
|
libvirtd = mkIf cfg.libvirt {
|
|
|
|
enable = true;
|
|
|
|
onBoot = "ignore";
|
|
|
|
onShutdown = "shutdown";
|
|
|
|
|
2024-12-07 01:51:19 +00:00
|
|
|
# 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
|
|
|
|
'');
|
|
|
|
};
|
|
|
|
|
2024-09-09 00:22:14 +00:00
|
|
|
qemu = {
|
|
|
|
swtpm.enable = true; # TPM emulation
|
|
|
|
|
2024-12-07 01:51:19 +00:00
|
|
|
# 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
|
|
|
|
|
2024-09-09 00:22:14 +00:00
|
|
|
# Build OVMF with Windows 11 support
|
2024-12-07 01:51:19 +00:00
|
|
|
ovmf.packages = with pkgs; [
|
|
|
|
(OVMF.override {
|
2024-09-09 00:22:14 +00:00
|
|
|
secureBoot = true;
|
|
|
|
tpmSupport = true;
|
2024-09-13 01:50:53 +00:00
|
|
|
})
|
|
|
|
.fd
|
2024-09-09 00:22:14 +00:00
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
# Guest hostname resolution
|
|
|
|
# https://libvirt.org/nss.html
|
|
|
|
#!! Requires DHCP, preferably without lease expiry
|
|
|
|
# https://libvirt.org/formatnetwork.html#addressing
|
|
|
|
#?? sudo virsh net-dhcp-leases NETWORK
|
|
|
|
#?? <range ...>
|
|
|
|
#?? <lease expiry="0"/>
|
|
|
|
#?? </range>
|
|
|
|
nss = {
|
|
|
|
enable = true;
|
|
|
|
enableGuest = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
# Attempt to synchronize time with host on resume
|
|
|
|
# https://libvirt.org/manpages/libvirt-guests.html
|
|
|
|
#!! Windows Time service must be started on Windows guest
|
|
|
|
#?? sudo virsh domtime DOMAIN --sync
|
|
|
|
extraConfig = ''
|
|
|
|
SYNC_TIME=1
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
# https://wiki.nixos.org/wiki/VirtualBox
|
|
|
|
# https://www.virtualbox.org
|
|
|
|
virtualbox.host = mkIf cfg.virtualbox {
|
|
|
|
enable = true;
|
|
|
|
enableExtensionPack = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-09-11 23:18:41 +00:00
|
|
|
# https://github.com/virt-manager/virt-manager
|
|
|
|
programs.virt-manager.enable = cfg.libvirt;
|
|
|
|
|
|
|
|
# https://libvirt.org/uri.html#default-uri-choice
|
|
|
|
environment.sessionVariables.LIBVIRT_DEFAULT_URI = mkIf cfg.libvirt "qemu:///system";
|
|
|
|
|
|
|
|
users.users.${config.custom.username}.extraGroups =
|
|
|
|
lib.optionals cfg.libvirt ["libvirtd"]
|
|
|
|
++ lib.optionals cfg.virtualbox ["vboxusers"];
|
|
|
|
|
2024-09-09 00:22:14 +00:00
|
|
|
systemd = mkIf cfg.libvirt {
|
2024-12-07 01:51:19 +00:00
|
|
|
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}";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-09-13 01:50:53 +00:00
|
|
|
# HACK: Fix libvirt not automatically locating firmware
|
|
|
|
# https://github.com/NixOS/nixpkgs/issues/115996#issuecomment-2224296279
|
|
|
|
# https://libvirt.org/formatdomain.html#bios-bootloader
|
2024-12-07 01:51:19 +00:00
|
|
|
"/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
|
|
|
|
''}";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2024-09-09 00:22:14 +00:00
|
|
|
|
2024-12-07 01:51:19 +00:00
|
|
|
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"];
|
2024-09-09 00:22:14 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|