Tim Hentenaar's Blog

Oct 18, 2013 20:49

Hacking PC/GEOS 1.x to run on DOS 6.22

Why doesn't PC/GEOS 1.x work on DOS 6 and up? This is a question I've wondered about for a long time. Recently, I've felt compelled to investigate and solve some of those lingering mysteries that I didn't have the time to solve way back when.

Of course, you can get PC/GEOS 1.x to run on MS-DOS 6 by loading setver.exe in config.sys, and forcing the PC/GEOS kernel.exe to run using DOS version 5. But, I wanted to dig into it and understand exactly what the problem is. Thus, I decended to my dark chambers to begin working my tried and true arcane magic upon PC/GEOS.

What is PC/GEOS?

PC/GEOS is a lesser known graphical desktop environment for DOS, decended from the legendary Graphical Environment Operating System for systems like the Commodore 64.

It was also the environment upon which the America Online client for DOS was based.

As I dug into it, I learned more than I ever wanted to know about it. As with all things that I reverse engineer, it inevitably yielded to me it's long-kept secrets.

The Problem

The problem in this case is quite simple. When PC/GEOS starts, it probes for information about all the drives detected by DOS. This part of GEOS is called the "Drive Module." If you were looking at a disassembly of the initialization routine for that module, you'd see the following:

If after looking at that the problem isn't self-evident, then I'll explain.

Before the subroutine, there's a 8-byte long table. This is a jump table used by the subroutine. If you look at the code starting at the probe_drives label, you can see clearly what it does. It takes the DOS major version number (e.g. 6), subtracts 2 (since the first entry is for DOS 2,) and multiplies the result by the size of a single word (2 - since all the addresses here are 1 word long).

It then uses this number (8 in the case of DOS 6) as an index into the aforementioned table, and makes a call to that address. Since there's no entry for DOS 6, it winds up going to cs:0x5756. You might recognize that offset as the bytecode representation of the first two instructions of the subroutine (push si, push di).

Since PC/GEOS works fine on DOS 6 with setver, I can postulate that this is likely the only compatibility problem between the two.

The Solution

For the authors of PC/GEOS, it would have been a simple matter of adding an entry to the jump table and reassembling the exe. Although, I can't help but wonder why they didn't at least add a check to ensure the index used in the call didn't go beyond the table, and handle that case appropriately. Maybe they figured this version would have reached its end of life by the time DOS 6 was released.

In order to fix the problem, I added a new subroutine to be called in place of init_drive_module. It checks the DOS major version, adjusts it if necessary, and then jumps to init_drive_module:

This is easy to do, since init_drive_module is only called in one place. I added the function to the end of the last page in the exe, since there was plenty of room left. However, there's a temporary address pointer at the end of the segment whose address is used to denote the end of the PC/GEOS kernel code.

There are a grand total of 7 references to that temporary pointer, and since the kernel relocates that particular segment before calling the main initialization routine, there's one more place to patch. In total, implementing this fix required patching the kernel in 11 different places.

For the curious, the ret instruction here is not necessary since we're using a jmp, which doesn't push a return address onto the stack, and the routine being jumped into includes a proper ret to return back to the line after the call in init_drive_module. However, I included it for the hell of it, since I needed to have some padding there anyhow. The version of the function that gets patched into the kernel also has a couple of nops to ensure proper alignment of the temporary pointer.

Without further ado, you can download the patch here. The source code is also available as a Gist on GitHub.

It should be run from the PC/GEOS installation directory where KERNEL.EXE resides (usually C:\GEOWORKS). It's important to note, however, that this patch will only cause PC/GEOS to work on DOS implementations that are compatible with DOS 5, and report version numbers above 5. This will not change anything for versions of DOS less than 5, and DR-DOS.