UML Linux on WSL2

Since WSL2 runs an actual Linux kernel that means you can run 32bit binaries! And that now means you can run stuff like ancient unmodified UML kernels on Windows! Isn’t that great!

I followed my old posts here & here, to get running or the short version being:

dpkg --add-architecture i386
apt-get update
apt-get upgrade
apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 slirp

Download a kernel, linux-2.6.24-rc7.bz2 and a root filesystem: Debian-4.0-x86-root_fs.bz2 and get running right away:

./linux-2.6.24-rc7 ubd0=test_fs eth0=slirp mem=512m

And it just worked!

So Apple is finally moving to ARM

Dawning of a new era. Again.

Details don’t seem to be anywhere near as complete as I’d like them for now, but the long speculated move to ARM has finally begun. Interestingly enough, it’s the end of OS X 10.x as now we have version 11, currently named macOS Big Sur:

I guess the more interesting thing will be the emulation in the new Rosetta2, if this is actual emulation or is this going to be relying on LLVM’s intermediary byte-code, allowing a user experience more akin to Java.

With the move to ARM, this will spell the end of the Hackintoshes. Which is a shame, as the best way to experience OS X, most certainly has been on non Apple hardware. I guess time will tell regarding the adoption of the desktops, but as always since the introduction of the Apple Store & Apps, computers have accounted for a negligible fraction of Apple’s sales. Even sales of iPads surpass those of all the computers combined.

The upcoming transition kit will be a Mac mini sporting the A12Z SoC, 16GB of memory and a 512GB SSD. This is the same processor in the current iPad Pro.

The Transition Kit is $500 USD, however it’s invite only. You can try your luck here at:


Naturally I was denied the opportunity to give them $500.

I suppose as time goes on more and more details will become available. I’m sure there will be a race to get Qemu to run Big Sur, although Im sure the retail product will be signed and encrypted, and Apple will consolify their ecosystem.

On the gaming side, however being able to run iOS apps on the desktop means that the Mac is now a serious gaming contender for the casual market. Can apple bridge the Candy Crush gap where Microsoft failed with RT?

Upgrading to WSL2

I finally got the update to version 2004 of Windows 10 (OS Build 19041.329) which now includes support for running a Linux kernel inside a VM, using paravirtual drivers letting it hook into Windows 10. It reminds me of WinOS/2 where, OS/2 would run Windows 3.1 in a virtual machine, but using special drivers it could redirect it on the native filesystem, and paint the windows on the OS/2 desktop.

So the first thing is make sure you have 2004, winver should look like this:

You will need to go to the old control panel, and enable the Virtual Machine Platform. For those of you using VMware, you’ll need at least version 15.5.5 (15.5.6 is current as of the time of me writing this). I’d suggest you do that before turning on this, but some people like to live dangerously. Also fully shut down all your VM’s otherwise things will end up giving you errors (as you’ll see later).

After the Virtual Machine Platform is installed, your machine will need to reboot. After a reboot, you’ll need to download the Linux Update to the system, available at:

It’s a simple install, and only takes a few seconds. I didn’t have to reboot.

now for the fun parts, you’ll need to list and shut down (terminate) your running WSL’s if you have any running.

C:\Users\neozeed>wsl --list --verbose
Debian Running 1

As you can see I only have one, and it’s called Debian, and it is currently running something. Let’s kill it!

C:\Users\neozeed>wsl -t Debian
C:\Users\neozeed>wsl --list --verbose
Debian Stopped 1

And now it’s stopped. The command to upgrade is pretty simple:

C:\Users\neozeed>wsl --set-version Debian 2
Conversion in progress, this may take a few minutes…
For information on key differences with WSL 2 please visit

And yes, you can also stop the WSL instance, and move it back to version 1, if you find 2 not doing what you want. However on first impressions, WSL2 is significantly faster.

If you are running VMware, and you didn’t shut down your VM’s you’ll get this lovely message when you try to resume:

The save state will be deleted, but rest assured it’ll launch okay (at least mine did!)

10.6 the last great OS X

One sad consequence of using the Microsoft Virtual Machine framework is that nesting is no longer available.

which is kind of a bummer, as that was the killer feature.

Sandboxie went GPL3!

I’ve been using Sandboxie for a long while to run all those questionable downloads on Windows. It’s a great light weight sandbox (as the name implies) for running random downloads, or even going to questionable websites as Sandboxie does a great job of isolating processes, and their filesystem access.

It’s not been all that cheap, but I felt it was worth it. I went to check to see how much it is as the conversation had come up on discord, and it turns out that Sophos had bought Sandboxie, and opened up the source code!

The downside is that there will be no further official development of the product. So I guess at some point I’ll have to break down and get a signing cert and re-build it if I want to keep using it.

Last version is locally mirrored here, as I understand it’ll be deleted soon enough.


PowerPC Solaris on the RS/6000

The following is a guest post by PA8600/PA-RISC! Thanks for doing this incredible writeup about an ultra rare Unix!

One of the weirdest times in computing was during the mid-90s, when the major RISC
vendors all had their own plans to dominate the consumer market and eventually wipe out
Intel. This was a time that led to overpriced non-x86 systems that intended to wipe out the
PC, Windows NT being ported to non-x86 platforms, PC style hardware paired with RISC
CPUs, Apple putting the processor line from IBM servers into Macs, and Silicon Graphics
designing a game console for Nintendo. While their attempts worked wonders in the
embedded field for MIPS and the AIM alliance, quite a few of these attempts at breaking into
the mainstream were total flops.

