|
There are several methods for identifying CPUs. For
this
documentation, I will concentrate on how to detect
different 32-bit
processors (as that is all that I am targetting for my
OS). This page
also includes some information on detecting 8 and 16-bit
processors,
although I don't believe it to be complete.
Early processor identification:
| CPU |
Method |
| 808x/186+ |
Shift register by 32. Clears register on 808x and
NEC V2/30.
This is because later CPUs mask shift/rotate value
with 01Fh. |
| 808x/NEC |
PUSHA;
NOP;
pusha is executed on V20/30, so we can check if SP
has
changed.
On 808x, pusha executes as a 2-byte nop, so SP is not
changed. |
| 808x/80C8x |
REP ES: MOVSB ; CX = 0FFFFh
Test within a loop.
If CX is non-zero at the end of a loop, then it is a
NMOS
chip.
If always zero, it is CMOS. |
| 18x/286 |
PUSH SP
On 286 and later, the original value of SP is stored.
On 18x and earlier, the new value is stored. |
| 8/16-bit |
Use self-modifying code (808x/8018x/Vx0)
The prefetch queue on 8-bit processors is 4 bytes
long.
The prefetch queue on 16-bit processors is 6 bytes
long.
For example, change a NOP to an INC. If executed as
INC, we we
have an 8-bit processor. |
| 286/3 86+ |
Test behaviour of flags[12-15].
| 808x and 8018x |
flags[12-15] are always set. |
| 286 |
flags[12-15] are always clear in
real-address mode. |
| 32-bit processors: real-mode |
bit 15 is always clear;
bits 12-14 have the last value loaded into
them. |
| 32-bit processors: protected
mode |
bit 15 is always clear;
bit 14 has the last value loaded into it;
and the IOPL bits depends on the (CPL).
The IOPL field can be changed only if the CPL
is 0. |
|
32-bit processor identification
| CPU |
Method |
| 486 |
Eflags[18] can be changed on 486 and later
processors. |
| 386DX |
To determine the stepping of 386DX:
Stepping B0 and earlier support IBTS/XBTS, later
don't.
Stepping B1, rep insb with CX=1 doesn't clear CX |
| NexGen Nx586 |
When we know it's a 386 (and not a 486), we can do
a div
test:
| xor ax,ax |
; clear ax |
| sahf |
; clear flags,
; bit 1 of flags is always set |
| mov ax,5 |
; move 5 into the dividend |
| xor dx,dx |
|
| mov bx,2 |
; move 2 into the divisor |
| div bl |
; perform div test |
| jz is_NexGen |
; flags not changed,
; it's a NexGen CPU |
ZF will never be set on a NexGen CPU, but will be set
on
others.
To detect CPUID on a NexGen processor, it has to be
done using
a #UD handler.
NexGen chips don't always have the ID Flag, and CPUID
is
handled by the BIOS. |
386SX/DX
(Also Cx486SLC/DLC) |
If CR0 bit 4 can be cleared, we have a 386, 386DX
or
Cx486DLC.
If it cannot be cleared, it is a 386SX, 486SLC or a
'real' 486.
Always restore CR0 (MSW) after this test. |
| i386 |
EX has 64M memory space
SX has 16M memory space
DX has 4G memory space |
| Am386SX/SXL/SXLV |
If you can execute SMM instructions, it's an SXLV.
|
| C&T 386's |
This involves a test for the 386 POPAD bug.
The 386 POPAD bug affects all 386DX and early 386SX
revisions.
I don't have any complete documentation for this,
only
what
Ralf Brown's Interrupt List says.
Psuedo-code:
Set EAX=12345678h ; value that won't roate
to same
value.
set i = 32
DO{
set EBX = EAX
clear EDX and EDI
push all and pop all (32-bit)
set ECX = [EDX + EDI]
IF(EAX <> EBX) exit loop.
rotate EAX left by 1
decrement i
} WHILE(i > 0) |
If i = 0, we have a C&T 386, otherwise it's an
AMD or
Intel.
|
| CPUID |
Eflags[21] can be changed on processors which
support CPUID. |
| Cyrix |
Finds Cyrix, TI, SGS, IBM processors.
First check that it is a 486+, then:
| Method 1: |
For pre-Pentium and non-SMI modes:
UMOV executed as double NOP on Cyrix
processors. |
| Method 2: |
Divide test:
Store 0 to flags low byte (bit 1 always set).
Divide 5 (in AX) by 2 (Cyrix show it in BL).
Read low byte of flags (LAHF).
If not equal to 2, it's not a Cyrix processor. |
If this test detects a Cyrix chip, CPUID must be
enabled before
use.
This is done by setting CPUIDEN (CCR4 bit 7).
See the section on Cyrix detection for more info on
this. |
| IBM |
386/486 SLC, 486BL3 (others??)
Test initially as 486 and Cyrix.
IBM 386 and some 486 use MSRs. |
| UMC |
I'm not sure what this does. I got it from RBIL.
Use this for UMC U486SX. For other UMC processors,
use
CPUID.
db 64h,0d6h
cmp eax,0ab6b1b07h
je u486SX
jne Other |
; looks like "SALC FS:",
but it's
not.
; OPCODES.LST with RBIL says "db
64h,0dbh"
; which is not SALC FS
; "umctest.c" from Herbert Oppmann confirms
; the values I have used.
|
|
| FPU |
Test for FPU:
Clear a 16-bit memory area [mem]
Initialise FPU (perform FNINIT)
Store FPU control word to [mem] (perform FNSTCW
[mem])
If [mem] is 037Fh, then we have an FPU present. |
| SMM |
Use UMOV to test for SMM enabled and SL enhanced
AMD 386/486s,
and IBM 486SLC2.
If no SMM, it will generate a #UD.
Cyrix executed this as a double nop.
Only use this test on 386/486, and make sure it's not
a UMC
processor first, as they will hang. |
|