how a from-scratch PC emulator learned to boot Windows 2000

CHAPTER 1 · THE MACHINE

A PC MADE OF RUST

Before Windows 2000 can boot, there has to be a PC. This chapter tours the one mddosem builds — a deliberately 1995-shaped machine recreated in Rust — the real firmware it learned to run in April 2026, the demands an NT kernel makes that DOS never did, the two outside oracles that kept the investigation honest, and the rules of engagement under which fifty-three days of debugging were fought.

27
crates in the Cargo workspace — CPU, memory, VGA, interrupt and timer chips, DOS, Win16, Win32, a long tail of sound hardware
≈31,000
lines in the opcode-switch interpreter — the correctness engine; all 47 endgame captures and both accepted boots ran interpreter-only
22 Apr
--real-boot ships: SeaBIOS + SeaVGABIOS running as real firmware on the emulated board
128 KiB
the trimmed SeaBIOS image — no ACPI tables, so Windows 2000 selects its Standard PC HAL
8086:7010
the PIIX3 IDE function NT's intelide driver interrogates PCI configuration space to find
0 bytes
setuperr.log on the QEMU reference install — the standing controlled experiment

An emulator, in earnest

mddosem is a hardware-accurate PC emulator written from scratch in Rust, begun as an exploration of how far AI-assisted development can take a genuinely hard problem. By the summer of 2026 it was a Cargo workspace of twenty-seven crates: an x86 CPU, a memory subsystem with paging, VGA and SVGA graphics, the 8259 interrupt controllers, the 8254 timer, DMA, serial ports, keyboard, a shelf of emulated sound hardware, and high-level support for DOS, Windows 3.1 and Win32 applications. Its stated philosophy is blunt: emulate real hardware, not specific programs. When software misbehaves, the software is treated as a witness reporting that the emulation is wrong.

At the heart of it sits an opcode-switch interpreter of roughly thirty-one thousand lines — the universal correctness engine, the code path every mode of the x86 runs through. A dynamic recompiler exists too, but it is opt-in, only ever covers 32-bit protected-mode code, and sat this story out: its own Windows 2000 bug (MDD-BUG-KILN-00005) remains open, and every endgame capture and both final accepted boots in this saga ran interpreter-only. When this site says "the emulator did X", it means the interpreter, executing one instruction at a time.

Two ways to be a BIOS

On a real PC the firmware is the first software: code in a ROM chip that the CPU executes from the moment of reset, which tests the machine, builds the interrupt vector table, and only then goes looking for something to boot. An emulator has a choice about how much of that to recreate.

mddosem's default is high-level emulation — HLE. There is no firmware at all: software interrupts such as INT 10h (video), INT 13h (disk), INT 16h (keyboard) and INT 1Ah (clock) vector to tiny stubs in the F000 BIOS segment, the emulator recognises the address, and a Rust handler does the work directly. For DOS this is ideal — fast, debuggable, and indistinguishable from the ROM's answer.

But an NT kernel does not want services; it wants a machine. So through April 2026 the project built --real-boot: SeaBIOS runs as the system firmware and SeaVGABIOS — the very vgabios-stdvga.bin ROM that QEMU ships — is mapped at guest address 0xC0000 and executed, instruction by instruction, on the emulated hardware, POST and all. Around the firmware grew the board it expected to find: a PCI bus with an Intel 440FX host bridge at 0:0.0, a floppy controller, an ATA disk state machine — and, crucially, a PIIX3 IDE controller on the PCI bus, added in the words of its commit "so SeaBIOS sees the HD". The --real-boot flag shipped on 22 April 2026. Five weeks later the first Windows 2000 checkpoint appeared in the journals.

One practical detail mattered from day one: Windows 2000 shipped no setup floppies (NT 3.51 did), but its CD is bootable. So an install starts from a blank raw disk image plus --cdrom and the SP4 ISO — SeaBIOS finds no bootable hard disk and falls through to the ATAPI CD, exactly as a 1999 PC would have done. Remember that arrangement; the harness's failure to keep half of it becomes chapter 5.

One interrupt, two machines
Default (HLE)--real-boot
What answers INT 10ha Rust handler, intercepted at an F000 stubSeaVGABIOS ROM code, executed on the emulated VGA
Who builds the interrupt vector tablethe emulator, at startupthe firmware, during POST
What sits at C000nothingSeaVGABIOS, mapped at 0xC0000
What it can bootDOS, Win16 and Win32 programs via the emulator's own loadersanything with a boot sector — FreeDOS from disk, and eventually NT

What Windows 2000 demands

