From b7838f5501cf64351ea9f407091d74a0f8bb05b3 Mon Sep 17 00:00:00 2001 From: Git Sagar Date: Fri, 18 Sep 2026 10:39:49 -0300 Subject: [PATCH] vms/windows: keep RDP VMs awake -- disable sleep in guest, fix the qemu global An idle Windows VM was suspending itself off the network after 15 min: the Balanced power plan sleeps on idle, and the qemu S3/S4 disable was a no-op -- `-global ICH9-LMB.disable_s3` is the wrong device class (q35's bridge is ICH9-LPC), which qemu rejected as "invalid class name", so the sleep states stayed on offer. Fix both ends: correct the global to ICH9-LPC so the firmware stops advertising S3/S4, and in post-oobe (any enableRDP image) switch to the High Performance scheme, zero the standby/hibernate/monitor idle timeouts and turn hibernate off -- a machine exposed as a service must not sleep. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_0117qMyjpuXsjpVAcpJbFD8g --- lib/images/windows/templates/generalize.nix | 10 ++++++++++ nixos/vms/config.nix | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/images/windows/templates/generalize.nix b/lib/images/windows/templates/generalize.nix index 9a54b4c..b9456ea 100644 --- a/lib/images/windows/templates/generalize.nix +++ b/lib/images/windows/templates/generalize.nix @@ -544,6 +544,16 @@ in reg add "HKLM\SYSTEM\CurrentControlSet\Services\SessionEnv" /v Start /t REG_DWORD /d 2 /f reg add "HKLM\SYSTEM\CurrentControlSet\Services\UmRdpService" /v Start /t REG_DWORD /d 2 /f reg add "HKLM\SYSTEM\CurrentControlSet\Services\TermService" /v Start /t REG_DWORD /d 2 /f + :: A VM reached over RDP must never suspend itself off the network. The + :: default Balanced plan sleeps after 15 min idle; switch to High + :: Performance and zero every idle timeout, and turn hibernate off. + powercfg /setactive SCHEME_MIN + powercfg /change standby-timeout-ac 0 + powercfg /change standby-timeout-dc 0 + powercfg /change hibernate-timeout-ac 0 + powercfg /change hibernate-timeout-dc 0 + powercfg /change monitor-timeout-ac 0 + powercfg /hibernate off ''} ${lib.optionalString (staticIP != null || configMedium) '' diff --git a/nixos/vms/config.nix b/nixos/vms/config.nix index 91ab137..fa5c4cd 100644 --- a/nixos/vms/config.nix +++ b/nixos/vms/config.nix @@ -233,11 +233,14 @@ let -machine type=${vmCfg.pc.type}${machineIrqchipArg} \ ${optionalString vmCfg.bios.efi "-bios ${pkgs.OVMF.fd}/FV/OVMF.fd"} \ ${optionalString vmCfg.bios.tpm "-chardev socket,id=chrtpm,path=/tmp/mytpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0"} \ - ${# Windows: localtime RTC, USB tablet for mouse, disable S3/S4 sleep + ${# Windows: localtime RTC, USB tablet for mouse, disable S3/S4 sleep. + # The q35 power/LPC bridge is ICH9-LPC -- ICH9-LMB was a typo qemu + # rejects ("invalid class name"), so the sleep states stayed offered + # and an idle guest could suspend itself right off the network. optionalString isWindows '' -rtc base=localtime,clock=host \ -device qemu-xhci -device usb-tablet \ - -global ICH9-LMB.disable_s3=1 -global ICH9-LMB.disable_s4=1 \ + -global ICH9-LPC.disable_s3=1 -global ICH9-LPC.disable_s4=1 \ ''} \ ${optionalString hasOsDisk "-drive file=${osDiskPath},format=qcow2,if=virtio${optionalString (vmCfg.disks.os.persist == false) ",snapshot=on"}"} \ ${optionalString (vmCfg.disks.iso.file != null) "-drive file=${toString vmCfg.disks.iso.file},media=cdrom,readonly=on"} \