WORK IN PROGRESS - PREVIEW ONLY

The AARD Code and DR DOS

In this long article, I, being as far as I know the first outside Microsoft to have learnt how the AARD code works, explain that I condemn its form but broadly sympathise with its function.

For roughly a year after I noticed on 17th April 1992 that the HIMEM.SYS driver from a Microsoft Windows 3.1 beta contained what eventually became known as the AARD Code, I had no idea which non-standard DOS had been affected. Whichever DOS it was, since the code was in WIN.COM too, its users will have been warned of an obscurely numbered “Non-fatal error” and been asked to “contact Windows 3.1 beta support” just from having tried to start this Windows on this DOS. Surely this had already happened to someone somewhere in the months before I had got this pre-release HIMEM.SYS to study.

But I could, at the time, only suppose. I was not a Windows 3.1 beta tester nor a user of any operating system other than MS-DOS. My reading of computer magazines never was more than occasional, even back then. Though I was actively participating in an online conferencing system in Britain, it would be nearly two years before I subscribed to Compuserve. Even more then than now, I was not at all plugged in to computer news. If real-world observation of the “Non-fatal error” had been reported publicly, I didn’t know of it and I wouldn’t have expected to. I had seen the error message for myself, of course, but only on my own computer—by installing my own device driver that made MS-DOS 5.00 fail the AARD code’s encrypted test.

Not until 30th May 1993 did I learn that the error message had hit DR DOS specifically. This was from Andrew Schulman, who had himself learnt only weeks before: see FTC MOVES TO FOCUS MICROSOFT ANTITRUST CASE by Wendy Goldman Rohm from the Chicago Tribune on 10th May 1993. There then came quickly Andrew’s article Examining the Windows AARD Detection Code in Dr. Dobb’s Journal, September 1993, and repeated discussion in Undocumented DOS, Second Edition, ISBN 0-201-63287-X, co-authored by Andrew for Addison-Wesley in 1994.

By the late 1990s, the AARD code had no small role in a court case, Caldera, Inc. v. Microsoft Corp., 72 F. Supp.2d.1295 (D. Utah 1999), which Caldera, who was by then the owner of DR DOS after Digital Research and Novell, brought against Microsoft “for damages and injunctive relief under the antitrust laws of the United States, and for damages in tort”. The AARD code has ever since been for many some sort of pin-up for anti-competitive practices by Microsoft.

Sympathy

I, for the record, have tended to side with Microsoft on this: not on the general question of anti-competitive practices, for which Microsoft deserves far greater condemnation than the computer industry and various governments have allowed it to escape with, but on the AARD code specifically; and not then for the disingenuous error message and the code’s obfuscation, which I always thought childish and quickly also regarded as despicable, but for Microsoft’s general disposition to DR DOS.

To clear all doubt about my attitude to the AARD code and DR DOS: had the AARD tests been coded without disguise, with failure warning frankly that Microsoft Windows is written for execution on MS-DOS, even if adding that other execution is at the user’s own risk and voids support from Microsoft, then I would not agree that Microsoft had wronged anyone.

To Microsoft, by my reckoning, DR DOS was an imitator of MS-DOS. In assessing Microsoft’s reaction to DR DOS, I must think what would be own reaction if I had designed and implemented something, and someone copied my design into a distinct implementation of their own. I would have to accept that copyright law gives me no protection and I might console myself with the proverb about imitation being flattery, but I would think it outrageously unjust if some law would somehow have me owe anything to the imitator.

This broad sympathy is, of course, strained by many complications, both in Microsoft’s overall disposition to DR DOS and in how Microsoft expressed this specifically through the AARD code.

Markets

Most important among the complications—and so obvious that it barely needs mention—is that no amount of regarding DR DOS as an imitator denies that DR DOS was legitimately a competitor of MS-DOS in a market of operating systems for micro-computers whose processors derive from the Intel 8086, which more or less quickly specialised to computers whose peripheral support derives from that of the IBM Personal Computer (PC).1 In this market, Microsoft enjoyed monopoly power through MS-DOS and Microsoft properly had responsibilities for fair competition, including with DR DOS.