Despite this, there were some weird products released during this period that most only assumed existed in tech magazine ads and reviews. One such product was Solaris for PowerPC. Now Solaris has existed on Intel platforms for ages and the Illumos fork has some interesting ports including a DEC Alpha port, but a forgotten official port exists for the PowerPC CPU architecture. Unlike OS/2, it’s complete and has a networking stack. It’s also perhaps one of the weirdest OSes on the PowerPC platform.

  • It’s a little-endian 32-bit PowerPC Unix and possibly the only one running in 32 bit mode. Windows NT and OS/2 (IIRC) were the other 32-bit PowerPC little-endian OSes and Linux is a 64 bit little endian OS.
  • It’s a limited access release, yet feels as polished as a released product.
  • It has a working networking stack.
  • Unlike AIX, it was designed to run on a variety of hardware with room to expand if more PPC hardware was sold. You can throw in a random 3com ISA NIC for example and it will in fact work with it.
  • It shares several things with Solaris for Intel including the installer.

I’m going to demonstrate perhaps the weirdest complete PowerPC OS on fitting hardware: the IBM RS/6000 7020 40p, also known as the Power Series 440 (6015) and by its codename “Sandalfoot”. The system is a PowerPC 601 based machine, featuring the PCI and ISA buses in an LPX style case. This is also one of the few machines that can run it. All screen captures are from a VGA2USB card as emulators cannot run anything but AIX.

What you need to run Solaris PPC

To run Solaris, the system requirements are just like that of Windows NT for PowerPC. You need a PReP machine (PowerPC Reference Platform, not to be confused with the HIV prevention pill or PrEP according to Wikipedia). Now finding a PReP machine is perhaps the hardest part of setting up Solaris for PowerPC and to understand why you need to know a bit about the history of the PowerPC platform.

One of the biggest problems with PowerPC hardware to this day has been the sheer inconsistency of how each machine boots. While Alpha machines had SRM/ARC and SPARC machines had OpenBoot, each vendor had their own way of booting a PowerPC machine despite rolling out standards.

There were essentially two different camps building PowerPC machines, IBM and Apple. IBM’s plans for universal PowerPC machines consisted of industry standard, low cost machines built around a PowerPC CPU, chipset, and lots of supporting components lifted from the PC platform along with PCI and ISA. The CHRP and PReP standards were essentially PCs with PowerPC processors in them. IBM’s plan was that you were going to replace your PC with a PowerPC machine someday. This was cemented by the fact that Windows NT was ported to the PowerPC platform, that OS/2 had an ill-fated port, and that a handful of third party Windows NT PPC machines were sold.

Apple on the other hand wanted to build Macs with PowerPC CPUs. Older Power Macs featured no PCI slots or Open Firmware, only NuBus slots carried over from classic 68k Macs. In fact much of the boot and OS code was emulated 68k code. Later on Apple would lift bits and pieces of things they enjoyed from the PowerPC standards such as Open Firmware, PCI, and even PS/2 and VGA ports on the clones. Apple’s plan was to replace the PC with the Mac, and Mac clones featured Apple style hardware on LPX motherboards. While the PCI clones featured Open Firmware, this version was designed to load the Macintosh Toolbox from ROM while “futureproofing” them by adding in the ability to boot something like Mac OS X/Rhapsody or BeOS.

Despite these similarities Macs were their own computers and were nothing like the IBM systems internally, aside from sharing the same CPU and maybe Open Firmware later on. But even Macs with Open Firmware were incapable of booting from hard disks formatted for IBM systems and vice versa. This is a common problem with installing PowerPC Linux as many installers do not check which machine they’re run on. Furthermore unlike modern day Intel Macs, PPC Macs were designed to only boot operating systems specifically written for them. They were incapable of running any OS solely written for the IBM machines.

The confusion between PPC machines has also caused a forum question to pop up, “how can I install PowerPC Windows on my Mac?” Even today the new OpenPower/PowerNV machines use a different bootloader than IBM’s hardware and completely lack Open Firmware.

Anyhow IBM built several different generations of PowerPC UNIX machines under several brand names including RS/6000, pSeries, and Power. Nearly all of them (aside from the Linux models) will run AIX, and later ones will run IBM i as well. Not just any PowerPC IBM hardware will run the OSes designed for PReP hardware however.

To run these old PReP OSes you’re looking at a very specific set of machines from the 1994-95 period, many with no characteristic diagnostic display most RS/6000 machines have. To run PowerPC Solaris much of the same applies here. You need a RS/6000 40p, or 7248 43p (not the later 140 and 150 with the display). The rare PPC Thinkpads and Personal Computer Power Series machines will run Solaris as well. It’s also compatible with the PowerStack machines from Motorola and one BetaArchive user had luck running it on a VME board. These machines are hard to find and unemulated as of writing, though the firmware files exist for the 40p at least and some efforts have been made in QEMU.

Mine features a PowerPC 601 CPU, 192mb of RAM (the max), a Weitek P9100 video card (branded as the IBM S15 IIRC), and a non-IBM 3com NIC. The 3com NIC has issues with the system as during boot if the NIC is connected to the network the system will refuse to boot fully and will either freeze or BSOD (in NT). The NIC is also not supported on AIX as well, and will eventually need to be replaced.

Curiously, not only is the IBM 40p/7020/6015 not listed in the HCL but the NIC it uses is. It’s well known that the Sandalfoot systems were used for early PReP OS development and it makes sense. Unlike the RS/6000 model 250, the 40p features PCI and ISA busses along with the same 601 CPU early PowerPC machines had. 


To install PowerPC Solaris, you first need to make a boot floppy. This isn’t uncommon with PReP operating systems. PowerPC Windows NT also requires a boot floppy for the ARC loader. The difference here is that there are two boot floppies; one for Motorola machines and one for IBM machines. Even on PowerPC this wasn’t terribly unusual, both the Moto Powerstack and Apple Network Server computers required custom AIX install media as well and Windows NT had specific HALs for each PPC machine.

On the Motorola PowerStack machines you need the same firmware used to install AIX instead of the ARC firmware for NT. On the IBM machines it’s vastly easier, you just need to make the floppy and shove it in. You then press the power switch and you’ll end up dumped to an Open Firmware prompt. As these IBM machines did not have Open Firmware, the bootloader loads Open Firmware from the floppy or hard disk every time you boot the machine. Keep in mind even the system management services are floppy loaded on these machines.

