Notes on running Windows ARM in Proxmox

With a little help from this gist and this Reddit post, I was able to get Windows 10 (and Windows 11, almost) booting in , my Raspberry Pi 4 running .

Neither is stable or of much use (the Pi is quite slow), but it was something that had been on my bucket list for a while.

This was what it looked like most of the time, when it worked.

I took a bit longer to get around to try this out than I bargained for because I hadn’t actually set up LVM in pimox yet, and also because I had to work around the machine type architecture bug noted in the gist.

I also had to try a number of ISOs, from Windows 10 LTSC with slipstreamed virtio drivers to Tiny 11, because the “normal” ARM ISOs I had wouldn’t boot, and I assumed that Tiny 11, at least, would have been tested under QEMU.

The Hard Way: Creating the VM in Proxmox

You can start setting things up via the GUI (it’s just easier to have it set up all the volumes), but you will need to tweak the config manually so that the end result looks like this (with the OS and virtio driver CDs included):

# cat /etc/pve/qemu-server/302.conf 
agent: 1
balloon: 512
bios: ovmf
boot: dcn
cores: 2
efidisk0: local-lvm:vm-302-disk-0,efitype=4m,pre-enrolled-keys=1,size=64M
scsi1: backup:iso/tiny11a64_r1.iso,media=cdrom,size=4375488K
scsi2: backup:iso/virtio-win-0.1.240.iso,media=cdrom,size=612812K
memory: 2048
name: tiny11-arm
net0: virtio=BC:24:11:79:2A:FF,bridge=vmbr0,firewall=1
numa: 0
ostype: linux
scsi0: local-lvm:vm-302-disk-1,cache=writeback,iothread=1,size=64G
scsihw: virtio-scsi-pci
smbios1: uuid=b1c36c87-d9bf-4504-a5c5-be4316796b68
sockets: 1
tpmstate0: local-lvm:vm-302-disk-2,size=4M,version=v2.0
arch: aarch64

Step Two: First Boot

There is probably a slightly easier way to do this, but I needed to start the VM manually and access it via VNC to get the virtio drivers installed:

# cat firstboot.sh 
/usr/bin/qemu-system-aarch64 \
-id 302 \
-name tiny11-arm \
-smbios type=1,uuid=ffffffff-ffff-ffff-ffff-ffffffffffff \
-drive if=pflash,unit=0,format=raw,readonly=on,file=/usr/share/pve-edk2-firmware//AAVMF_CODE.fd \
-drive if=pflash,unit=1,format=raw,id=drive-efidisk0,file=/dev/pve/vm-302-disk-1 \
-tpmstate0 file=/dev/pve/vm-302-disk-2 \
-smp 2 \
-m 2048 \
-boot menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg \
-nodefaults \
-nographic \
-device qemu-xhci \
-device usb-kbd \
-device usb-tablet \
-device ramfb \
-device virtio-scsi-pci,id=scsihw0,bus=pcie.0,addr=0x5 \
-drive file=/dev/pve/vm-302-disk-0,id=drive-scsi0,format=raw,cache.direct=on,aio=native,detect-zeroes=on,if=none \
-device scsi-hd,bus=scsihw0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0,id=scsi0,bootindex=200 \
\
-drive file=/mnt/pve/backup/template/iso/win10_LTSC_2021_arm64_virtio.iso,if=none,id=windows,media=cdrom \
-device usb-storage,drive=windows,bootindex=100 \
\
-drive file=/mnt/pve/backup/template/iso/virtio-win-0.1.240.iso,if=none,id=drive-virtio,media=cdrom \
-device usb-storage,drive=drive-virtio \
\
-netdev type=tap,id=net0,ifname=tap302i0,script=/var/lib/qemu-server/pve-bridge,downscript=/var/lib/qemu-server/pve-bridgedown \
-device virtio-net-pci,mac=de:ad:be:ef:42:00,netdev=net0,bus=pcie.0,addr=0x12,id=net0 \
-M virt,virtualization=on -cpu max \
-vnc :0

Note that the machine type had to be tweaked to run on the (whether because of the KVM version or chipset support), and that you have a few seconds to connect to the host via VNC so that you can hit a key to boot from CD.

Then you’ll need to be very patient and let the installation process play out. In my case, it took almost 30m to get to the initial input selection screen, and much longer than that to finish (the mouse is pretty responsive throughout, so you can use that to check things haven’t stalled).

With Windows 10, I eventually got stuck on OOBE errors, which I fixed by hitting Shift+F10 and typing in these commands:

net user Administrator /active:yes
net user /add your_user_name your_password
net localgroup administrators user_name /add
cd %windir%\system32\oobe
msoobe.exe

…powering off, and then restarting the VM and letting it boot from the hard disk (you should later do net user Administrator /active:no to disable the Administrator account) and install the virtio drivers.

That sort of worked, but the VM would eventually crash, (which I suspect is due to the Pi’s CPU instruction set).

With Windows 11, I had a much harder time altogether–I only reached the OOBE stage twice, and even then the VM would not come up again after rebooting.

Clever, But Failed Tricks

I also tried using UTM to create a qcow2 file (it installed Windows in less than 5 minutes) and importing that across:

qm importdisk 302 /mnt/pve/backup/template/qcow/3812E0DC-9E92-4CB9-AA07-91060E03B1E7.qcow2 local-lvm

…but that failed since the hardware virtualization is just different (the boot drive in UTM is configured as an NVME), and I couldn’t find a good way to import tpmdata (just dumping that into the LVM store didn’t work).

I will eventually get back to this once I map out the way maps its config entries into KVM options (and I get a beefier ARM64 host).

Until then, Happy New Year!

This page is referenced in: