Geoff Chappell, Software Analyst
The UNSUPPORTED_PROCESSOR bug check shows that at least one processor is of a type that is not supported.
Perhaps for backwards compatibility with a time when processors were much simpler, the bug-check arguments for 32-bit Windows tell nothing more than what processor is present, and leave the user to wonder what about the processor does not suffice.
|Bug Check Code:||UNSUPPORTED_PROCESSOR (0x5D)|
|1st Argument:||0x0386 if processor is an 80386;
family, model and stepping, if processor rejected because of inadequate features
|2nd Argument:||0 if processor is an 80386;
first four characters of CPU vendor string, if processor rejected because of inadequate features
|3rd Argument:||0 if processor is an 80386;
second four characters of CPU vendor string, if processor rejected because of inadequate features
|4th Argument:||0 if processor is an 80386;
third four characters of CPU vendor string, if processor rejected because of inadequate features
All 80386 processors are unsupported in version 4.0 and higher. When the unsupported processor is an 80386, the first bug-check argument is 0x0386 and the others are all zero.
In versions 4.0 and 5.0, the 80386 is the only unsupported processor and the only possible cause of this bug check. Starting with version 5.1, other processors cause this bug check if they lack support for particular CPU features. The family, model and stepping are given as byte-wide bit fields in the first argument:
|bits 0 to 7||stepping|
|bits 8 to 15||model|
|bits 16 to 23||family|
|bits 24 to 31||1 in versions 5.1 and 5.2;
3 in versions 6.0 and higher
The significance of the highest byte is not presently known. The remaining arguments are the CPU vendor string, as produced in registers ebx, edx and ecx, respectively, when executing cpuid with 0 in eax.
Successive Windows versions need ever more CPU features. For the most part, each feature has a corresponding bit in feature flags that are returned in one or another register after executing one or another function of the cpuid instruction, and the feature is present or absent according to whether the bit is set or clear. However, 32-bit Windows dates from a time when the cpuid instruction was not nearly so well established, and the tests for some features are complicated by special cases.
Windows XP kicks off the escalating requirements by insisting on the cmpxchg8b instruction. At its simplest, support for the CMPXCHG8B instruction is indicated by a set CX bit (8) in the feature flags from cpuid function 1, but there are complications for processors from several vendors. A consequence of requiring cmpxchg8b is that all 80486 processors became unsupported in version 5.1 and higher, if Intel is to be believed that this instruction “is not supported on Intel processors earlier than the Pentium processors.” (See the Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 2A: Instruction Set Reference A-M.)
Version 6.0 and higher require the rdtsc instruction and its time-stamp counter.
Version 6.1 insists on having a numerical coprocessor, such that its absence causes this bug check. Later versions do not.
Version 6.2 greatly increases the required features. Precisely how each feature is detected is beyond the present scope of this article. Some are a simple matter of testing for a corresponding bit in feature flags that are returned by the cpuid instruction. As with support for cmpxchg8b, however, there are special cases for more than a few. For now, only a summary can be ventured. The newly required features are:
Note that in version 6.2 and higher, the kernel is anyway distributed only in its form that supports Physical Address Extension (PAE) and thus necessarily with 64-bit page table entries. Checking for PAE support, however, is not the business of this bug check.
The x64 builds have completely different requirements, of course. The parameters for the bug check are different, too, and have been getting more informative as 64-bit Windows matures:
|Bug Check Code:||UNSUPPORTED_PROCESSOR (0x5D)|
|1st Argument:||feature bits (edx from
cpuid function 0x01), if processor rejected
because of inadequate features;
|2nd Argument:||extended feature bits (edx from
cpuid function 0x80000001), if processor rejected
because of inadequate features (6.2 and higher);
|3rd Argument:||extended feature bits (ecx from
cpuid function 0x80000001), if processor rejected
because of inadequate features (6.3 and higher);
|4th Argument:||non-zero count of faults from attempting to execute
prefetchw instruction (6.3 and higher);
For the extended features if presented for the 2nd argument, the XD bit (20) is simulated as set if the processor has AuthenticAMD as its vendor string.
All known builds of 64-bit Windows, up to and including version 10.0, limit their support to particular CPU vendors. These are identified from the vendor string, meaning the sequence of characters obtained by executing cpuid with 0 in eax and then copying ebx, edx and ecx to successive memory locations. Any but the following cause this bug check, with zero in all arguments:
Perhaps there’s no law that requires Microsoft to allow its software to run on every CPU that’s said by its manufacturer to be x64-compatible. Yet even if there were no other manufacturers of x64-compatible processors when Microsoft wrote this code, the effect must have been plain at the time: any manufacturers who do eventually make an x64-compatible processor to compete with AMD and Intel are denied their most substantial market until Microsoft condescends with some new release of Windows that does not dismiss competing processors as unsupported—and then, to sell their new processor, they are drafted into Microsoft’s mission of persuading computer users to obtain this latest Windows release. This is behaviour that might be expected of a cartel, with Microsoft using its operating-system monopoly to protects its friends’ interests in the competitive market of processors that share the x64 instruction set. It ought perhaps be investigated by regulatory authorities.
From the start, 64-bit Windows insists on processors that have many of the relatively modern CPU features that the contemporaneous 32-bit builds still had to be capable of doing without. Perhaps as an advantage of starting late and of having fewer vendors to accommodate, 64-bit Windows has none of the complexity that 32-bit Windows faces for testing the presence of required features. Mostly, 64-bit Windows depends just on flags returned by two executions of the cpuid instruction.
In the feature bits that are returned in edx after executing cpuid with 1 in eax, all the following must be set: FPU (0), DE (2), PSE (3), TSC (4), MSR (5), PAE (6), MCE (7), CX8 (8), APIC (9), MTRR (12), PGE (13), MCA (14), CMOV (15), PAT (16), CFLSH (19), MMX (23), FXSR (24), SSE (25) and SSE2 (26).
A set SYSCALL bit (11) is required in the extended feature bits that are produced in edx by executing cpuid with 0x80000001 in eax. In version 6.2 and higher, the XD bit (20) must be set too, except that this is taken as granted if the processor’s vendor string is AuthenticAMD.
Version 6.3 and higher also inspect what’s returned in ecx by these executions of cpuid. The CX16 bit (13) and the LAHF bit (0) must be set in the flags that are produced by cpuid functions 1 and 0x80000001, respectively.
Harder to establish, but no less required, is support for the prefetchw instruction. There is no feature flag to check for this. Instead, in version 6.3 and higher, support is tested by trying to execute the instruction and seeing if the processor objects. This is less of a change from earlier versions than might at first be thought. All known builds of the 64-bit kernel use prefetchw liberally. Before version 6.3, if the processor happens not to support the instruction, then a handler for the Invalid Opcode exception keeps putting things right for continued execution, including to patch the instruction away so that the performance hit from the exception doesn’t recur. The change for version 6.3 is just to do away with the patching but with a check that it’s not needed.
Failure on any of these counts causes the bug check. The arguments tell which features were found but leave the user to deduce which missing feature (or features) matter.
Up to and including the version 6.0 from the original Windows Vista, the 64-bit kernel checks that division of 0x004B5FA3A053724C by 0x00CB5FA3 gives 0x5EE0B7E5. The test is a 32-bit div of edx:eax by r8d. This may look plausible as defending against a defect in some processor’s arithmetic, such as Microsoft has done at various levels in 32-bit builds of earlier Windows versions (for multiplications in the 80386 and floating-point divisions in the Pentium). However, this particular test is nothing of that sort. For one thing, it is performed surprisingly late. If you genuinely doubted the accuracy of a processor’s arithmetic, you would test it before depending on the arithmetic. Yet by the time the kernel performs this test division, it has performed similar divisions already. Indeed, though the tests for vendor and features are performed almost immediately that the kernel starts executing, the test for accurate division is left until phase 1 of initialisation.
In fact, this division serves as the way to initialise Kernel Patch Protection, also called PatchGuard. This is a scheme by which the kernel records the state of various sensitive items at startup and defends against run-time changes, which are held to be malicious and are usually dealt with as bug check 0x0109. When the test division executes while a kernel debugger is attached, it proceeds as expected. However, in the ordinary execution, without a kernel debugger, a contrivance in the code changes the division so that the high byte of the dividend is 0x01. This makes the high 32 bits of the dividend larger than the divisor, so that the div instruction faults. The exception handler initialises PatchGuard. If this initialisation succeeds, the div is restarted with the 0x01 cleared from the high byte of the dividend and the expected quotient is obtained. If the initialisation fails, the div is restarted with the highest two bytes cleared from the dividend, such that the quotient is incorrect and causes this bug check. A recommendable article on the details of PatchGuard, including its initialisation and how the initialisation is reached through this division, is Bypassing PatchGuard on Windows x64. Regular readers of this website will know that it is no small compliment for me to cite other people’s research as reliable enough to be recommended.
The version 6.0 from Windows Vista SP1 changes the mechanism by which PatchGuard gets to initialise. It still relies on contriving an exception from a (different) division but without any implications for this bug check.
The UNSUPPORTED_PROCESSOR bug check can occur in version 4.0 and higher.
No code is known for raising this bug check in version 3.51. Contemporaneous documentation (the Windows NT 3.51 Resource Kit) even gives bug check 0x5D a different name (HEAP_INITIALIZATION_FAILED). Some detection of unsupported processors is performed and acted on, however. The kernel rejects early steppings of the 80386 by raising bug check 0x5C:
|Bug Check Code:||HAL_INITIALIZATION_FAILED (0x5C)|
|2nd Argument:||processor family, i.e., 3 for 80386|
|3rd Argument:||processor model and stepping|
In the 3rd argument, the stepping is the low 8 bits and the model is the next 8 bits. Both are simulated from testing for various defects, as described in CPU Identification by the Windows Kernel. This simulated model must be greater than 1 to avoid the bug check.
Microsoft’s documentation says that there are no parameters for this bug check.