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. 

Installation

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 (https://github.com/NCommander/win1-hello-world-annotations)


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 PCjs.org 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.

hPrevInstance

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.

MakeProcInstance

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

Web Rendering Proxy – Full Page Scrolling

(This is a guest post by Antoni Sawicki aka Tenox)

Due to a popular demand I have added an option of generating full page height screenshot and allowing client browser to do the scrolling.

This makes the browsing experience much smoother, you have resources for it. Beware, a full page screenshot can be several MB in size encoded as gif/png and much more as a decoded raw bitmap on the client. I managed to crash Mosaic and OmniWeb a few times. Fortunately typical Wikipedia page is under 1 MB so for most part is should be fine. To activate just put 0 in page Height.

I have drafted a pre-release on github for testing. Please let me know any feedback. I’m also thinking whether enable this by default, or not.

Multia under Thermal Camera

(This is a guest post by Antoni Sawicki aka Tenox)

DEC Multias are known for notoriously overheating. Someone even coined a term “Multia Heat Death”. The typical folklore recommendation of the time was to only run it vertically, replace the built-in fan with a more powerful, etc.

In modern times one can inexpensively acquire a thermal camera that attaches to a mobile phone. So why not take a peak inside the inferno.

This is how Multia looks like in a thermal camera. PS is on top. CPU on the left. FDD/HDD bottom left.

The CPU, Alpha AXP, runs at around 60C, not great, not terrible.

Scanning up close through individual chips I found this curiosity:

Wedged between the memory chips and the power supply is a little chip that generates almost 100C. That’s a boiling temperature of water. Note the thermal image is shifted in regards to the visual part due to close range.

What does this chip do? I have no clue. Perhaps someone can help here. What I however did to it is this:

Slapped on this really nice radiator. In fact I added little radiators you can buy for Raspberry PI to all the chips generating tons of heat.

This is how the motherboard looks like right now:

I also added a tiny fan on top of the CPU. Drilled some holes in the case and of course replaced the main fan with a highest air flow I could find.

Time will tell if this resolves the heat death, but my Multia now runs much cooler with help of all the radiators and extra fans.

Reviving 20 year old web forum software

(This is a guest post by xorhash.)

What makes you nostalgic? I don’t know about you, but for me, it’s definitely early 2000s web forums. Names like vBulletin, UltimateBB, phpBB, YaBB, IkonBoard, … bring a smile to my face. Thus, I figured it would be time to revisit the oldest vBulletin I could get my hands on. As it turns out, vBulletin used to offer “vBulletin Lite” back in the year 2000, which is a version of vBulletin 1.x stripped down so much, it almost stops being vBulletin.

Because they hid it behind a form, the web archive didn’t quite catch it, but I managed to find a different copy online, which seems pristine enough at least: vbulletinlite101.zip

So that’s just a bunch of code. I could just get a period-appropriate Red Hat 9 installation going, but that’d be boring. How much work could it possibly be to get this to run? In hindsight: just about six hours. Please allow me to say that the code is of rather questionable quality. Do not expose this to the Internet. Without even trying, I found at least two SQL injections. Every SQL injection immediately leads to code execution under PHP as well since the templates are interpreted using eval(). And so I set out on my quest to port this to a modern OS.

SoftwareOriginal RequirementMy Version
Operating System“different flavours of UNIX, as well as Windows NT/98”Ubuntu 19.04
InterpreterPHP 3.0.9PHP 7.2.19
DatabaseMySQL 3.22MariaDB 10.3.13

The details of this are rather boring, so allow me to point out some highlights and discoveries made while digging through the code:

  • 50 reply limit: Threads were limited to 50 replies. There was no pagination. Any replies beyond that would just replace the most recent post. I’m not sure if this was an attempt at preventing server and client load from excessively large pages or an attempt to “encourage” people to actually buy vBulletin.
  • No accounts: Unlike vBulletin 1.x, there were no accounts. All posts would just have a username field and an optional field for an e-mail address; even if provided, the e-mail address does not get verified.
  • No thread/post management: There’s no way to conveniently delete threads or posts, leaving the forums completely defenseless against spam. I suspect this was by design, so that nobody would stick with vBulletin Lite.
  • Icon plagiarism: The icons for the “search” and “home” buttons are actually taken from Internet Explorer 4. For comparison, here are the buttons in Internet Explorer:
Internet Explorer 4 search button Internet Explorer 4 home button
  • Questionable security: vBulletin Lite was not a pinnacle of secure and defensive coding. Though some efforts were made (e. g. using addslashes(), which is nowadays considered inappropriate, but was all that what was available at the time in PHP 3), they were not thorough and overlooked spots. When encountering a database error, the actual SQL query and error details would be shown in an HTML comment on the error page, greatly helping attackers build their SQL injection even without source code available. The admin control panel password is stored in plaintext: on the server as well as in the cookie that persists an admin session. I’m also not sold on using eval() for interpreting templates from the database.
  • Filenames ending in .php3: Back then, it was common for PHP scripts to have a filename ending in .php3, though I couldn’t find the exact reason why this used to be common practice (possibly to allow PHP/FI 2.0 and PHP 3.0 to co-exist, maybe?). Nowadays, everything’s normally just a .php file.
  • register_globals was very much a thing: The PHP (anti-)feature register_globals caused request parameters and cookies to be turned into global variables in the script, e. g. https://www.php.example/test.php?x=1 would set $x to 1. vBulletin Lite relied on register_globals existing and working. PHP removed it in version 5.4, so a lot of request handling needed to be changed for vBulletin Lite to work at all.
  • MySQL has implicit defaults: Apparently, if strict mode is not enabled, MySQL has implicit defaults for various data types. vBulletin Lite relied on this behavior, much to my surprise. I’m not sure who thought this was a good feature, but it sure surprised me.
  • Password caching until exactly 2020: When successfully logging into the admin control panel, a cookie “controlpassword” is set. It is hardcoded to expire at the beginning of 2020—next year. I’m glad I didn’t have to try and debug that subtle issue. My patch makes it so that the cookie expires at the start of the next year.
  • A typo in the admin control panel: In admin/forum.php, deletion of a forum should bring the list of forums again. However, due to a typo (“modfiy” instead of “modify”), the page instead stays blank. I also took the liberty to fix this obvious bug.
  • Feature remnants: vBulletin Lite kind of looks like a rushjob; I’d love to find out if that’s true. There are leftovers of various features, which manifest themselves in stray variables being referenced but never set. For example, the e-mail field in the template for the newthread.php page actually references $password, which nothing else ever reads or sets. Similarly, forumdisplay.php references a $datecut variable, which I assume regular vBulletin 1.x would use to prune old threads by date (to save space on the database?).
  • Ampersands in HTML: vBulletin had literal ampersands (&) in the templates, namely in links. Firefox complains about this nowadays and expects &amp; even in <a href>, but I didn’t want to touch that because I’m afraid I might break an old browser by changing this behavior.

As mentioned above, I made a patch for vBulletin Lite 1.0.1 to make it work with modern versions of PHP and MySQL: vbulletinlite101-2019.diff
Applying it requires some preparation (renaming the files from .php3 to .php and adjusting the names of included files ahead of time); after that, it should apply cleanly:

$ for i in *.php3; do mv $i $(basename $i .php3).php; done
$ cd admin && for i in *.php3; do mv $i $(basename $i .php3).php; done
$ cd .. && find . -name "*.php" -exec sed -i 's/php3/php/g' {} \;
$ patch -p1 < PATH_TO_PATCH.diff

vBulletin Lite had a mechanism that would send e-mail a configurable address about SQL errors. I ended up disabling that in db_mysql.php, spilling the error onto the page and kept that behavior in the patch to make debugging easier (since this has no business running in production anymore anyway). See the areas marked with TODO if you want to undo that after all.

I used the new ?? syntax introduced in PHP 7, so this patch may not immediately work with PHP 5, though the worst grunt work has already been taken care of.

And for those who want to give it a kick, I put one up on vbulletin.virtuallyfun.com.


The website that used to host vBulletin Lite notes that “vBulletin Lite may be modified for your own use only. Under no circumstances may any modified vBulletin Lite code be distributed”.

I hope that separating this into a pristine archive and a patch—with no functional changes—is good enough. Should this still not be enough for the rightsholders (currently MH Sub I, LLC dba vBulletin), takedown requests will of course be honored.

WRP 4.0 Preview

(This is a guest post from Antoni Sawicki aka Tenox)

Welcome a completely new and absolutely insane mode of Web Rendering Proxy. ISMAP on steroids!

While v3.0 was largely just a port from Python/Webkit to GoLang/Chromedp, the new version is a whole new game. Previously WRP worked by walking the DOM and making a clickable imagemap out of <A HREF> nodes. Version 4.0 works by using x,y coordinates obtained from ISMAP to perform a simulated mouse click in Chrome browser. This way you can click on any element of the page. From annoying cookie warnings, to various drop down menus and even play some online games. Also pagination has been replaced with a clickable scroll bar.

Enough talking, you can watch this video:

Or download the new version and try it yourself!

Please report bugs on github.com. Thank you!

WRP 3.0 Beta ready for testing

(This is a guest post from Antoni Sawicki aka Tenox)

I have released WRP 3.0 for testing. It’s currently a browser-in-browser server rather than a true proxy, but that’s in the works. Please try it out and let me know. Usage instructions are on the main github project page.

Today using trickery I was able to login to my reddit account from Mosaic:

Update: just added the missing image quantizer so that the color number input box actually does something useful. Now you can browse porn even with 16 colors:

WRP Runs on Windows

(This is a guest post by Antoni Sawicki aka Tenox)

Thats right, the new beta version of Web Rendering Proxy runs natively on Windows. Single EXE, no libraries or dependencies required. Only Chrome Browser.

I took a Internet Explorer 1.5 for a spin today while WRP was running on my Windows 10 PC. Worked just fine.

I have added Prev/Next buttons so that you can easily “scroll” through long pages.

ISMAP support has been added, proof:

You can download a preview build on github.