DOS-era software treats the PC as a bag of parts: ask the BIOS for a sector, poke the VGA, hook a vector. Windows 2000 treats the PC as a contract — and it reads the small print. Four of its demands became, more or less exactly, the chapters of this story:

And one small courtesy DOS never asked for: when NT wants to reboot the machine, it pulses the reset line on the 8042 keyboard controller — the same polite, deliberate reset that chapter 2's restart loop rode round and round.

Eight handovers, sector to desktop

Everything in the chapters ahead happens somewhere along one rail: the chain of handovers that takes a PC from a 512-byte boot sector to a desktop. Each stage exercises different hardware, which is why each era of the campaign stalled at a different stop. Step through it — the captions note what each stage demands of the machine, and where the story broke down.

THE BOOT CHAIN — WHERE EACH ERA STALLED ⏭ step through · keys ← → when focused
1 / 8
Boot order and stall eras from the bug ledger (MDD-BUG-KILN-00004), the 2026 campaign journals, and the 15 July thread census (counts via W2K_DATA). The rail is a recreation — a schematic of Windows 2000's documented boot sequence on a Standard PC HAL machine, not a screenshot.

The oracles

"Compatibility is ground truth" is the project's phrase: when documentation and observed behaviour disagree, the behaviour real machines actually exhibited wins. For a campaign this long, that principle needed instruments — two of them.

The first is a controlled experiment. On 4 June a reference installation of the same SP4 ISO, with the same product key and the same unattended answer file, was run under QEMU with -machine pc,acpi=off — the same Standard PC HAL, the same absent ACPI, the same PIIX3-shaped disk controller. It completes. Its setuperr.log is zero bytes long. From that day on, every alarming line in mddosem's guest logs could be cross-examined: does the successful reference show the same error? Then it is noise, however sinister it reads — an access-denied here, an "LSA Policy Open DB Error=2" there; the reference logs eighteen of those and recovers. Only a genuine divergence between the two installs counts as evidence. Chapter 2 shows this technique demolishing an entire day's worth of plausible theories.

The second oracle is DOSBox-X — the project's standing reference for how PC hardware actually behaves, and an emulator on which Windows 2000 also boots. mddosem's doctrine treats any discrepancy with DOSBox-X as its own bug until proven otherwise, and more than one fix in this story was settled by reading DOSBox-X's source to see what a working machine does. The awkward discovery that the two oracles genuinely disagree with each other about the 8259 interrupt controller — and what mddosem did about it — is chapter 3's story.

Rules of engagement

On 23 June, with setup stuck in a loop nobody yet understood, Arthur issued the goal prompt that governed the rest of the campaign. It is deliberately a goal, not a design — and its two load-bearing sentences are worth quoting exactly:

The point of the rules is what success would mean. An install coaxed past its own checks proves nothing about the emulation; an install that completes because the machine finally behaves proves everything. So the definition of done was pinned in the guest's own terms: the RestartSetup and SystemSetupInProgress registry flags cleared by setup itself, an interactive desktop, FreeCell visibly usable — and the whole run reproduced on a second independent copy of the disk. The rules had teeth, too: in July a transplanted QEMU-made install — a tempting end-run that got further than any native boot yet had — was rejected as doctrine-violating and set aside. Chapter 7 records the finish under exactly these terms: no transplanted install, no bypass, no disabled component.

The cast

This story is told in the plural because the work was. Arthur — the human engineer whose emulator this is — set the goals, made the calls the prompts reserved for him, fixed a blocking disk-image tool the day it mattered, and personally typed the product key (chapter 5). Three AI colleagues did the long-haul engineering: Claude built the kernel-debugger transport and the RAM census of chapter 4; Codex reviewed designs throughout, then drove the endgame branch — all four unlocking fixes and the recorded acceptance; Fable 5 served as consulting diagnostician, brought in for the expensive reasoning passes — it pinned the disk-interrupt bug of chapter 3 — with every claim re-verified against source before it was believed. The work spread across machines, and the repository's branch grammar keeps the provenance: the ledger ID MDD-BUG-KILN-00004 remembers the KILN box that raised the bug, and branch names carry the minting agent's tag (HUM, CDX). Every commit ends with a co-author trailer naming the model that wrote it. All of which is colour rather than the point — but when a story's evidence is its git history, the bylines are part of the record.

Sources for this chapter — the boot-media runbook and real-boot commit trail (April–May 2026), the 23 June goal prompt, the QEMU oracle verdicts of 4–5 June, the bug ledger MDD-BUG-KILN-00004, and the campaign journals; census figures via W2K_DATA. The full evidence table is in chapter 7.