But this market in PC-compatible operating systems is not the only—or even the main—operating-system market that DR DOS was in. DR DOS had copied the MS-DOS interfaces as if to compete with MS-DOS in a market of operating systems that are compatible with software that’s written to run on MS-DOS. This is the “DOS market” that features in Caldera’s court filings when talking of the AARD code as unlawfully anti-competitive.

To Microsoft this “DOS market” never was a market. There was just MS-DOS itself and a handful of mostly very slight adaptations by one or another Original Equipment Manufacturer (OEM) to whom Microsoft licensed the source code.2 Later came a few specialised variants that Microsoft created (itself or jointly) for its newer operating systems—notably OS/2 and, years later, Windows NT—so they could offer some sort of compatibility box with limited support for MS-DOS applications. All were under Microsoft’s control, at least initially, by the historical accident of Microsoft’s being the designer and first implementer.

That this collection of MS-DOS and licensed variants amounted to any sort of DOS market with DR DOS as a participant in competition with MS-DOS was only from Digital Research copying the MS-DOS design into DR DOS and declaring that this copy was good enough that programs written for MS-DOS should work on DR DOS too. What Digital Research, and later Novell and Caldera, seem never to have explained is how or why this say-so is supposed to bind any writers of MS-DOS programs to anticipate execution on DR DOS, let alone to bear any costs from their programs turning out not to work on DR DOS too.

This is not to say that copying the MS-DOS interfaces and any amount of supporting architecture to make DR DOS was in any way wrong or unlawful. The usual protections of intellectual property in software, i.e., copyright, patents and trade secrets, seem not to have been available to Microsoft for MS-DOS. Inasmuch as the copying into DR DOS was only of the design, not of any expression, there was no copyright infringement. There were apparently no applicable patents. Even the functions that Microsoft falsely documented as “Not used” in the first version and later as “Used internally” can’t sensibly have been regarded as trade secrets: if nothing else, Microsoft itself distributed with MS-DOS a program named DEBUG that put the workings of undocumented functions in plain sight.

Common Ancestry

There is anyway the complication that Microsoft had copied too. Caldera makes quite a lot of this in a Consolidated Statement of Facts in April 1999 for its law suit. MS-DOS is there said to be variously a copy or clone of an operating system named CP/M which had been developed long before by none other than Digital Research. I perhaps misunderstand Caldera’s point but what I detect is a suggestion that DR DOS was a legitimate competitor of MS-DOS in a DOS market because of common ancestry.

A problem with this is that whatever may have been Microsoft’s grubby business dealings in the early 1980s on the way to birthing MS-DOS, the first MS-DOS was much more distant from CP/M than DR DOS ever was from MS-DOS, and its design relative to CP/M had much more distinct a purpose than DR DOS ever had relative to MS-DOS.

Distance

CP/M had been written for an 8-bit processor, MS-DOS for a 16-bit processor. Both processors were made by Intel and the one was very much a successor of the other but without binary compatibility. MS-DOS never could have run programs that were written for CP/M. DR DOS, in contrast, aimed from the start to run programs that had been (or would yet be) written for MS-DOS.

What certainly was intended for MS-DOS is that programs written for CP/M could be more or less easily rewritten as MS-DOS programs. In the jargon, they could be ported to the 16-bit processor for execution by MS-DOS. Intel had greatly helped by designing the new processor’s Instruction set to allow for mechanical translation from the old as some sort of source-code compatibility, but this did not of itself attend to a program’s interface with a possibly very different operating system. To ease this part of the porting, so that it too was reduced to something approaching a mechanical rebuild, MS-DOS re-implemented the CP/M interface and enough of the CP/M architecture for the interface to work. Thus does MS-DOS have such features as the function numbers from CP/M, the File Control Block (FCB) structure that is used for input and output to many of those functions, the $-terminated strings that are expected for another of those functions, the particular CP/M mechanism of calling through known addresses, and the CP/M architecture of loading .COM programs at a particular offset above a base structure which has those known addresses.3

