Windows 2000 in QEMU on an M1 Mac

Software

I just made the switch to Apple Silicon for my primary Mac, and I wanted to know what my virtualisation options were. I was delighted to see QEMU runs, including my favourite nostalgic CPU families:

  • i386/pc
  • i386/isapc
  • sparc/sun4m
  • powerpc/mac99

I haven’t run any concrete benchmarks, so take my observations with a grain of salt. But, anecdotally the responsiveness is marginally better than my last Intel MacBook Pro, which is impressive. There even looks to be a nice GUI if you require.

My first test was with Windows 2000. It’s my preferred legacy Windows because it tends to run well in VMs with its ACPI support. It also has a decent interface, supports my vintage desktop software, and does so within a tight resource footprint by modern standards.

Here’s the VM I ran up last week, with my cheesy OEM additions rendered in full 16-bit Cirrus VGA glory:

Screenshot of Windows 2000 showing the System Properties screen with a QEMU Virtual CPU version 2.5+, and Device Manager in the background showing an ACPI Uniprocessor PC and QEMU drive. Also Solitaire.

But not all was smooth sailing. Neither Windows 2000 Professional, nor Windows NT 4.0 Workstation could make it through their installers without triggering a blue screen of death, and the following ominous warning:

KMODE_EXCEPTION_NOT_HANDLED

I vaguely remember seeing this years ago when I was messing with KVM on Debian, but for the life of me I couldn’t remember the mitigation. QEMU still includes a -win2k-hack argument to prevent a premature disk full error, but I haven’t had to use for a while, and it made no difference here.

A bunch of open-ended web searches later, and I found a post by Michael Tokarev on the Debian Bugs mailing list that suggested the following workaround:

The recommended course of things is to reinstall windows NT (or find a way to fix the issue inside it without reinstalling), for which -cpu qemu64,level=1 is a work-around for the bug mentioned. After install, either continue using the level=1 suboption, or apply service pack 6, which will fix the bug in the guest.

I applied this to my boot script, and the installer completed. Huzzah!

#!/bin/sh
qemu-system-i386 \
	-cpu qemu32,level=1 \
	-m 512M \
	-device sb16 \
	-hda drivec.qcow2

I’m not a QEMU or Windows systems developer, so I can only speculate what that specific bug within Windows was. I’m just happy I have a workaround.

Author bio and support

Me!

Ruben Schade is a technical writer and infrastructure architect in Sydney, Australia who refers to himself in the third person. Hi!

The site is powered by Hugo, FreeBSD, and OpenZFS on OrionVM, everyone’s favourite bespoke cloud infrastructure provider.

If you found this post helpful or entertaining, you can shout me a coffee or send a comment. Thanks ☺️.