Attempting to install the October 1992 pre-release on any CPU less than about 20 years old is likely to result in the following error message:
This is similar to the behavior of the official Windows NT 3.1 and 3.5 releases, but harder to work around, and likely to happen even on Pentiums and some 486s. The reason for that is that Microsoft knew too much, but not enough.
In the October 1992 beta version of Windows NT, the installer recognized 386, 486, and 586 CPUs. This was a change from the July 1992 pre-release, which only knew about 386s and 486s. The Pentium processor was in fact only released in March 1993, after unexpected delays.
Microsoft had clearly inside information from Intel and the October 1992 Windows NT beta uses the CPUID instruction to identify the processor. This may well be the first more or less public use of the CPUID instruction, about six months before the official release of the first processors with CPUID support.
Unfortunately Microsoft’s usage completely contradicts the published Pentium documentation. It seems safe to assume that Intel gave Microsoft early specifications which then changed before the chip was released. Why Microsoft applied this information before it could be tested on any released hardware is a different question.
What is certain is that the NT kernel (typically NTOSKRNL.EXE) detects the CPU type during startup. This is done in a function called KiSetProcessorType.
KiSetProcessorType uses the standard Intel CPU identification algorithm, with the assumption that the CPU has to be at least a 386, as it is already executing 32-bit code. First the code attempts to modify the AC (Alignment Check) bit in EFLAGS. If that succeeds, the CPU is assumed to be at least a 486. Otherwise KiSetProcessorType goes off to determine the 386 stepping by checking for specific implementation quirks.
If the CPU is determined to be at least a 486, KiSetProcessorType attempts to modify the ID bit in EFLAGS to verify CPUID support. If the bit can’t be modified, the function again goes off to determine the 486 stepping. If CPUID support is found, KiSetProcessorType executes CPUID and uses the standard technique to extract the processor family and stepping.
Except Microsoft’s code doesn’t work. It appears that some early CPUID specification presumed that only a single set of information would be returned by CPUID in EAX/EBX/ECX/EDX. Later someone realized that it would be much better to make the mechanism extensible, and the contents of EAX register determine what information CPUID returns. For the original Pentium, only EAX values of 0 and 1 were supported, and all other values returned zeros in EAX/EBX/ECX/EDX.
The writers of Windows NT were clearly unaware of this and did not set EAX to any specific value prior to executing CPUID. KiSetProcessorType copies CR0 contents into EAX on function entry, so the typical EAX value when executing CPUID might be something like 8000003Fh.
The effect this has on CPUID is processor specific. For the Pentium, the documented response is to return zeros. For the Pentium Pro and for 486s with CPUID support, the response is undocumented. For current Intel processors, the documented response is to return the data for the highest supported standard CPUID leaf. The latter behavior was verified with Core 2 and Core i7 CPUs, as well as with an old Pentium II system.
The upshot is that the October 1992 beta of Windows NT probably won’t get the expected response on any processor with CPUID support, not even on a Pentium or a 486. The detected family might end up as 0 (on a Pentium), as 1 (on at least some Pentium II systems), or some other more or less random value which the installer certainly will not like.
What can be done about this? Either run this beta version of Windows NT on a CPU old enough that it doesn’t support the CPUID instruction (a 386 or an old 486), or patch the NT kernel. If the latter strategy is chosen, the following instruction sequence
or ebx,0x00200000 push ebx popfd cpuid
needs to be replaced with something along the lines of
xor eax,eax inc eax nop ... cpuid
The effect of this change is that the CPUID bit in EFLAGS is not restored (which isn’t necessary) and EAX is forced to 1, which will cause CPUID to deliver the data the rest of the routine expects. Naturally this will also require the actual CPUID to be faked, except when running on a 486 or a Pentium. But that’s a lot easier.
Alternatively the NT kernel could be patched to force a specific processor family (not using CPUID at all), though this was not explored. Note that this build of Windows NT has no checksums or other mechanisms that would make patching troublesome; simply modifying the code in the executable image is enough.
With the patched kernel in place, the Windows NT setup finally relents and does not prevent installation anymore.
Update: New information has come to light officially confirming the above speculation. Preliminary P5 (aka Pentium) documentation specified a much simpler CPUID instruction which took no input and reported processor model information in the AX register.
The information returned by CPUID was designed to match the data placed into the DX register after reset, but it was readable at any time, available from unprivileged code, and the CPUID instruction was also intended to be a serializing instruction that unprivileged code could use. The latter use is still valid, but complicated by the fact that CPUID implemented in production processors destroys the contents of EAX/EBX/ECX/EDX registers, which is hardly helpful for serialization.
The initial CPUID design did not involve EFLAGS at all and users were expected to handle the invalid opcode exception on 486 CPUs. Someone presumably explained to Intel that a less intrusive design was needed, because applications could not necessarily recover from invalid opcode exceptions. The October ’92 NT pre-release was clearly written to a newer specification which used EFLAGS, but did not yet change the operation of the CPUID instruction itself.