Purpose

That MS-DOS copied from the CP/M programming interface and architecture is therefore undeniable, but MS-DOS also had a new interface of its own and a significantly extended architecture.4 This was because MS-DOS had the larger purpose of supporting something new: MS-DOS programs.

To ease the writing of new code by programmers who were used to CP/M, and to support more careful porting of old code to get new efficiency from the new operating system, the new interrupt-based interface in MS-DOS includes the CP/M functions. But make no mistake that this was anything but a crutch to help programmers make the transition. It was the new interface that was the more substantial, notably for having new functions. It was the new interface that was greatly preferred for new programming. The Disk Operating System manual for PC-DOS 1.0 documented the call-based mechanism of the CP/M interface only as an “additional mechanism provided for pre-existing programs that were written with different calling conventions”. See especially that the new functions of the new interrupt-based interface were not available through the old call-based interface.

A line was thus drawn at wherever CP/M had yet reached on its old processor. The future of MS-DOS lay entirely with its new interface and new processor. Of the CP/M functions that were carried into the new interface, those that work with the FCB structure were deprecated for new programming as soon as MS-DOS 2.00. This second version is a world apart from the first. Putting this distance firmly on the public record is presumably the internal reason that Microsoft published source code for versions 1.25 and 2.11 in 2014 at the Computer History Museum and in 2018 on GitHub.5

That MS-DOS could run old programs that had been written for CP/M but could now be rewritten for MS-DOS was more than incidental and may even have been important for a time, but MS-DOS was never pitched at being a better CP/M for running CP/M programs even after porting. Right from its birth, MS-DOS was a new operating system aimed at having its own ecology of new programs.

Nothing even vaguely like this can sensibly be claimed for DR DOS. Running old and new programs that were written for MS-DOS, unchanged, was the one reason for existence that DR DOS ever had. For its claim to distinction among PC-compatible operating systems, DR DOS was presented first and foremost as better than MS-DOS for running MS-DOS programs.

That anyone other than Digital Research itself might write programs specifically for DR DOS was at best secondary. It surely did happen—the DR DOS interface does have its own functionality in excess of what it reproduces from MS-DOS—but it seems not to have been much intended. Digital Research did not encourage programmers to write new DR DOS programs in anything like the way that MS-DOS extended the legacy CP/M interface to provide for writing new MS-DOS programs.

WRITING IN PROGRESS

A Simple Incompatibility

None of this attitude of mine to DR DOS, its place in any market and especially about its claimed compatibility with MS-DOS programs is new. For instance, I am the “technical reviewer” who is quoted in Undocumented DOS, Second Edition (on page 182) as

Angrily rejecting DR DOS’s claims to MS-DOS compatibility, one reviewer (no, not a Microsoft employee) dismissed the idea of anyone “actually checking for the presence of this rather imperfect clone” and bluntly told us, “I see no reason why journalists should cooperate with DR’s desire to have programmers share their development and marketing costs.”

Though I don’t agree I was angry, exactly, the email (dated 19th January 1993) that I’m quoted from certainly did have me as “extremely uneasy about special adaptation of code so that it also runs under DR-DOS” (with “special” between underscores in the plain-text email). I very much disagree that my unease “reflects a general feeling that DR DOS is Brand X and pretty much irrelevant.” However wide may have been the perception that DR DOS and MS-DOS are different brands of some generic DOS, with DR DOS yet to gain relevance by competing successfully on price, quality or whatever, I was nowhere near it. To me, DOS meant MS-DOS and its licensed variants such as PC DOS. DR DOS was no more a brand of these than juices pressed from soy beans, almonds or cashews are brands of milk. This is not to say they have no merit—some of those juices are more enjoyable than is most American milk—but they’re not different brands of the same thing. To me, DR DOS could not even be a candidate for consideration as another brand if it would always, as seemed likely, need special accommodation in anyone’s DOS programming.

