目标与现状
把旧 Windows 10 LTSC 系统盘(Hyper-V 动态 VHDX)在 NixOS 上以 KVM/libvirt 虚拟机运行,按需进入;原始系统盘文件全程不动。
| 项 | 值 |
|---|---|
| 域 | max2-win10ltsc(libvirt qemu:///system) |
| 磁盘 | /s500data/kvm/vms/max2-win10ltsc.qcow2(源 VHDX 的转换副本) |
| 固件 / 机型 | UEFI(OVMF,libvirt firmware='efi')+ q35 |
| 设备 | 磁盘 AHCI(SATA)、网卡 e1000e、SPICE 控制台(只听 127.0.0.1) |
| 资源 | 8 GiB 内存 / 4 vCPU;clock offset='localtime'(Windows 用本地时间) |
| 自启动 | 关闭(按需进入,不随宿主开机启动) |
前置事实(实测)
| 项 | 实测值 |
|---|---|
| 源盘 | /s500data/kvm/max2_win10ltsc_system.VHDX,动态盘,虚拟 2 TB / 实占 198.56 GB |
| 分区表 | GPT:p1 = EFI 系统分区(vfat);p2 = NTFS(Windows 卷) |
| ESP 引导 | \EFI\Boot\bootx64.efi 存在 ⇒ UEFI 可引导 |
| 加密 | 无 BitLocker |
| 休眠态 | 无 hiberfil.sys(干净关机) |
| 宿主能力 | 内核 ntfs3 / loop / nbd / kvm_amd 齐备,/dev/kvm 就绪 |
实现过程
虚拟化栈(声明式落地)
模块:/etc/nixos/modules/system/service/libvirt.nix;在 configuration.nix 的 imports 清单里放开一行即启用(该仓库惯例:一行一模块、打开功能 = 取消注释)。
virtualisation.libvirtd.enable = true—— VM 管理守护进程,并创建默认 NAT 网络(virbr0)qemu.swtpm.enable = true—— 预置 TPM(Win10 用不到,日后跑 Win11 直接可用)qemu.vhostUserPackages = [ pkgs.virtiofsd ]—— 宿主目录共享给 guest 所需boot.kernelModules = [ "kvm-amd" ]—— AMD-V(本机 svm)networking.firewall.trustedInterfaces = [ "virbr0" ]—— 信任 NAT 网桥,出网不被挡- 系统包:virt-manager、virt-viewer、spice-gtk、qemu、qemu-utils、virt-v2v、virtio-win、cdrkit、libguestfs
生效:
sudo nixos-rebuild switch
注意:NixOS 26.05 已移除 virtualisation.libvirtd.qemu.ovmf 子模块(写进配置会在求值期断言失败);OVMF 固件现随 qemu 默认提供。
磁盘准备(转成自包含副本,源盘不动)
qemu-img convert -p -f vhdx -O qcow2 \
/s500data/kvm/max2_win10ltsc_system.VHDX \
/s500data/kvm/vms/max2-win10ltsc.qcow2
产物:virtual size 1.86 TiB、disk size 177 GiB、corrupt: false;源 VHDX 的 size 与 mtime 转前转后一致(确未改动)。
域定义与启动
域 XML:/s500data/kvm/vms/win10-virtual.xml(项目仓库内另存一份留档)。关键形态:
<os firmware='efi'>
<type arch='x86_64' machine='q35'>hvm</type>
</os>
<clock offset='localtime'/>
<disk type='file' device='disk'>…<target dev='sda' bus='sata'/></disk>
<interface type='network'><source network='default'/><model type='e1000e'/></interface>
sudo virsh -c qemu:///system define /s500data/kvm/vms/win10-virtual.xml
sudo virsh -c qemu:///system start max2-win10ltsc
磁盘池:vms → /s500data/kvm/vms。
网络(libvirt 默认 NAT)
NixOS 只把 libvirt 自带的 default.xml 拷到 /var/lib/libvirt/qemu/networks/,还需设一次自动启动:
sudo virsh -c qemu:///system net-autostart default
sudo virsh -c qemu:///system net-start default
之后 virbr0 = 192.168.122.1/24,guest 经 DHCP 取址(实测 guest 拿到 192.168.122.x,可 ping 通)。
管理命令
| 用途 | 命令 |
|---|---|
| 列出域(含未启动) | virsh -c qemu:///system list --all |
| 开机 / 优雅关机 / 断电 | virsh -c qemu:///system start|shutdown|destroy max2-win10ltsc |
| 域信息(含 Autostart) | virsh -c qemu:///system dominfo max2-win10ltsc |
| 图形控制台 | virt-manager(连接 qemu:///system)或 virt-viewer -c qemu:///system max2-win10ltsc |
| 截屏(不必进桌面) | virsh -c qemu:///system screenshot max2-win10ltsc /tmp/shot.png |
| guest 拿到的 IP | virsh -c qemu:///system net-dhcp-leases default |
| 存储池 | virsh -c qemu:///system pool-list --all |
| 改域定义 | virsh -c qemu:///system edit max2-win10ltsc |
| 磁盘 I/O 统计 | virsh -c qemu:///system domblkstat max2-win10ltsc sda |
关键点:非 root 的 virsh 默认连 qemu:///session,系统域必须显式 -c qemu:///system,否则 list / net-list 全是空。
踩坑记录
- 网络看起来没起来:libvirt 的 default 网络不是定义好的就有,需
net-autostart default(它才会建 autostart 符号链接),否则每次 libvirtd 起也不带它。 - 26.05 的 ovmf 子模块已删:
virtualisation.libvirtd.qemu.ovmf写进配置会在求值期断言失败。 - 同名域 define 被拒:报
already exists with uuid …—— 名字相同但 XML 里没写或写了不同<uuid>时,libvirt 判定为另一个域;改定义必须带原 uuid,或先virsh undefine --keep-nvram再重定义。 - boot 元素冲突:
<os><boot dev='hd'/>与设备上的<boot order='1'/>不能同时用(报per-device boot elements cannot be used together with os/boot elements),二选一。 - virt-v2v 转换失败(本 guest 特有):在 Inspecting the source 阶段报
hivex: _hivex_get_values: EFAULT, value is not a valid block→inspect_os raised Hivex.Error。成因是 guest 的 SYSTEM hive 在MountedDevices处有 hivex 读不了的块(内容问题,不是配置问题,命令行无开关可绕)。⇒ 改用qemu-img直接转 qcow2 + 手工域定义(AHCI/e1000e 都是 Win10 自带驱动,不需要注入)。 - 整盘 raw 直接按 ntfs3 挂载会失败:报
Primary boot signature is not NTFS—— NTFS 卷在分区里,要加offset=(本档案 1048576 = LBA 2048×512)。 - ACPI 关机不响应:guest 停在锁屏时
virsh shutdown可能长时间不退出,必要时用destroy(硬断电);频繁硬断电会在 guest 侧留下未清理的关机状态。
备注
对硬件有检测要求的 win 软件,可以通过修改虚拟化硬件来调通即可。