Windows NT 3.1 April 1991 build

April 1991 build
Build of Windows NT 3.1
Screenshot
Reversi running under x86 emulation
OS familyWindows NT
Version number4.0
ArchitectureMIPS R3000
Compiled on1991-04-04

The Windows NT 3.1 April 1991 build is an otherwise unidentified early build of Windows NT 3.1, which is currently the earliest available build of Windows NT overall. Disk images labeled "WOW Reversi MIPS Demo" that contain ZIP archives with the build's files were added to the PCjs miscellaneous diskette repository on 4 November 2023 by Jeff Parsons, the developer of the PCjs website and a former Microsoft employee.[1]

The build is compiled against an early version of the Microsoft Jazz architecture that predates the launch of the MIPS R4000 processor. As such, it actually targets the earlier R3000 processor, which is not fully compatible with the R4000.

The build was used for an internal demonstration of Reversi running under Windows on Windows and x86 emulation on a MIPS machine during a weekly "Thursday Beers" event.[2] This demonstration was memorable for Reversi displaying square pieces rather than round, because GDI couldn't draw circles or curves yet.[2][3] The primitives implemented by this build's GDI only include lines, rectangles and text. Furthermore, only solid color brushes are supported. According to internal conversations, GDI was not planned to be code complete until June 1991.[4]

Emulation[edit | edit source]

A kernel debugger instance running on OS/2 2.0 connected to the build, showing the Session Manager command line prompt.