The occasion for this particular expression of unease about special coding for DR DOS was that a draft of the book’s CRITSECT.C (on page 585) had got itself into some bother about learning the true DOS version rather than a possibly false version from int 21h function 30h (which is subject to the SETVER tool). For exactly this purpose, MS-DOS 5.00 had introduced int 21h function 3306h. Earlier versions fail this function. But how does a program learn that this function has failed? The answer is different in MS-DOS and DR DOS—which, of course, I couldn’t resist pointing out even though it was at best tangential to the larger work of the CRITSECT.C code.

To MS-DOS since version 3.00 or 3.10 (depending on the OEM), int 21h function 33h is one of a handful that the kernel handles entirely on the caller’s stack without enabling interrupts and, as best as possible, without producing side-effects. Notably, these functions change no kernel data that isn’t explicitly related to the function and they especially do not check for Ctrl-Break in the break=on configuration.6 All versions 2.00 and higher handle unknown subfunctions of int 21h function 33h by setting al to FFh and preserving all other registers (including the flags). Earlier versions don’t have function 33h at all, and fail it similarly but with al cleared to zero. These are the MS-DOS indicators that int 21h function 33h fails.

DR DOS 6.0, if not also its earlier versions, handles int 21h function 33h differently—on the caller’s stack, as does MS-DOS, but as a function whose failure produces an error code and has the side-effect of setting extended error information. An unknown subfunction returns with a set carry flag and with ax set to 0001h (this being the error code for an invalid function). This is the DR DOS indicator that int 21h function 33h fails.

Does the difference matter? Not by itself perhaps. There are easy ways around it. Even the side-effect of setting extended error information looks like it can matter only with contrivance, e.g., if for some Terminate and Stay Resident (TSR) program’s reactivation to make DOS calls, the TSR calls int 21h function 3306h before saving extended error information or after restoring it.

Against dismissing this difference as having no consequence in real-world use is the wonder that it exists at all: int 21h function 33h is very nearly as simple as can be. Only functions 50h, 51h, 62h and 64h have simpler implementations (in MS-DOS). These five are the first functions that would be checked in any systematic examination of an int 21h implementation whether by reading binary code or source code, whether the purpose is to reproduce the interface or to assess two implementations for compatibility. DR DOS has clearly gone its own way with these functions. The intention may have been to improve them—and others, as with adding functions 25h, 35h and 59h to those that MS-DOS processes on the caller’s stack—but one outcome, presumably unintended, is that defensive programming that would check for a function’s failure is put to differentiating MS-DOS and DR DOS (or devising a work-around).

Given this difference even for the simplest elements of the interface, it would be extraordinarily naïve to hope that special coding isn’t required for deeper issues too. On how many points, large or small, well-intended or not, need the DR DOS implementation of the int 21h interface differ from that of MS-DOS before the practical need for special coding invalidates the imitator’s claims of compatibility?

Blinkers

The preceding question seems to have got conflicted in the early 1990s—and may be still in the apparently growing community of retro-computing enthusiasts, some of whom are vigorously revising history, at least as recorded by Wikipedia, to favour DR DOS. The conflict I mean is that celebration of DR DOS as a compatible alternative to MS-DOS for running MS-DOS programs often coincided with requests that MS-DOS programmers should keep in mind what different writing may be needed for DR DOS.

