Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Running in QEMU

The flake ships runners so you do not have to remember QEMU invocations. Each is a nix run app.

nix run .#vm

The default. Portable, no KVM required.

qemu-system-x86_64 -M q35 -m 4096 -smp 4 -vga std \
  -cpu IvyBridge,vendor=GenuineIntel \
  -fw_cfg name=opt/ovmf/X-PciMmio64Mb,string=2048 \
  OVMF code and vars as pflash \
  -drive id=root,format=raw,file=<image> \
  qemu-xhci with USB keyboard and mouse \
  intel-hda with hda-duplex \
  -serial mon:stdio -no-reboot -no-shutdown

Notes on the choices: IvyBridge because TCG works on some CPU models and dies on others, and this is a confirmed good one (see Running on real hardware); -vga std because virtio-gpu in Blt-only mode gives no early framebuffer; the extra PCI MMIO window because the default is too small for what the firmware wants to map; and -no-reboot -no-shutdown so a panic leaves the machine sitting there for you to read.

nix run .#kvm

Same system, accelerated, and set up for day-to-day use.

-machine q35,accel=kvm -cpu host -vga std
virtio-net with hostfwd tcp::2222-:22

The disk controller is selectable with PUREDARWIN_VM_DISK: the default is AHCI (ich9-ahci with an ide-hd), or virtio-blk-pci. Being able to switch matters, because the two exercise completely different driver paths.

With the network forward in place you can ssh -p 2222 root@localhost into the guest once sshd is running.

nix run .#arm64-virt

qemu-system-aarch64 -machine virt,gic-version=3 -cpu neoverse-n2 \
  -smp 4 -m 4096 -boot order=c,strict=on \
  AAVMF code and vars as pflash \
  -device virtio-blk-pci,bootindex=1 \
  -device ramfb \
  virtio-net-pci with hostfwd tcp::2223-:22 \
  qemu-xhci keyboard and mouse \
  -display none

neoverse-n2 rather than max is deliberate. -cpu max crashes the EDK2 firmware before it produces any output at all, which looks exactly like a dead serial port and wasted a lot of time once. ramfb is the display that works; the virt machine also needs the xHCI keyboard for input.

nix run .#arm64-uefi and .#arm64-uboot

Two alternative arm64 paths kept for bringup work: a virtio-gpu-pci and GTK display variant, and a U-Boot boot rather than UEFI.

Environment variables

VariableEffect
PUREDARWIN_IMAGEImage to boot. Otherwise the runner looks for ./puredarwin.img then ./result/puredarwin.img
PUREDARWIN_VM_MEMORYGuest RAM in MB
PUREDARWIN_VM_SMPCPU count
PUREDARWIN_VM_VGAVGA device
PUREDARWIN_VM_DISKahci or virtio (kvm runner)
PUREDARWIN_VM_STATE_DIRWhere OVMF variables are kept, default ./.puredarwin-vm
PUREDARWIN_OVMF_CODE, PUREDARWIN_OVMF_VARS, PUREDARWIN_OVMF_VARS_TEMPLATEOverride the firmware

A read-only image (a result symlink into the Nix store) is opened with snapshot=on automatically, so you can boot a store path without copying it first.

Working with a writable image

For anything that needs to persist, copy the image out of the store, or drive a qcow2 overlay on top of it. An overlay is the better default when you are iterating: it keeps the pristine image intact and throwing away the overlay is a clean reset.