You then run into the first big hurdle to installing the OS, “disk” and “net” are mapped to very specific devices and if the SCSI IDs of these are different it will not boot. If the CD drive is not at ID 3 and the HDD is not at ID 6 the commands will not work. You will need to set an environment variable and tell it to boot from these disks manually for the first install.

Booting the OS is similar to booting it on a Sun, but the installer resembles that of the Intel version. The first thing that happens is you wait for the slow 2 speed CD drive to load the OS as the screen turns Open Firmware white. You will need to set the terminal type, and then then video and mouse input before X will load. The video options are limited to the S3 864/928, the Weitek P9000 and P9100, and Moto’s Cirrus Logic GD5434. Notice how the Power Series 440 (6015)/RS6k 7020 40p is referred to by its codename “Sandalfoot”.

Once you enter this in Solaris will boot load X it does on a Sun or Intel box, and the installer will be exactly the same. This phase is very uneventful as the slow CD drive copies files to the hard disk. I didn’t take a lot of screenshots of this part because you can get the same experience with QEMU or an old SPARCStation. You set the network info, you partition the HDD, you choose what you want, and you sit back as it installs.

Then you’ll be dropped at the Open Firmware bootloader and you’ll enter the right commands to make it boot if “boot disk” doesn’t automatically boot the OS.

The installation is not complete however. The next step is to swap CDs and install the GUI. A default install will drop you at a command line, with the second disk you can install OpenWindows and CDE and get a full working desktop. Login, switch CDs, change to the correct directory, and run the installer.

Once this is done, simply type in reboot and once you login you’ll be at a desktop that looks exactly like a Solaris 2.5.1 install on any other platform with one difference. There is literally zero third party software, and for years there was literally zero way of making software for it. You’re stuck with a stock OS and whatever utilities Solaris 2.5.1 came with. You’ll want to use OpenWindows as well, CDE is vastly slower on the 601 CPU (but not as slow as AIX 4.3 for example). The platform directory also tells you what IBM machines it can run on, and all the RS/6000s are titled PPS. The 6015 is the 40p, the 6040 and 6042 are the ThinkPad models 830 and 850, the 6050/70 are the Personal Computer Power Series variants of the 7248 43p, and the PowerStacks are pretty self-explanatory.

The Compiler Problem (and solutions)

For the longest time Solaris for PowerPC was neglected among those who happened to own a PReP machine for one reason: it lacked a compiler. A compiler is perhaps the most important part of any operating system as it allows one to write code for it. As was the case with UNIX operating systems from the time, the compiler was sold separately. With any UNIX that was widely distributed this wasn’t too much of an issue, as GCC or other third party compilers existed for the platform. Furthermore most compilers for these commercial UNIX operating systems ended up dumped online.

Solaris for PowerPC lacked both of these for ages due to the obscurity and rarity of the port. But in 2018 Tenox dug up the official compiler, yet this remained unnoticed for a while. This led to someone else experimenting with cross compilation on Solaris, and managing to compile PowerPC Solaris software. They then released a port of GCC for Solaris 2.5.1 for PowerPC while posting instructions on how to compile it.

To use GCC for Solaris, you need to unzip the compiler, add it to the path, and then symlink a few files that GCC ends up looking for. This is discussed in the BetaArchive thread about this, but I’ll quote it here.

$ ls -l /opt/ppc-gcc/lib/gcc-lib/powerpcle-sun-solaris2/2.95/
total 13224
-rwxr-xr-x   1 bin      bin      5157747 Feb 16 10:30 cc1
-rwxr-xr-x   1 bin      bin       404074 Feb 16 10:30 collect2
-rwxr-xr-x   1 bin      bin       453525 Feb 16 10:30 cpp
-rw-r--r--   1 bin      bin         1932 Feb 16 10:30 ecrti.o
-rw-r--r--   1 bin      bin         1749 Feb 16 10:30 ecrtn.o
drwxr-xr-x   3 bin      bin         1024 Feb 16 10:29 include
-rw-r--r--   1 bin      bin       673012 Feb 16 10:30 libgcc.a
drwxr-xr-x   2 bin      bin          512 Feb 16 10:30 nof
-rw-r--r--   1 bin      bin         4212 Feb 16 10:30 scrt0.o
-rw-r--r--   1 bin      bin         1360 Feb 16 10:30 scrti.o
-rw-r--r--   1 bin      bin         1104 Feb 16 10:30 scrtn.o
-rw-r--r--   1 bin      bin         7868 Feb 16 10:30 specs
lrwxrwxrwx   1 root     other         24 Feb 22 21:35 values-Xa.o -> /usr/ccs/lib/values-Xa.o
lrwxrwxrwx   1 root     other         24 Feb 22 21:36 values-Xc.o -> /usr/ccs/lib/values-Xc.o
lrwxrwxrwx   1 root     other         24 Feb 22 21:36 values-Xs.o -> /usr/ccs/lib/values-Xs.o
lrwxrwxrwx   1 root     other         24 Feb 22 21:36 values-Xt.o -> /usr/ccs/lib/values-Xt.o
lrwxrwxrwx   1 root     other         26 Feb 22 21:37 values-xpg4.o -> /usr/ccs/lib/values-xpg4.o

Once you do this, you can now compile C code at least with GCC. This means that Solaris for the PowerPC platform now is a usable operating system, aside from the fact it has no precompiled software whatsoever. Even Windows NT for PowerPC has more software for it. Software can now be compiled using GCC or the original compiler, and cross compiled with GCC on a non-PPC box. Using the cross compiler lets you compile more basics for compiling PPC Solaris code as well such as make. In this screenshot you can also see me compiling a basic “endian test” code example to demonstrate the little endianness of the PowerPC port.