The 1990s had opened with MS-DOS in a period of stagnation. Its version 4.00 from 1988 and its slight update as version 4.01 in 1989 were not without innovation, but the new features (such as installable file system drivers) were wanted by hardly anyone. What might have got a broad welcome (as with a menu-driven shell) was unattractive to look at and awkward to use. Totally neglected were features (notably, of using RAM from outside the 1MB address space of the 8086) that were regarded as necessary by the sorts of users and programmers whom we might nowadays call early adopters or influencers. To these users especially, the release of DR DOS 5.0 in 1990 may have felt like fresh air. DR DOS 5.0 and again DR DOS 6.0 in 1991 had features that these users wanted badly but which were many months (even more than a year) from being offered in the next MS-DOS. These were golden years for DR DOS. But with success came increased attention and in its turn closer inspection.

The programming literature inevitably started collecting incompatibilities. For some measure of this, consider the development of Undocumented DOS, Second Edition in 1994 from the original Undocumented DOS, ISBN 0-201-57064-5, also co-authored by Andrew for Addison-Wesley but in 1990.

Though the original had its first printing in October 1990, it may have been prepared before the release of DR DOS 5.0 in August 1990. It talks only of version 3.40 and only then briefly (on pages 24 and 25). An immediate practical point for readers was the reassurance that most of the book’s techniques and samples for using undocumented functions work on DR DOS too. A good general point is that what the book termed “simulated DOS environments” (conspicuously not operating systems) “can only support an undocumented DOS function call or data structure if someone consciously put it there.” But this looks to have been the extent of the authors’ expressed interest. The very large appendix of Undocumented DOS Functions, extracted from the online Interrupt List, made no special cases for DR DOS.

To this baseline, I add—presuming that private communication in email adds useful background for this point without giving away anything secret—that by February 1992, Andrew noted to me that “Several readers have asked for more coverage of DR-DOS” and by July 1992 this had grown to “many readers have asked for coverage of it” (with “many” between asterisks in the plain-text email).

Sometimes, what readers ask for is what readers get. By 1994, Undocumented DOS, Second Edition lists Novell DOS on the cover to show what the book has been “expanded to include”. Inside, a chapter on Other DOSs runs to nearly 50 pages, not quite half for DR DOS (which is now referrred to very much as an operating system). The updated appendix now lists int 21h functions that DR DOS adds to the MS-DOS interface, along with some variations from MS-DOS, especially in structures such as those exposed by int 21h function 52h. Sometimes, the appendix hints at differences of behaviour, as for instance when noting of int 21h function 60h that “for DOS 3.30-6.0, the input and output buffers may be the same”, apparently leaving the reader to speculate whether something they might otherwise have taken as natural is mentioned because it wasn’t true for earlier MS-DOS versions or is not true for some different DOS.7 The full Interrupt List on the book’s diskette clarifies that the DR DOS 6.0 implementation of this function did not have this stated capability even for an update in April 1992. Indeed, this full Interrupt List, dated 1st August 1993, makes very many special cases for the DR DOS implementations—including, by the way, to note the DR DOS handling of int 21h function 3306h (see above) and to classify it as a bug.

Plainly, by mid-1993, it was an open secret that DR DOS and MS-DOS had notably different behaviour in terms of their supposedly common programming interface. That some, even many, still talked of DR DOS as fully compatible can no longer have been wishful thinking in advance of information.

WRITING IN PROGRESS


[1] MS-DOS was designed from the start for customisation. The system files are written in the assembly language of the 8086 instruction set but are selectively adaptable to whatever hardware support a computer’s manufacturer cares to design around this processor. The kernel, named MSDOS.SYS or IBMDOS.COM, assumes notably little about the computer: free use of RAM in one block from address zero upwards (after the processor-defined interrupt vector table); and free use of interrupt numbers 20h to 3Fh. It is apparently not expected to be adapted much by licensees. Hardware dependencies instead go into the other system file, named IO.SYS or IBMBIO.COM, which the computer manufacturer might in principle rewrite substantially if the computer hardware is unusual.

