We're going to run Windows 11 IoT (ARM) on Mac M1 (ARM) using the native binary translation, thanks to up-to-date version of qemu which has native hardware support.
Install qemu and required tools (coreutils - we need truncate/gtruncate, dd/gdd CLI tools, samba - to share files between host and guest VM).
$ brew install qemu coreutils samba
Download A64FRE ISO from archive.org, and rename it to windows.iso
for simplicity.
$ sha256sum 26100.1.240331-1435.ge_release_CLIENT_ENTERPRISES_OEM_A64FRE_en-us.iso
743fdddf1c774cd97ec96b99b12577869cd320d24d7ca97c1c9dc44ad172f9ae 26100.1.240331-1435.ge_release_CLIENT_ENTERPRISES_OEM_A64FRE_en-us.iso
Or, download an evaluation copy from:
https://www.microsoft.com/en-us/evalcenter/evaluate-windows-11-iot-enterprise-ltsc
Prepare UEFI firmware image
$ gtruncate -s 64m efi.img
$ gdd if=/opt/homebrew/opt/qemu/share/qemu/edk2-aarch64-code.fd of=efi.img conv=notrunc
Prepare UEFI variables image
$ gtruncate -s 64m vars.img
$ gdd if=/opt/homebrew/opt/qemu/share/qemu/edk2-arm-vars.fd of=vars.img conv=notrunc
Prepare system disk image (put as much space as you need)
$ qemu-img create -f qcow2 disk.qcow2 40G
Download virtio ISO with required drivers
$ curl -fsSLO https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso
Start VM
$ qemu-system-aarch64 \
-m 4G -smp 4 -cpu host -M virt -accel hvf \
-drive if=pflash,format=raw,file=efi.img,readonly=on \
-drive if=pflash,format=raw,file=vars.img \
-device ramfb \
-device qemu-xhci \
-device usb-kbd \
-device usb-tablet \
-netdev user,id=net,ipv6=off,smb="$HOME" \
-device virtio-net-pci,netdev=net \
-device usb-storage,drive=install \
-drive if=none,id=install,format=raw,media=cdrom,readonly=on,file=windows.iso \
-device usb-storage,drive=virtio-drivers \
-drive if=none,id=virtio-drivers,format=raw,media=cdrom,readonly=on,file=virtio-win.iso \
-device virtio-blk,drive=system \
-drive if=none,id=system,format=qcow2,file=disk.qcow2
Press any key when prompted at boot. Keep sane defaults, skip product key if you don't have one. Select Windows 11 IoT Enterprise LTSC
edition, so that we skip TPM2 check.
If no hard disk drives were identified by the installer, just click Load driver
and side-load an appropriate driver from the mounted ISO drive (e.g., click Browse
, nagivate to CD-ROM named virtio-win
, select viostor\w11\ARM64
folder).
When presented with the network connection dialog, click SHIFT+F10, type oobe\bypassnro.cmd
and hit enter. Wait for reboot to be completed. Next time on the same screen press no internet connection
button.
When presented with the password selection prompt leave it empty to bypass security questions.
Once installation is finished install network controller driver from the same CD-ROM drive (press WIN+R, run devmgmt.msc
, find Ethernet controller
, install driver, nagivate to CD-ROM named virtio-win
and select NetKVM\w11\ARM64
folder).
Install guest-tools from https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win-guest-tools.exe
I was not able to find a valid driver for unknown ACPI\LNRO0005
device. Keep it as is.
This is the point where you may want to stop, because we are done with the installation.
It should work out of the box, we can omit most of the properties and switch to virtio-gpu as follows:
$ qemu-system-aarch64 \
-m 4G -smp 4 -cpu host -M virt -accel hvf \
-drive if=pflash,format=raw,file=efi.img,readonly=on \
-drive if=pflash,format=raw,file=vars.img \
-device virtio-gpu-pci \
-display default \
-device qemu-xhci \
-device usb-kbd \
-device usb-tablet \
-netdev user,id=net,ipv6=off,smb="$HOME" \
-device virtio-net-pci,netdev=net \
-device virtio-blk,drive=system \
-drive if=none,id=system,format=qcow2,file=disk.qcow2
If not, try to boot with -device ramfb
again, and install required drivers from the CD-ROM manually:
> e:
> cd cert
> certutil -addstore Root Virtio_Win_Red_Hat_CA.cer
> certutil -addstore -f TrustedPublisher Virtio_Win_Red_Hat_CA.cer
> cd ..\viogpudo\w11\ARM64
> pnputil /add-driver viogpudo.inf /install
Now try to boot with -device virtio-gpu-pci
again.
Allow guest access to Samba share (it is accessible over \\10.0.2.4\qemu
in Windows VM)
> REG ADD HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters /v AllowInsecureGuestAuth /t REG_DWORD /d 1 /f
Disable security questions for local accounts
> REG ADD HKLM\SOFTWARE\Policies\Microsoft\Windows\System /v NoLocalPasswordResetQuestions /t REG_DWORD /d 1 /f
Classic context menu
> REG ADD HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32 /f /ve
Disable services
> sc stop DiagTrack
> sc config DiagTrack start=disabled
> sc stop Spooler
> sc config Spooler start=disabled
> sc stop WSearch
> sc config WSearch start=disabled
Disable Recall and AI related features
> REG ADD HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsAI /v DisableAIDataAnalysis /t REG_DWORD /d 1 /f
> REG ADD HKCU\SOFTWARE\Policies\Microsoft\Windows\WindowsAI /v DisableAIDataAnalysis /t REG_DWORD /d 1 /f
> REG ADD HKLM\Software\Policies\Microsoft\Windows\WindowsCopilot /v TurnOffWindowsCopilot /t REG_DWORD /d 1 /f
> REG ADD HKCU\Software\Policies\Microsoft\Windows\WindowsCopilot /v TurnOffWindowsCopilot /t REG_DWORD /d 1 /f
If you are looking for the TPM2 software emulation.
$ brew install swtpm
Make sure VM is turned off, then start swtpm as daemon (it will be running in the background)
$ swtpm_setup --create-config-files skip-if-exist
$ swtpm_setup --tpmstate "$(pwd)/tpm" --tpm2 --create-ek-cert --create-platform-cert
$ swtpm socket --tpmstate dir="$(pwd)/tpm" --ctrl type=unixio,path="$(pwd)/tpm/swtpm-sock" --tpm2 --daemon
Add these command-line parameters
$ qemu-system-aarch64 \
-chardev socket,id=chrtpm,path=./tpm/swtpm-sock \
-tpmdev emulator,id=tpm0,chardev=chrtpm \
-device tpm-tis-device,tpmdev=tpm0 \
...
To terminate TPM2 daemon
$ kill -INT $(pidof swtpm)