The only problem is that there’s going to be little interest until someone makes a PReP machine emulator. PReP hardware is very hard to come by on the used market these days and while in the early 2000s it might have been easy to find something like a specific RS6k, but judging by the eBay listings there were a lot more MCA, CHRP, and even later PReP models (like the 43p-140) than there are early PReP machines in circulation. QEMU can emulate the 40p somewhat, but right now its 40p emulation is less like an actual 40p and more like something to please AIX. It definitely has the novelty of being a “little-endian PowerPC Unix” however.

Examining Windows 1.0 HELLO.C

The following is a guest post by NCommander of SoylentNews fame!

For those who’ve been long-time readers of SoylentNews, it’s not exactly a secret that I have a personal interest in retro computing and documenting the history and evolution of the Personal Computer. About three years ago, I ran a series of articles about restoring Xenix 2.2.3c, and I’m far overdue on writing a new one. For those who do programming work of any sort, you’ll also be familiar with “Hello World”, the first program most, if not all, programmers write in their careers.

A sample hello world program might look like the following:

#include <stdio.h>

int main() {
 printf("Hello world\n");
 return 0;

Recently, I was inspired to investigate the original HELLO.C for Windows 1.0, a 125 line behemoth that was talked about in hush tones. To that end, I recorded a video on YouTube that provides a look into the world of programming for Windows 1.0, and then testing the backward compatibility of Windows through to Windows 10.

For those less inclined to watch a video, my write-up of the experience is past the fold and an annotated version of the file is available on GitHub (

Bring Out Your Dinosaurs – DOS 3.3

Before we even get into the topic of HELLO.C though, there’s a fair bit to be said about these ancient versions of Windows. Windows 1.0, like all pre-95 versions, required DOS to be pre-installed. One quirk however with this specific version of Windows is that it blows up when run on anything later than DOS 3.3. Part of this is due to an internal version check which can be worked around with SETVER. However, even if this version check is bypassed, there are supposedly known issues with running COMMAND.COM. To reduce the number of potential headaches, I decided to simply install PC-DOS 3.3, and give Windows what it wants.

You might notice I didn’t say Microsoft DOS 3.3. The reason is that DOS didn’t exist as a standalone product at the time. Instead, system builders would license the DOS OEM Adaptation Kit and create their own DOS such as Compaq DOS 3.3. Given that PC-DOS was built for IBM’s own line of PCs, it’s generally considered the most “generic” version of the pre-DOS 5.0 versions, and this version was chosen for our base. However, due to its age, it has some quirks that would disappear with the later and more common DOS versions.

PC DOS 3.3 loaded just fine in VirtualBox and — with the single 720 KiB floppy being bootable — immediately dropped me to a command prompt. Likewise, FDISK and FORMAT were available to partition the hard drive for installation. Each individual partition is limited, however, to 32 MiB. Even at the time, this was somewhat constrained and Compaq DOS was the first (to the best of my knowledge) to remove this limitation. Running FORMAT C: /S created a bootable drive, but something oft-forgotten was that IBM actually provided an installation utility known as SELECT.

SELECT’s obscurity primarily lies in its non-obvious name or usage, nor the fact that it’s actually needed to install DOS; it’s sufficient to simply copy the files to the hard disk. However, SELECT does create CONFIG.SYS and AUTOEXEC.BAT so it’s handy to use. Compared to the later DOS setup, SELECT requires a relatively arcane invocation with the target installation folder, keyboard layout, and country-code entered as arguments and simply errors out if these are incorrect. Once the correct runes are typed, SELECT formats the target drive, copies DOS, and finishes installation.

Without much fanfare, the first hurdle was crossed, and we’re off to installing Windows.

Windows 1.0 Installation/Mouse Woes

With DOS installed, it was on to Windows. Compared to the minimalist SELECT command, Windows 1.0 comes with a dedicated installer and a simple text-based interface. This bit of polish was likely due to the fact that most users would be expected to install Windows themselves instead of having it pre-installed.

Another interesting quirk was that Windows could be installed to a second floppy disk due to the rarity of hard drives of the era, something that we would see later with Microsoft C 4.0. Installation went (mostly) smoothly, although it took me two tries to get a working install due to a typo. Typing WIN brought me to the rather spartan interface of Windows 1.0.

Although functional, what was missing was mouse support. Due to its age, Windows predates the mouse as a standard piece of equipment and predates the PS/2 mouse protocol; only serial and bus mice were supported out of the box. There are two ways to solve this problem:

The first, which is what I used, involves copying MOUSE.DRV from Windows 2.0 to the Windows 1.0 installation media, and then reinstalling, selecting the “Microsoft Mouse” option from the menu. Re-installation is required because WIN.COM is statically linked as part of installation with only the necessary drivers included; there is no option to change settings afterward. The SDK documentation details the static linking process, and how to run Windows in “slow mode” for driver development, but the end result is the same. If you want to reconfigure, you need to re-install.

The second option, which I was unaware of until after producing my video is to use the PS/2 release of Windows 1.0. Like DOS of the era, Windows was licensed to OEMs who could adapt it to their individual hardware. IBM did in fact do so for their then-new PS/2 line of computers, adding in PS/2 mouse support at the time. Despite being for the PS/2 line, this version of Windows is known to run on AT-compatible machines.

Regardless, the second hurdle had been passed, and I had a working mouse. This made exploring Windows 1.0 much easier.

The Windows 1.0 Experience

If you’re interested in trying Windows 1.0, I’d recommend heading over to and using their browser-based emulator to play with it as it already has working mouse support and doesn’t require acquiring 35 year old software. Likewise, there are numerous write-ups about this version, but I’d be remiss if I didn’t spend at least a little time talking about it, at least from a technical level.

Compared to even the slightly later Windows 2.0, Windows 1.0 is much closer to DOSSHELL than any other version of Windows, and is essentially a graphical bolt-on to DOS although through deep magic, it is capable of cooperative multitasking. This was done entirely with software trickery as Windows pre-dates the 80286, and ran on the original 8086. COMMAND.COM could be run as a text-based application, however, most DOS applications would launch a full-screen session and take control of the UI.

This is likely why Windows 1.0 has issues on later versions of DOS as it’s likely taking control of internal structures within DOS to perform borderline magic on a processor that had no concept of memory protection.

Another oddity is that this version of Windows doesn’t actually have “windows” per say. Instead applications are tiled, with only dialogue boxes appearing as free-floating Windows. Overlapping Windows would appear in 2.0, but it’s clear from the API that they were at least planned for at some point. Most notable, the CreateWindow() function call has arguments for x and y coordinates.

My best guess is Microsoft wished to avoid the wrath of Apple who had gone on a legal warpath of any company that too-closely copied the UI of the then-new Apple Macintosh. Compared to later versions, there are also almost no included applications. The most notable applications that were included are: NOTEPAD, PAINT, WRITE, and CARDFILE.

While NOTEPAD is essentially unchanged from its modern version, Write could be best considered a stripped-down version of Word, and would remain a mainstay until Windows 95 where it was replaced with Wordpad. CARDFILE likewise was a digital Rolodex. CARDFILE remained part of the default install until Windows 3.1, and remained on the CD-ROM for 95, 98, and ME before disappearing entirely.

PAINT, on the other hand, is entirely different from the Paintbrush application that would become a mainstay. Specifically, it’s limited to monochrome graphics, and files are saved in MSP format. Part of this is due to limitations of the Windows API of the era: for drawing bitmaps to the screen, Windows provided Display Independent Bitmaps or DIBs. These had no concept of a palette and were limited to the 8 colors that Windows uses as part of the EGA palette. Color support appears to have been a late addition to Windows, and seemingly wasn’t fully realized until Windows 3.0.

Paintbrush (and the later and confusingly-named Paint) was actually a third party application created by ZSoft which had DOS and Windows 1.0 versions. ZSoft Paintbrush was very similar to what shipped in Windows 3.0 and used a bit of technical trickery to take advantage of the full EGA palette.

With that quick look completed, let’s go back to actually getting to HELLO.C, and that involved getting the SDK installed.

The Windows SDK and Microsoft C 4.0

Getting the Windows SDK setup is something of an experience. Most of Microsoft’s documentation for this era has been lost, but the OS/2 Museum has scanned copies of some of the reference binders, and the second disk in the SDK has both a README file and an installation batch file that managed to have most of the necessary information needed.

Unlike later SDK versions, it was the responsibility of the programmer to provide a compiler. Officially, Microsoft supported the following tools:

  • Microsoft Macro Assembler (MASM) 4
  • Microsoft C 4.0 (not to be confused with MSC++4, or Visual C++)
  • Microsoft Pascal 3.3

Unofficially (and unconfirmed), there were versions of Borland C that could also be used, although this was untested, and appeared to not have been documented beyond some notes on USENET. More interestingly, all the above tools were compilers for DOS, and didn’t have any specific support for Windows. Instead, a replacement linker was shipped in the SDK that could create Windows 1.0 “NE” New Executables, an executable format that would also be used on early OS/2 before being replaced by Portable (PE) and Linear Executables (LX) respectively.

For the purposes of compiling HELLO.C, Microsoft C 4.0 was installed. Like Windows, MSC could be run from floppy disk, albeit it with a lot of disk swapping. No installer is provided, instead, the surviving PDFs have several pages of COPY commands combined with edits to AUTOEXEC.BAT and CONFIG.SYS for hard drive installation. It was also at this point I installed SLED, a full screen editor as DOS 3.3 only shipped with EDLIN. EDIT wouldn’t appear until DOS 5.0

After much disk feeding and some troubleshooting, I managed to compile a quick and dirty Hello World program for DOS. One other interesting quirk of MSC 4.0 was it did not include a standalone assembler; MASM was a separate retail product at the time. With the compiler sorted, it was time for the SDK.

Fortunately, an installation script is provided. Like SELECT, it required listing out a bunch of folders, but otherwise was simple enough to use. For reasons that probably only made sense in 1985, both the script and the README file was on Disk 2, and not Disk 1. This was confirmed not to be a labeling error as the script immediately asks for Disk 1 to be inserted.

The install script copies files from four of the seven disks before returning to a command line. Disk 5 contains the debug build of Windows, which are roughly equivalent to checked builds of modern Windows. Disk 6 and 7 have sample code, including HELLO.C.

With the final hurdle passed, it wasn’t too hard to get to compiled HELLO.EXE.

Dissecting HELLO.C

I’m going to go through these at a high level, my annotated hello.c goes into much more detail on all these points.

General Notes

Now that we can build it, it’s time to take a look at what actually makes up the nuts and bolts of a 16-bit Windows application. The first major difference, simply due to age is that HELLO.C uses K&R C simply on the basis of pre-dating the ANSI C function. It’s also clear that certain conventions weren’t commonplace yet: for example, windows.h lacks inclusion guards.

NEAR and FAR pointers

long FAR PASCAL HelloWndProc(HWND, unsigned, WORD, LONG);

Oh boy, the bane of anyone coding in real mode, near and far pointers are a “feature” that many would simply like to forget. The difference is seemingly simple, a near pointer is nearly identical to a standard pointer in C, except it refers to memory within a known segment, and a far pointer is a pointer that includes the segment selector. Clear right?

Yeah, I didn’t think so. To actually understand what these are, we need to segue into the 8086’s 20-bit memory map. Internally, the 8086 was a 16-bit processor, and thus could directly address 2^16 bits of memory at a time, or 64 kilobytes in total. Various tricks were done to break the 16-bit memory barrier such as bank switching, or in the case of the 8086, segmentation.

Instead of making all 20-bits directly accessible, memory pointers are divided into a selector which forms the base of a given pointer, and an offset from that base, allowing the full address space to be mapped. In effect, the 8086 gave four independent windows into system memory through the use of the Code Segment (CS), Data Segment (DS), Stack Segment (SS), and the Extra Segment (ES).

Near pointers thus are used in cases where data or a function call is in the same segment and only contain the offset; they’re functionally identical to normal C pointers within a given segment. Far pointers include both segment and offset, and the 8086 had special opcodes for using these. Of note is the far call, which automatically pushed and popped the code segment for jumping between locations in memory. This will be relevant later.

HelloWndProc is a forward declaration for the Hello Window callback, a standard feature of Windows programming. Callback functions always had to be declared FAR as Windows would need to load the correct segment when jumping into application code from the task manager. Hence the far declaration. Windows 1.0 and 2.0, in addition, had other rules we’ll look at below.

WinMain Decleration:

int PASCAL WinMain( hInstance, hPrevInstance, lpszCmdLine, cmdShow )
HANDLE hInstance, hPrevInstance;
LPSTR lpszCmdLine;
int cmdShow;

PASCAL Calling Convention

Windows API functions are all declared as PASCAL calling convention, also known as STDCALL on modern Windows. Under normal circumstances, the C programming language has a nominal calling convention (known as CDECL) which primarily relates to how the stack is cleaned up after a function call. In CDECL-declared functions, its the responsibility of the calling function to clean the stack. This is necessary for vardiac functions (aka, functions that take a variable number of arguments) to work as the callee won’t know how many were pushed onto the stack.

The downside to CDECL is that it requires additional prologue and epilogue instructions for each and every function call, thereby slowing down execution speed and increasing disk space requirements. Conversely, PASCAL calling convention left cleanup to be performed by the called function and usually only needed a single opcode to clean the stack at function end. It was likely due to execution and disk space concerns that Windows standardized on this convention (and in fact still uses it on 32-bit Windows.


if (!hPrevInstance) {
/* Call initialization procedure if this is the first instance */
if (!HelloInit( hInstance ))
return FALSE;
} else {
/* Copy data from previous instance */
GetInstanceData( hPrevInstance, (PSTR)szAppName, 10 );
GetInstanceData( hPrevInstance, (PSTR)szAbout, 10 );
GetInstanceData( hPrevInstance, (PSTR)szMessage, 15 );
GetInstanceData( hPrevInstance, (PSTR)&MessageLength, sizeof(int) );

hPrevInstance has been a vestigial organ in modern Windows for decades. It’s set to NULL on program start, and has no purpose in Win32. Of course, that doesn’t mean it was always meaningless. Applications on 16-bit Windows existed in a general soup of shared address space. Furthermore, Windows didn’t immediately reclaim memory that was marked unused. Applications thus could have pieces of themselves remain resident beyond the lifespan of the application.

hPrevInstance was a pointer to these previous instances. If an application still happened to have its resources registered to the Windows Resource Manager, it could reclaim them instead of having to load them fresh from disk. hPrevInstance was set to NULL if no previous instance was loaded, thereby instructing the application to reload everything it needs. Resources are registered with a global key so trying to register the same resource twice would lead to an initialization failure.

I’ve also gotten the impression that resources could be shared across applications although I haven’t explicitly confirmed this.

Local/Global Memory Allocations

NOTE: Mostly cribbled off Raymond Chen’s blog, a great read for why Windows works the way it does.

pHelloClass = (PWNDCLASS)LocalAlloc( LPTR, sizeof(WNDCLASS) );
LocalFree( (HANDLE)pHelloClass );

Another concept that’s essentially gone is that memory allocations were classified as either local to an application or global. Due to the segmented architecture, applications have multiple heaps: a local heap that is initialized with the program and exists in the local data segment, and a global heap which requires a far pointer to make access to and from.

Every executable and DLL got their own local heaps, but global heaps could be shared across process boundaries, and as best I can tell, weren’t automatically deallocated when a process ended. HEAPWALK could be used to see who allocated what and find leaks in the address space. It could also be combined with SHAKER which rearranged blocks of memories in an attempt to shake loose bugs. This is similar to more modern-day tools like valgrind on Linux, or Microsoft’s Application Testing tools.


lpprocAbout = MakeProcInstance( (FARPROC)About, hInstance );

Oh boy, this is a real stinker and an entirely unnecessary one at that. MakeProcInstance didn’t even make it to Windows 3.1 and its entire existence is because Microsoft forgot details of their own operating environment. To explain, we’re going to need to dig a bit deeper into segmented mode programming.

MakeProcInstance’s purpose was to register a function suitable as a callback. Only functions that have been marked with MPI or declared as an EXPORT in the module file can be safely called across process boundaries. The reason for this is that Windows needs to register the Code Segment and Data Segment to a global store to make function calls safely. Remember, each application had its own local heap which lived in its own selector in DS.

In real mode, doing a CALL FAR to jump to a far pointer automatically push and popped the code segment as needed, but the data segment was left unchanged. As such, a mechanism was required to store the additional information needed to find the local heap. So far, this is sounding relatively reasonable.

The problem is that 16-bit Windows has this as an invariant: DS = SS …

If you’re a real mode programmer, that might make it clear where I’m going with this. The Stack Segment selector is used to denote where in memory the stack is living. SS also got pushed to the stack during a function call across process boundaries along with the previous SP. You might begin to see why MakeProcInstance becomes entirely unnecessary.

Instead of needing a global registration system for function calls, an application could just look at the stack base pointer (bp) and retrieve the previous SS from there. Since SS = DS, the previous data segment was in fact saved and no registration is required, just a change to how Windows handles function epilogs and prologs. This was actually found by a third party, and a tool FixDS was released by Michael Geary that rewrote function code to do what I just described. Microsoft eventually incorporated his fix directly into Windows, and MakeProcInstance disappeared as a necessity.

Other Oddities

From Raymond Chen’s blog and other sources, one interesting aspect of 16-bit Windows was it was actually designed with the possibility that applications would have their own address space, and there was talk that Windows would be ported to run on top of XENIX, Microsoft’s UNIX-based operating system. It’s unclear if OS/2’s Presentation Manager shared code with 16-bit Windows although several design aspects and API names were closely linked together.

From the design of 16-bit Windows and playing with it, what’s clear is this was actually future-proofing for Protected Mode on the 80286, sometimes known as segmented protection mode. On 286’s Protected Mode, while the processor was 32-bit, the memory address space was still segmented into 64-kilobyte windows. The primary difference was that the segment selectors became logical instead of physical addresses.

Had the 80286 actually succeeded, 32-bit Windows would have been essentially identical to 16-bit Windows due to how this processor worked. In truth, separate address spaces would have to wait for the 80386 and Windows NT to see the light of day, and this potential ability was never used. The 80386 both removed the 64-kilobyte limit and introduced a flat address space through paging which brought the x86 processor more inline with other architectures.

Backwards Compatibility on Windows 3.1

While Microsoft’s backward compatibility is a thing of legend, in truth, it didn’t actually start existing until Windows 3.1 and later. Since Windows 1.0 and 2.0 applications ran in real mode, they could directly manipulate the hardware and perform operations that would crash under Protected Mode.

Microsoft originally released Windows 286, and 386 to add support for the 80286 and 80386, functionality that would be merged together in Windows 3.0 as Standard Mode, and 386 Enhanced Mode along with legacy “Real Mode” support. Due to running parts of the operating system in Protected Mode, many of the tricks applications could perform would cause a General Protection Fault and simply fail. This wasn’t seen as a problem as early versions of Windows were not popular, and Microsoft actually dropped support for 1.x and 2.x applications in Windows 95.

Windows for Workgroups was installed in a fresh virtual machine, and HELLO.EXE, plus two more example applications, CARDFILE and FONTTEST were copied with it. Upon loading, Windows did not disappoint throwing up a compatibility warning right at the get-go.

Accepting the warning showing that all three applications ran fine, albeit it with a broken resolution due to 0,0 being passed into CreateWindow().

However, there’s a bit more to explore here. The Windows 3.1 SDK included a utility known as MARK. MARK was used, as the name suggests, to mark legacy applications as being OK to run under Protected Mode. It also could enable the use of TrueType fonts, a feature introduced back in Windows 3.0.

The effect is clear, HELLO.EXE now renders in TrueType fonts. The reason TrueType fonts are not immediately enabled can be see in FONTTEST, where the system typeface now overruns several dialog fields.

The question now was, can we go further?

35 Years Later …

As previously noted, Windows 95 dropped support for 1.x and 2.x binaries. The same however was not true for Windows NT, which modern versions of Windows are based upon. However, running 16-bit applications is complicated by the fact that NTVDM is not available on 64-bit installations. As such, a fresh copy of Windows 10 32-bit was installed.

Some pain was suffered convincing Windows that I didn’t want to use a Microsoft account to sign in. Inserting the same floppy disk as used in the previous test, I double-clicked HELLO and Feature Installer popped up asking to install NTVDM. After letting NTVDM install, a second attempt shows, yes, it is possible to run Windows 1.x applications on Windows 10.

FONTTEST also worked without issue, although the TrueType fonts from Windows 3.1 had disappeared. CARDFILE loaded but immediately died with an initialization error. I did try debugging the issue and found WinDbg at least has partial support for working with these ancient binaries, although the story of why CARDFILE dies will have to wait for another day.

In Closing …

I do hope you enjoyed this look at ancient Windows and HELLO.C. I’m happy to answer questions, and the next topic I’m likely going to cover is a more in-depth look at the differences between Windows 3.1 and Windows for Workgroups combined with demonstrating how networking worked in those versions.

Any feedback on either the article, or the video is welcome to help me improve my content in the future.

Until next time,

73 de NCommander

Making MacOS Mojave more like MacOS

I was looking for some generic music and I thought I’d just download some MIDI files, and go with that. I mean come on, it’s 2020, even Windows 10 can play MIDI’s and even Microsoft has finally put in some sampled sound banks back in the what Vista days? Maybe XP??

Anyway, Apple has had sound banked MIDI for ages, going back to MacOS 7.something with a really revamped and great one in MacOS 8. Anyways I download Cuba Baion, and it doesn’t know what to do with it. I drag it to QuickTime 10, and it doesn’t know either.

So I fire up a Snow Leopard VM, and it too has QuickTime 10, and although it cannot play it, it offers to open up QuickTime 7 for me, and it plays. So I do the natrual thing, and zip of QuckTime 7, and copy it to Mojave, and lo it runs!

Back in the day, I bought QuickTime so I search my emails, and yep April of 2006 there is the receipt with the code!

I put in my pro key from back in 2006 and it happily registered.


Now, another thing from Snow Leopard that isn’t around anymore is X11. Can it be that easy?

I copy the app over, along with /usr/X11 and yes, that’s all it takes, and now I have X11 running on Mojave!

Too bad Catalina users, you can’t do any of this.

Free386 (386|DOS-Extender – RUN386 compatible)

I just found this late last night. The world can always use another DOS Extender, and here we go, out of Japan with Free386!

  • Version: 0.61
  • Date: 2016/12/28
  • Author: [email protected]
  • Machine: PC/AT(DOS/V)
  • Machine in Japanese: FM-TOWNS, PC-9801/PC-9821
  • Compatible: MS-DOS and XMS and VCPI (with HIMEM.SYS and EMM386.EXE)
  • Language: NASM (Full assembly language)
  • Licence: PDS ( and Free386’s source files)

You can find it here:

Poorly machine translated readme as follows:

From the futon, I thought i’d publish the “Free386” of dos-extender that I had made before to GitHub.

If you want to publish it anyway, NASM and alink also included together and if there is a DOS environment, i thought that anyone can assemble it is out of luck. I found a bug in alink when generating flat mode.exe/.com file. It’s around here that i started to go crazy in a lot of ways(laughs)

Patching alink was done on Linux. I then used TOWNS-gcc to generate alink.exp, but i used the MP header format that TOWNS-gcc generates. We found a bug that the EXP file cannot run on its own. If this is not corrected, it is not possible to distribute including the development environment because it does not usually have the EXP execution environment. When I checked, there was a bug in how to allocate memory, and when the memory capacity started to exceed 8MB, i was allocating memory space that does not exist in the back.

In fact, Free386 at the time was a lot of files that didn’t work properly, and i was worried because it became unstable, it was a mistake in the allocation of memory that is not. However, to examine this, i created a tool to dump memory maps and paging (i.e., it’s included), it was quite a bit of a hassle.

Now, when the memory allocation bug is fixed, almost all DOS generic EXP files and many TOWNS software now work. However, towns-OS’s biggest mystery system is the CoCo/NSD driver around the moss, and the software written in F-BASIC386 does not start. When you come this far, you want to move it.

So we start editing the CoCo/NSD driver. After a little research, I immediately found out the following.

  • CoCo.EXE resides in DOS memory (real memory).
  • NSDD resides in extended memory.

This means that CoCo is presumed to load nsd files into extended memory and manage that information. Now the question is how to get that management information. Is there information in coco memory that resides like SYSINIT? I thought.

For now, to check the area, Free386, i attached the ability to dump the register status before and after the int service was executed by hooking up the interrupt. We analyzed \hcopy\deldrv.exp, which has the ability to remove the specified NSD driver, as “we need to find the NSD driver and the structure seems simpler” in the mechanism.

Int = 0000_008E  CS:EIP = 000C:0000_1ADC   SS:ESP = 0014:0001_0B88
 DS = 0014        ES = 0060        FS = 0014        GS = 0014
EAX = 0000_C003  EBX = 0000_0001  ECX = 0000_0000  EDX = 0000_66EC
ESI = 0000_0246  EDI = 2074_6E00  EBP = 0001_0C48  FLG = 0000_0046
CR0 = 8000_0021  CR2 = 0000_0000  CR3 = 0002_9000    D0 S1 P1 C0  
 DS = 0014        ES = 0014        FS = 0014        GS = 0014
EAX = 0000_0003  EBX = 0000_0010  ECX = 0000_0000  EDX = 0001_0C18
ESI = 0000_0246  EDI = 2074_6E00  EBP = 0001_0C48  FLG = 0000_0006
CR0 = 8000_0021  CR2 = 0000_0000  CR3 = 0002_9000    D0 S0 P1 C0  

Information like this comes out a lot in turn. If you look at the changes in coco’s residency and other changes in behavior, you can see that int 8eh/AX=Cx0x is a CoCo service. At the same time, log int 8eh and make a file (included) run386. I also looked at the behavior of the EXE and explored the commonalities of both of them, and i thought, “How would I design the mechanism if I were you?” We looked up coco services from the perspective of “**.

Then we traced to a service that provides driver resident information called int 8eh/AX=C103h. Using this information, the NSD driver in extended memory could be correctly pasted into memory and implemented on the selector. To verify, I ran deldrv.exp using Free386 and was able to uninstall the NSD driver correctly.

Great. End.

…… I wish I had solved it in that way.

TOWNS-OS is an OS of a mysterious structure, and even though there is a BIOS (TBIOS) of 32bit Native mode for graphicprocessing, some services such as timers use the BIOS of FM-R compatible 16-bit operation as it is. It has an incomprehensible structure to use it from the 32bit program side while managing resources, such as a 16-bit timer BIOS.

In terrible cases, each time the processing and interrupt of real-mode resources such as timers and keyboards, switch the CPU to real mode, if during those real-mode BIOS processing, interrupt the PROCESSING of the BIOS, such as FM sound source or VSYNC occurs, it seems to return to protected mode once.

NSD driver called forRBIOS (for Real BIOS) is the intermediary for this incomprehensible structure. Just as DOS-Extender acts as an intermediary for 32-bit programs and MS-DOS, it acts as a real-mode BIOS and a 32bit program intermediary.

In a RUN386 environment, when forRBIOS.NSD is built in, interrupt vectors such as int 8eh are rewritten so that the NSD driver gets the interrupt. **Where is this information? ** That was a mystery that was left behind. However, RUN386 is a . No matter how much the INT log is done until you run EXP, it doesn’t look like it. If you look at the memory of the coco that is resident, there is no information that seems to be it.

If you’re not going to initialize the resident NSD itself. I thought, i patched the entry of the resident forRBIOS, and when the service routine was called, i tried to use the rough business of falling into an infinite loop was bingo.

Finally, you can now run exp files generated by F-BASIC386 and so on. The analysis results are recorded in the doc. By the way, when you run a program that does not require forRBIOS (written in High-C, etc.), the whole process is slower than when you initialize forRBIOS. I really think this is the specs of TOWNS-OS (laughs)

This is the first time in more than a decade since the development was suspended in 2001, and the DOS-Extender, which is compatible with RUN386, was made.

Qemu 5 was recently released

It’s been jumping numbers like crazy, and I’m still holding onto 0.9 because I’m weird. Anyways there is something amazing hiding in all those release notes and stuff:


The m68k emulation is good enough to run Linux! Granted the target machine is the Macintosh 800, although the Mac ROM doesn’t boot enough to do anything Apple enough, using a serial console however does get us into the system. On my ancient Mac Pro I get emulation in the speed range of a 1Ghz G4!

[email protected]:~# cat /proc/cpuinfo 
CPU: 68040
MMU: 68040
FPU: 68040
Clocking: 1304.9MHz
BogoMips: 869.99
Calibration: 4349952 loops

Absolutely amazing!

Installation is a bit tricky as there is no true bootrom / boot process, so I had to load the installer with a dummy ‘raw’ disk, and tar the kernel & initrd to that raw disk so I could later extract it on the native OS to boot into the disk. I followed mostly the instructions here.

And what is that? NeXT CUBE emulation?

The peripherals are nowhere near complete enough to boot, HOWEVER it does boot the PROM, complete with keyboard support.

qemu-system-m68k -M next-cube -bios Rev_2.5_v66.BIN

It’s fun enough to play with. And thanks to Qemu’s fast emulation, perhaps this is a speedy way to run stuff in the future?

Now isn’t that cool?