This build can be emulated using a modified version of MAME that adds a custom R3000-based Jazz machine. In order to boot the build, another virtual machine running MIPSKD.EXE (located in NT.ZIP on disk #1) on OS/2 also must be connected via a serial port to the MAME instance.

Building the emulator[edit | edit source]

Assuming a development environment prepared beforehand, run the following command in the MAME source code directory:

$ make -j8 SUBTARGET=r3000jazz SOURCES=src/mame/microsoft/r3kjazz.cpp

Successful compilation will result in a r3000jazz executable in the cloned repository.

Setting up OS/2 for debugging[edit | edit source]

The build requires a kernel debugger to be attached because it executes a breakpoint early in boot. Without a debugger attached, it cannot be made to continue past that point. Therefore, it is recommended to set up a OS/2 2.0 virtual machine with a serial port that can connect to MAME to run the included MIPSKD.EXE. Make sure to enable the serial port during OS/2 setup, otherwise it will not be accessible.

The serial port can be configured in VirtualBox for use with MAME and NTSerialPort as follows:

  1. Open Settings
  2. Go to the Serial Ports tab
  3. Check the Enable Serial Port checkbox
  4. Set port number to COM1
  5. Set port mode to TCP
  6. Uncheck the "Connect to existing pipe/socket" checkbox
  7. Set path/address to 31337

It is possible (although not required) to set up debugging symbols by copying the entire NT installation into C:\NTOLD and then using DEBUG.CMD from disk #1 to launch the debugger instead of running MIPSKD.EXE directly.

Running NT[edit | edit source]

  1. Start the kernel debugger.
  2. Start NTSerialTool if running the debugger inside VirtualBox.
  3. Run MAME with $ ./r3000jazz r3000jazz -serial0 null_modem -bitb socket.127.0.0.1:31338 -hard1 <path to disk image> -window, where <path-to-disk-image> is the path to your disk image with NT.
  4. Start NT by running \ntoskrnl in the ARC firmware.

At this point, log messages should start appearing in the debugger, eventually arriving at the NT SM> prompt. The build will often break into the debugger; if this happens, type g into the debugger and press Enter.

If the ARC firmware shows an NVRAM warning on startup or cannot find the kernel file, go to Run setup > Initialize system > Set default configuration, press Enter at all prompts and then exit out of setup.

Emulator issues[edit | edit source]

Serial port baudrate[edit | edit source]

The emulation expects that the serial port is operated at 9600 bps. Some virtualizers such as VirtualBox might send data faster than the expected baud rate, resulting in the debugger not working correctly.

NTSerialTool can be used to limit the baud rate. The serial port for the debugger virtual machine first needs to be first set up so that it listens on TCP port 31337. When trying to run the build, start the VM first, then run NTSerialTool and then start MAME with serial port connected to TCP port 31338. If configured correctly, the tool will show that it connected to MAME.

Cursor[edit | edit source]

The hardware cursor is currently not emulated, therefore the cursor is not visible. Mouse clicks will still work, however not being able to see the cursor makes interacting with the OS difficult. It may be easier to use keyboard shortcuts to navigate around.

SCSI errors[edit | edit source]

Random SCSI errors may occur, most likely because of bugs in the emulator. Currently there is no workaround for this issue, and the emulated machine must be reset if SCSI error occurs.

Branding[edit | edit source]

The build includes inconsistent branding, owing to its primitive nature:

  • The internal version number (set by the BaseGetConnectInformation function in BASESRV.DLL, which is used to update the global variable returned by the GetVersion function in BASE.DLL) is set as 4.0, and the command-line shell (CMD.EXE) similarly identifies itself as Windows Version 4.0 Command Interpreter;
  • Configuration files and kernel identify the operating system by its original project name, NT OS/2;
  • The desktop in the graphical shell refers to the operating system as NT 32-bit Windows (in a similar nature to builds 175 and 196) whereas other aspects of the system simply refer to it as just NT, and;
  • A number of file descriptions utilize the Windows 32 naming.

Directory layout[edit | edit source]

Path Archive Contains
\ NT.ZIP (disk #1) Kernel, configuration file and the Session Manager
Nt
Bin NTBIN.ZIP (disk #2) Most executable files
Bin86 NTBIN86.ZIP (disk #2) Disk images and save states used by the x86 emulator
Dll NTDLL.ZIP (disk #3) Libraries
SubSys NTSUBSYS.ZIP (disk #2) Subsystem executables
Windows NTWIN.ZIP (disk #2) WIN.INI
Fonts Font files

Windows-on-Windows[edit | edit source]

This is the earliest known build to include Windows-on-Windows (WoW), a compatibility layer that allows 32-bit Windows to run 16-bit DOS and Windows applications. The environment in this build is based on MS-DOS 5.00 build 336 and a very early build of Windows 3.1, which are loaded by the x86 emulator (X86.EXE) from two disk images (DOS500.DSK and WOW.DSK). This is a notable difference from later builds, which load the system files directly from disk as the host file system is passed through to the DOS environment by NTVDM. Furthermore, the x86 emulator is an inhouse project, rather than the customized version of SoftPC that shipped with the retail version. The source code for a later version of this emulator was released by Jeff Parsons on 14 November 2023, 10 days after the original build upload.[5]

Calendar, Reversi and Notepad from Windows 3.0 are included, while the rest of the system is dated from 25 January 1991 to 20 March 1991, which predates build 026, the earliest available build of Windows 3.1. Also included are HELLO.EXE and GENERIC.EXE sample applications. USER.DLL, dated 18 March 1991, was deleted from the disk at some point. Because SHELL.DLL (which contains the About dialog where the version and build information is displayed) from this build is not included, it's not possible to determine the exact build number.

Unlike the released version of WoW, the 16-bit Windows components run in real mode, not protected mode. Further reverse engineering will be required to determine the thunking mechanism (invalid instruction sequence? interrupt?) used for GDI.EXE and USER.EXE to call into their Win32 counterparts.

REVERSI.HOT[edit | edit source]

REVERSI.HOT (located in C:\Nt\Bin86; NTBIN86.ZIP on disk #2) is a state save of this build running Reversi under x86 emulation. The first 640 KiB stores the memory content of the x86 virtual machine. The next 88 bytes describes the state of the registers and other data. The last 2000 bytes contains every character that was on the console (80x25 characters) before Windows entered graphics mode. This file was likely prepared to save time required for initializing MS-DOS, 16-bit Windows and loading Reversi under emulation, which may have occupied a significant amount of time.

Text on the screen before 16-bit Windows entered graphics mode (note dte instead of date, this is due to the x86 emulator having an issue with printing the lowercase a character):

Current dte is Sun 01-06-1980
Enter new dte (mm-dd-yy):
Current time is  5:59:56.58
Enter new time:


Microsoft(R) MS-DOS(R) Version 5.00.336ß
             (C)Copyright Microsoft Corp 1981-1990.

A>b:

B>kernel reversi.exe
B:\SYSTEM.INI

State saves may be loaded by entering l <path-to-save-file> and created by entering s <path-to-save-file> at the x86 emulator prompt.

Console mode[edit | edit source]

Task manager shown when running a console application.

This build includes an early implementation of the console subsystem, which is incompatible with GDI (enabled by default). In order to launch console applications, such as CMD.EXE, it is required to enable the console subsystem first by setting the subsystem line in NTOS2.CFG to the following:

SubSystem = \SystemDisk\Nt\SubSys\csrss.exe ObjectDirectory=\Windows SubSystemType=Windows ServerDll=basesrv,1 ServerDll=consrv,2

Console mode cannot run simultaneously with the SM prompt, as the prompt blocks all code execution. Running the DELAY -1 command by entering it into the prompt or setting it as the InitialCommand in NTOS2.CFG will effectively disable the SM prompt and allow the console mode task manager to draw itself onto the screen and accept input. The default shell can then be launched by choosing the "Start a Program" option and pressing Enter. However, doing so results in an assertion failure as the result of a failed console handle dereference.

API differences[edit | edit source]

This build features a primitive version of the Win32 API. Many frequently used functions are missing and only the ANSI character set is supported, making it the only available build of NT to not have 2 variants (ANSI and Wide) of every function involving strings. Furthermore, GRE and USER must be manually initialized by calling Initialize and InitWindows respectively. It is also worth noting that WinMain is not supported, all programs (native, console and GUI) must only use the C-styled main function as entry point. As a result, handle to the current instance is typically obtained through the Process Environment Block found in the Thread Environment Block.

Compared to build 196, the Graphics Rendering Engine is implemented in a separate DLL (GRE.DLL) rather than being a part of the GDI server DLL (GDISRV.DLL). This is similar to the separation of the GPI and the graphics engine in OS/2.

Bugs and quirks[edit | edit source]

  • The visible resolution is limited to 1024x1024, even though the actual display resolution is 1280x1024. The right-most portion of the screen is covered by a black bar, although window outlines are still rendered if dragged into the area. This is caused by the hard coding of 1024x1024 as the dimensions of window stations' desktop windows (xxxCreateWindowEx(0, 0x8001, NULL, WS_POPUP | WS_CLIPCHILDREN, 0, 0, 1024, 1024, NULL, NULL, hModuleWin, NULL)). This bug can be fixed by changing the byte at offset 0x47D05 of USERSRV.DLL from 04 to 05.
  • The letter "a" does not appear properly in the x86 emulator windows, it also cannot be inputted to any WOW process.

Gallery[edit | edit source]

References[edit | edit source]