It is common knowledge that Windows NT 3.1 only recognizes up to 64 MB RAM, unlike NT 3.5 and later versions. This statement can be found in various places, including this blog. The limitation was empirically determined by installing NT 3.1 on various physical or emulated platforms.
It is easy to accept this as a fact since it is well known that even NT 3.1’s minimum requirement of 16 MB RAM was quite high when it was released in 1993, and systems with 64 MB memory (let alone more) were practically unheard of.
Imagine my surprise when I installed the original build 511 of NT 3.1 on a 1995 Intel server board (that’s a whole another story) and saw the full 128 MB RAM being recognized. Clearly “common knowledge” is not the same as actual facts.
Finding official statements on the maximum memory supported by Windows NT 3.1 is difficult. Key information is available from Microsoft in KB117373, but with an important caveat. The KB article talks about INT 15h/E820h usage but does not mention that NT 3.1 does not support that interface. NT 3.5 does and that is in fact why it has no trouble detecting more than 64 MB RAM on typical systems. So what’s the real story with NT 3.1?
The KB article answers that question fairly accurately, although it does not explain the history of the BIOS interfaces. The original IBM PC and PC/XT only supported conventional memory, whose size NT 3.1 queries with INT 12h. The PC/AT introduced the concept of extended memory (i.e. directly addressable memory beyond 1 MB) and added INT 15h/88h service to detect its size. Said function returns the number of kilobytes beyond 1 MB as a 16-bit value. The PC/AT (286) was architecturally limited to 16 MB physical memory which function 88h had no trouble reporting.
Things got complicated with he PS/2 schism. IBM provided separate memory detection interfaces for PS/2 systems. The rest of the world originally stuck with INT 15h/88h to report more than 16 MB RAM.
Once server systems with 64 MB RAM and more started appearing, INT 15h/88h was no longer sufficient. No later than early 1993 (before NT 3.1 was released), some Compaq machines started supporting INT 15h/E801h which separately reports (as 16-bit values) the number of kilobytes between 1 MB and 16 MB, and the number of 64 KB blocks above 16 MB. It is obvious that this function can report up to 4 GB RAM, the 386 (and 486 and Pentium) architectural limit. The same interface was also supported by Phoenix and AMI BIOSes since 1994.
This function has a significant limitation in that the memory it reports must be contiguous. It is possible to have a memory hole (for device addressing) below 16 MB but nowhere else. For that reason, a more advanced INT 15h/E820h function was soon specified. Another rationale for INT 15h/E820h was that with the advent of PCI, operating systems needed to know not just where RAM/ROM/etc. is but also where it isn’t, and what regions are safe for relocating PCI memory resources into.
The INT 15h/E820h function can report a complex memory map and is supported by modern PCs (it was adopted by ACPI), as well as all modern operating systems. But not by Windows NT 3.1.
So back to NT 3.1. The OS loader (NTLDR/SETUPLDR) calls INT 12h, INT 15h/88h, and INT 15h/E801h (in that order) to detect the amount of installed memory. Obviously INT 15h/E801h is the key to recognizing more than 64 MB RAM since INT 15h/88h can’t report more.
The catch is that NT 3.1 has to successfully call BIOS INT 15h/E801h and the amount of memory between 1 MB and 16 MB returned in register AX must equal the value previously returned by INT 15h/88h. That requires the amount returned by INT 15h/88h to be limited to 15,360 KB, i.e. 16 MB total. That is exactly the problem because most BIOSes do not limit the amount reported by INT 15h/88h… because if they did, all the software which only relies on that function could not use memory between 16 MB and 64 MB. The limitation is documented in the above mentioned KB article.
The above screenshot shows NT 3.1 (using the original boot loader) recognizing 1GB RAM when INT 15h/88h returns 15MB and INT 15h/E801h is available.
OS/2 2.11 and Warp
Windows NT 3.1 was not alone in using this logic. OS/2 2.x used a very similar approach, as documented by IBM. OS/2 2.11 used it and the initial OS/2 Warp, as well as Warp Connect, still used the same algorithm. OS/2 Warp Server already changed the logic and works with typical BIOSes. That means an updated OS/2 Warp (or Warp 4) can detect more than 64 MB RAM even when INT 15h/88h reports 64 MB.
OS/2 2.0 and 2.1 did not detect more than 16 MB on PC/AT-class machines out of the box, although fixes were available to support larger memory sizes. Needless to say, this was not a huge issue in 1992-1993.
It is worth mentioning that HIMEM.SYS distributed with MS-DOS 6.0 (and likely other HIMEM.SYS versions) can also utilize INT 15h/E801h. Unfortunately, unlike NT 3.1, HIMEM.SYS only calls the function if it determines that the system is a Compaq EISA machine. NT does not implement any such restriction.
Finally, it is unavoidable to mention the infamous “OS select for DRAM > 64MB” option found in many BIOSes, with the choices being “OS/2” and “Non-OS/2”. The option is only useful for OS/2 2.11 and early OS/2 Warp FixPack levels, not for OS/2 in general. On systems with more than 64 MB, it reduces the memory reported via INT 15h/88h to exactly 15 MB, so that the amount of extended memory below 16 MB reported by INT 15h/E801h matches. That satisfies the assumptions of OS/2 2.11/Warp, and presumably NT 3.1, allowing the OS to recognize more than 64 MB RAM. With newer OS/2 and NT versions, the BIOS option is harmful (because it confuses software relying strictly on INT 15h/88h) and should not be used.
This problem is largely a result of lack of leadership. IBM thought it led when it introduced the PS/2 platform, but the rest of the world it did not follow. Compaq, Intel, or Microsoft did not have nearly as much clout in the early 1990s as IBM once did. And so the PC platform turned into a fragmented mess, resulting in many headaches for the users.