Geoff Chappell - Software Analyst
The UNSUPPORTED_PROCESSOR bug check shows that at least one processor is of a type that is not supported.
|Bug Check Code:||UNSUPPORTED_PROCESSOR|
|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.
Starting with version 5.1, other processors cause this bug check if they lack support for particular CPU features:
In these cases, the arguments describe the offending processor. 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 6.1
The significance of the highest byte is not presently known.
Although support for the CMPXCHG8B instruction is established by testing for the feature rather than inferring it from a processor identification, a consequence of requiring this support is that the 80486 processor is unsupported since Windows XP, 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.)
The x64 builds have completely different requirements, of course. The parameters for the bug check are different, too:
|Bug Check Code:||UNSUPPORTED_PROCESSOR|
|1st Argument:||feature bits, if processor rejected because of inadequate features;
All known builds of 64-bit Windows, up to and including version 6.1 for Windows 7, limit their support to particular vendors. These are identified from the vendor string, meaning the sequence of characters obtained by executing CPUID with 0 in EAX and then storing the values of ebx, edx and ecx at 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 would be denied their most substantial market until Microsoft condescends with some sort of new release that does not dismiss competing processors as unsupported. 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.
All the feature bits FPU, DE, PSE, TSC, MSR, PAE, MCE, CX8, APIC, MTRR, PGE, MCA, CMOV, PAT, CFLSH, MMX, FXSR, SSE and SSE2 must be set, and the SYSCALL and SYSRET instructions must be supported. The feature bits are returned in edx after executing CPUID with 1 in EAX. The SYSCALL and SYSRET instructions are supported if executing CPUID with 0x80000001 in EAX sets bit 11 in edx. Failure on either count is indicated by reproducing the feature bits as the 1st bug-check argument.
Up to and including the version 6.0 from the original Windows Vista, the 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 x86 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 and Windows Server 2008 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 this bug check a different name (HEAP_INITIALIZATION_FAILED). Some detection of unsupported processors is performed and acted on, however. Early steppings of the 80386 are rejected as the boot processor by raising bug check 0x5C:
|Bug Check Code:||HAL_INITIALIZATION_FAILED|
|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 number must be greater than 1 to avoid the bug check.
Microsoft’s documentation says that there are no parameters for this bug check.