Patcher9x: adding support for WFW 3.11 with networking enabled under QEMU

Mon Sep 08 2025

For some time I had been wondering why my WFW (Windows for Workgroups) 3.11 test image had been failing to boot in QEMU, preferring instead to switch to a blank screen almost immediately after displaying the splash screen. Whilst searching for some clues as to why this happens, I came across the excellent blog post at https://www.os2museum.com/wp/those-win9x-crashes-on-fast-machines/ which explained that the issue was likely a divide by zero error being caused by modern computers running too quickly for one of its internal timer calibration loops.

Through my passion for retrocomputing I was already aware of patcher9x which consists of a number of patches to allow Windows 9x to run on modern hardware, along with a framework to compile and apply the patches to the original CAB files or to a pre-installed disk image. What interested me at first was that when comparing the output of QEMU’s TCG compiler with the existing patches for Windows 9x, the instructions being executed at the point where the splash screen disappeared and the screen went blank was almost identical indicating that the timing loop was almost certainly the culprit.

It seemed to me that it would be possible to update patcher9x to fix the same issue in WFW 3.11, so my first task was to build the code and confirm that it worked as expected in QEMU. Here I hit the first problem: whilst I could build the code locally and patch the binaries on Linux, there didn’t seem to be a way to regenerate the boot floppy provided as part of each patcher9x release.

My first task was therefore to try and automate this, and I soon realised that I could create a suitable “builder” Docker image containing the relevant compilers, and then use this to generate a fresh floppy image as part of GitHub Actions. There was a boot/README.md file that contained basic information as to how to create the floppy image, but looking at the current images I could see that this was out of date. It was then a case of writing a script to take an empty bootable floppy image (patcher9x uses FreeDOS) and then adding in all the files included in the current release floppy image. I then expanded this further to generate the entire set of release artifacts and sent then sent this PR upstream as Feature: implement GitHub Actions to create patcher9x release artifacts.

Fortunately the PR was merged quickly, and so then it was just a case of finding the time to implement the NDIS.386 patch and integrate it into patcher9x itself. Whilst analysing the existing win9x code I could see that the code and patch generated by speedndis_v1.asm was almost exactly what was needed, so I made a couple of tweaks and I was pleased to find that I could now boot and install tcp32b.exe in WFW 3.11 and both telnet into www.google.com on port 80 and ping hosts by IP address using QEMU’s ne2k_isa network card. The resulting PR was sent upstream as Add support for WFW 3.11 and merged upstream in September 2025.

Huge thanks to Michal Necasek at os2museum.com for the write-up which made this even possible. The great thing about the upstream patch is that it is not exclusive to QEMU, and so I hope it will unlock WFW 3.11 for a new generation of retrocomputing enthusiasts. Perhaps one day I will get around to installing old copies of NCSA Mosaic and Mozilla for the ultimate 16-bit web experience…