CPU Identification by the Windows Kernel

The Windows kernel executes an identification routine for each processor.

Identification Algorithms

The primary means of identification is of course the CPUID instruction, which was introduced with some models of the 80486 processor. The kernel regards the CPUID instruction as unimplemented by the processor if either:

In the simplest cases needed for learning the family, model and stepping, the CPUID instruction takes a function number in the EAX register. Execution with zero in EAX produces in eax the maximum supported function number. The family, model and stepping are expected as results of executing function 1. If the execution of function 0 did not return at least 1 in eax, then the CPUID instruction is not the slightest bit useful to the kernel and is dismissed as unsupported, such that the processor must be an 80386 or 80486.

(As an aside, this article makes a convention of using upper and lower case to indicate whether a register is used for input or output, respectively.)

Pentium and Higher

Having confirmed that the CPUID instruction is usable for obtaining a family, model and stepping, the kernel re-executes functions 0 and 1.

Execution with 0 in EAX returns something in eax, as noted above, but what matters now is that a vendor identifier is returned in other registers. Specifically, if the values returned in ebx, edx and ecx are stored at successive memory locations, they read as a string of single-byte characters. The Windows Vista kernel knows the following vendor strings, at various times, for various purposes:

but for the basic matter of discovering the family, model and stepping, only “GenuineIntel” is given any significance.

When CPUID is executed with 1 in EAX, it returns version information (also called a processor signature) in eax, in which the family, model and stepping are bit fields:

bits 0 to 3 stepping
bits 4 to 7 model
bits 8 to 11 family
bits 16 to 19 extended model
bits 20 to 27 extended family

The family and model were originally 4-bit numbers, represented directly by corresponding 4-bit fields. Recent processors provide for 8-bit family and model numbers, composed from two fields. The 8-bit family and model are indicated when the 4-bit family field is full, i.e., contains 15. If the vendor is “GenuineIntel”, then the 8-bit model is also indicated when the 4-bit family field contains 6.

The 8-bit family is formed by adding the 4-bit family field to the 8-bit extended family field. The 8-bit model is formed by taking the 4-bit model field for the low bits and the 4-bit extended model field for the high bits.

Older Windows Versions

In Windows NT 4.0 (original, from 1996), the family field is taken as 3 bits, not 4, and the two extended fields are ignored. In one notable case, the NT 4.0 kernel does not ask for the processor signature from CPUID but assigns the processor to family 5, model 0 and stepping 0. This case applies if executing CPUID with zero in EAX returns with eax greater than 3. Mostly, the kernel reacts thereafter as if CPUID is unavailable. Whether this was intended as a defence against implausibility when CPUID was a relatively new and perhaps unstable facliity, it at least risked a future compatibliity problem. Later processors from Intel can be configured to limit the returned maximum to 3 by setting bit 22 in the machine-specific register IA32_MISC_ENABLE (0x01A0). Intel’s literature suggests that “BIOS should contain a setup question that allows users to specify when the installed OS does not support CPUID functions greater than 3.” It is not known whether NT 4.0 was the cause, but if you wanted to install NT 4.0 on a new computer, you might do well to look for this BIOS option.

The Windows 2000 kernel (original, from 1999) drops the defence against CPUID returning more than 3 as the maximum function. It also widens its knowledge of the family field to 4 bits.

Windows XP (Service Pack 1a, from 2002) recognises the two extended fields when the 4-bit family field holds 15, but is not coded for Intel’s use of the extended model when the 4-bit family is 6.

Older Processors

The processor signature predates the CPUID instruction, but only as the initial value of the EDX register after reset. Many, if not all, machines with these processors even have BIOS support through which this value can be retrieved (by resetting the processor, without losing memory, having configured the BIOS not to reinitialise as if from a reboot but to resume execution at a given address, with the EDX register preseved from the reset). This is perhaps a bit much for the kernel, if not for anyone. When faced with a processor that does not have a CPUID instruction to report the processor signature, the kernel invents family, model and stepping numbers from the results of various tests. How closely these correspond with information from Intel is not known.

Of course, with the Pentium being substantially more than a decade old, the tests that the Windows kernel uses for identifying processors that do not support CPUID are surely of historical interest only. The relevant code is unchanged since at least Windows NT 4.0 (byte for byte), and is surely even older than that, since it was for NT 4.0 that Microsoft formally withdrew support for the 80386.

If the AC bit (0x00040000) in the EFLAGS register can be changed, then the processor is deemed to be an 80486 (family 4). Otherwise, it is an 80386 (family 3).

Early 80486

Some, perhaps even many, 80486 processors do implement the CPUID instruction. For those that do not, the kernel tests successively for what seem mostly to be defects. Any 80486 that passes all the tests is model 3.

Family Model Stepping Test
4 0 0 ET bit (0x10) of CR0 register can be cleared
4 1 0 reading DR4 register causes Invalid Opcode exception
4 2 0 numeric coprocessor not present;
or pseudo-denormal not normalised for fractional FSCALE
4 3 0  

According to Intel (see, for instance, section 17.17.1 of the Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide, Part 1), the ET bit of CR0 is hard-wired to 1 for Intel486 processors. Presumably then, it can be changed on some early 80486 processors only as a defect, which distinguishes what Microsoft regards as model 0.