[2] By “very slight” for the degree of adaptation, I mean at the system-programming level, ignoring what any OEM added by way of supposedly useful applications. Though I say there were only a “handful” of OEM adapations, I suspect there were originally many more. In version 2.00 and higher, OEM adaptations are distinguished programmatically by OEM numbers that int 21h function 30h can return in bh. Microsoft is not known to have documented these numbers, but the DOSMGR Virtual Device Driver (VxD) in Windows knows of seven for versions 3.10 to 4.00 inclusive. See DOS Internals, page 111.

[3] A .COM program ported from CP/M runs in a segment of 8086 address space that is set up to mimic the whole 8080 address space. The segment is addressed by all four of the 8086 segment registers, which the ported program can ignore. The first 0x0100 bytes are prepared so that the ported program can treat them as the System Parameters from the base of the CP/M memory map. The particular preparation at offset 0x05 for the CP/M way that the ported program calls what it thinks is the FDOS turned into a very long-lasting difficulty, not so much for the call but because the word at offset 0x06, which encodes the target of the call, doubles as the program’s indication of how much memory is available for its use. There is much too much to this to cover in a footnote: you’d think the Internet must have a definitve treatise to cite by now!

[4] The first MS-DOS, released only as PC DOS 1.00 for IBM, had most famously a new file system whose only significant similarity to that of CP/M was that it kept the case-insensitive 8.3 naming convention from the FCB structure in the CP/M interface (not that similarly constrained filename.ext conventions had been new to CP/M). At least as important immediately was the wholly new file format for executables, allowing them to be much larger than 64KB. Less noticed at the time were the system-generated exceptions int 23h and int 24h. The latter may return to the kernel, which is then to retry whatever had gone wrong, or at least to try picking up as if the error had not occurred. Either way, before the handler returns it is allowed to have called back into the kernel to do character I/O, notably to explain the error and offer to Abort, Retry, Ignore? Thus did version 1.00 have the beginnings of the re-entrancy which went on to support the debatable innovations of Terminate and Stay Resident (TSR) programs, along with networking and pre-emptive multi-tasking. This may in turn be much of how a humble single-tasking operating system for single-processor computers, rather than Xenix or OS/2 or anything else, ended up being the bridge over which the mass market was ushered into modern computing.

[5] Imagine a hobbyist student of the MS-DOS kernel as binary code. In practice, two decades after the last commercial release of an MS-DOS kernel (as integrated into Windows Me), this hobbyist will likely have got hold of an OEM Adaptation Kit (OAK) for a version that preceded the incorporation of MS-DOS into Windows 95. Apparently, the NDA for such kits is long expired, which some take as leaving copyright as the one constraint on distribution and use. In an OAK, the student can read source code, including headers that define structures, and although the kernel itself is represented mostly by object files, not source code, these are rich in symbolic information. For the student who does not have the help of an OAK, the source code that Microsoft has formally published for version 2.11 will still be easy to match against the binary of any later kernel and thus be very helpful for labelling, but the source code for version 1.25 will hardly be recognisable as having any relevance at all.

[6] That the kernel executes these functions entirely on the caller’s stack is untrue in the dos=high configuration of MS-DOS 5.00 and higher if the function is called while the A20 line is disabled. Should this case ever occur, which must be extremely rare in practice, the kernel switches to its auxiliary stack while enabling the A20 line. That int 21h function 33h is among the (ordinarily) re-entrant functions as early as version 3.00 is true for an IBMDOS.COM, dated 22nd April 1985, from an OEM build by COMPAQ, but not for an IBMDOS.COM dated 5th July 1984 from PC DOS.

[7] For the MS-DOS implementation of int 21h function 60h, the translation of input into an internal buffer from which to copy the output on success is as old as the function. That the Interrupt List correctly dates the function’s introduction to version 3.00 but the behaviour to version 3.30 may mean only that no contributors ever reported one way or the other for earlier versions. Incidentally, this function’s use of the internal buffer provides my oldest memory of recognising a buffer overflow in any Microsoft code: the buffer is 80h bytes but the function will parse as many as 86h bytes into it.