The DR4 register has long been documented as reserved, but Intel notes (see sections 17.22.3 and 18.2.2) that it has long been aliased to DR6. No indication is given of when this started, but Microsoft seems to think it begins after what Microsoft calls model 1.

Detection of a numeric coprocessor is a standard test. The kernel clears the MP, EM, TS and ET bits of the CR0 register, initialises the floating-point unit (FPU) and reads the floating-point status word. An FPU is present if all flags in the low byte are clear. With the test done, the kernel sets the EM, TS and NE bits of the CR0 register, and also the ET bit if the coprocessor was detected.

Model 2 is identified by a defect in the FSCALE instruction’s handling of pseudo-denormals. These are 80-bit floating-point numbers that have zero as the biased exponent and 1 as the integer part. They ought never be given as operands, but are tolerated for compatibility. They supposedly cannot be generated as the result of a floating-point operation. They, along with actual denormals, are supposed to be normalised automatically if the Denormal Operand exception is masked. Scaling by a fraction leaves a normalised operand unchanged. Model 2 is apparently defective in that fractional scaling leaves a pseudo-denormal operand un-normalised. For testing the FSCALE instruction, the kernel clears the MP, EM, TS and ET bits of the CR0 register and masks all floating-point exceptions (by setting the low 8 bits of the floating-point control word). The 80-bit pseudo-denormal used for the test is zero except for having 1 as its integer part. If scaling the pseudo-denormal by 0.5 leaves the exponent as zero, then the processor is model 2.

80386

Finer identification of 80386 processors is largely academic. Whatever the model or stepping, the 80386 processor is unsupported for the NT versions of Windows since at least Windows NT 4.0, and soon causes the bug check UNSUPPORTED_PROCESSOR (0x5D). Before then, the kernel works its way through more tests for defects. For any 80386 processor that passes all tests, the model and stepping leap ahead to 3 and 1.

Family Model Stepping Test
3 0 0 32-bit MUL not reliably correct
3 1 0 supports XBTS instruction
3 1 1 set TF bit (0x0100) in EFLAGS causes Debug exception (interrupt 0x01) only at completion of REP MOVSB
3 3 1  

The particular multiplication that distinguishes model 0 is of 0x81 by 0x0417A000. This same test was used by Microsoft at least as far back as Windows 3.10 Enhanced Mode, to advise

The Intel 80386 processor in this computer does not reliably execute 32-bit
multiply operations. Windows usually works correctly on computers with this
problem but may occasionally fail. You may want to replace your 80386 processor.
Press any key to continue...

The instruction whose support is tested for model 1 stepping 0 has opcode bytes 0x0F 0xA6 followed by a Mod R/M byte and by whatever more this byte indicates is needed for the operand. This opcode is disassembled as XBTS by Microsoft’s DUMPBIN utility from Visual C++, and has been since at least the mid-90s. However, the same opcode was apparently reused for the CMPXCHG instruction on some 80486 processors. The confusion seems to have left a lasting mark: Intel’s opcode charts leave 0x0F 0xA6 unassigned even now. The specific test performed by the Windows kernel is to load EAX and EDX with zero and ECX with 0xFF00. If executing XBTS ECX,EDX does not cause an Invalid Opcode exception and clears ecx to zero (which CMPXCHG ECX,EDX would not), then XBTS is deemed to be supported and the processor is model 1 stepping 0. This case model of 80386 processor also was known to Windows 3.10 Enhanced Mode, and was rejected as fatal:

Windows may not run correctly with the 80386 processor in this computer.
 
Upgrade your 80386 processor or start Windows in standard mode by typing
WIN /s at the MS-DOS prompt.

When string instructions such as MOVSB are repeated because of a REP prefix, each operation is ordinarily interruptible. As Intel says (for REP in the Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 2B: Instruction Set Reference N-Z), this “allows long string operations to proceed without affecting the interrupt response time of the system.” It ordinarily applies also to the Debug exception, such as raised by the processor at the end of executing an instruction for which the TF bit is set in the EFLAGS when the instruction started. Programmers may have noticed this in the real world of assembly-language debugging. If the debugger actually does implement its trace command as a trace, as opposed to setting an INT 3 breakpoint where the instruction is calculated to end, then a two-byte REP MOVSB may take many keystrokes to trace through! Apparently, this is not a problem for model 1 stepping 1, but it is surely a defect.

Accessibility of Results

The primary place at which the kernel stores the results of this identification is in the formally opaque KPRCB structure, reachable from (and indeed, embedded in) the partially opaque KPCR structure. The fields of both structures are named by Microsoft in symbol files. The main ones that are relevant to CPU identification are:

Offset Name Size Description
0x18 CpuType byte family
0x19 CpuID byte 1 if CPUID instruction is supported;
else 0
0x1A CpuStepping byte stepping
0x1B CpuModel byte model
0x1BA8 CpuVendor byte numeric code for identified vendor
0x1BAC VendorString 13 bytes vendor string, null-terminated

Note that the CpuType member corresponds most closely with what the Intel literature describes as the family, not the type.

The CpuVendor member is 0 if no vendor string is known. The identified vendors run from 1 to 6 (in the same order as given near the beginning of this article). The value 7 indicates that a vendor string is known but is not identified.