CPU Detection Code

Disclaimer:
This post comes from my old blog back in 2004. I’m reposting it here so that I don’t lose the content. The source was hand-written HTML so the formatting probably appears a bit off.

CPU Detection Code

I dug this code up from a project that I worked on a long time ago. Unfortunately,
it is woefully out of date, especially with any of the latest P4 processors.
Also unfortunately, I don’t have a large suite of machines on which to test this,
however, I have verified a large number of these, but not all.
Also missing from the list are any AMD processors since my old companies didn’t
explicitly support AMD. Oh, well. As always, this code is to be used at your own
expense, and I guess with this particular set of code, that means a little more.
Anyway, I hope someone finds this interesting, and if you have any questions,
feel free to ask.

-BossHogg



#include “windows.h”

bool QueryCPUID();

bool QueryMMX();

bool QueryHyperThreading();

void QueryVendorString(char* string);

bool QuerySerialNumber(char* string);

void GetCPUInfoString(char* string);

unsigned long QueryCacheSize();

unsigned long QueryCPUCount();

unsigned char QueryCPUModel();

unsigned char QueryCPUFamily();

unsigned char QueryCPUStepping();

unsigned char QueryCPUType();

bool Is8086()

{

int is8086=0;

__asm {

pushf

pop ax

mov cx, ax

and ax, 0fffh

push ax

popf

pushf

pop ax

and ax, 0f000h

cmp ax, 0f000h

mov is8086, 0

jne DONE_8086_CHECK

mov is8086, 1

DONE_8086_CHECK:

};

return !!is8086;

}

bool Is80286()

{

int is80286=0;

__asm {

smsw ax

and ax, 1

or cx, 0f000h

push cx

popf

pushf

pop ax

and ax, 0f000h

mov is80286, 1

jz DONE_80286_CHECK

mov is80286, 0

DONE_80286_CHECK:

};

return !!is80286;

}

bool Is80386()

{

int is80386=0;

__asm {

pushfd

pop eax

mov ecx, eax

xor eax, 40000h

push eax

popfd

pushfd

pop eax

xor eax, ecx

mov is80386, 1

jz DONE_80386_CHECK

mov is80386, 0

DONE_80386_CHECK:

};

return !!is80386;

}

bool QueryCPUID()

{

int hasCPUID=0;

__asm

{

pushfd

pop eax

mov ecx, eax

and ecx, 0x00200000

xor eax, 0x00200000

push eax

popfd

pushfd

pop eax

and eax, 0x00200000

xor eax, ecx

mov hasCPUID, eax

};

return !!hasCPUID;

}

bool QueryMMX()

{

bool canDoMMX=false;

__asm

{

mov eax, 1 ; request for feature flags

_emit 0x0F ; CPUID on Pentiums is 0f,a2

_emit 0xA2

test edx, 0x00800000 ; is MMX technology Bit(bit 23)in feature

jz DONE_MMX_CHECK ; flags equal to 1

mov canDoMMX,1

DONE_MMX_CHECK:

};

return canDoMMX;

}

bool QueryHyperThreading()

{

unsigned int regEdx = 0;

unsigned int regEax = 0;

unsigned int vendorId[3] = {0, 0, 0};

if (!QueryCPUID())

return false;

__asm

{

xor eax, eax // call cpuid with eax = 0

cpuid // Get vendor id string

mov vendorId, ebx

mov vendorId + 4, edx

mov vendorId + 8, ecx

mov eax, 1 // call cpuid with eax = 1

cpuid

mov regEax, eax // eax contains family processor type

mov regEdx, edx // edx has info about the availability of hyper-Threading

}

if (((regEax & 0x0F00) == 0x0F00) || (regEax & 0x0F00000))

{

if (vendorId[0] == ‘uneG’ && vendorId[1] == ‘Ieni’ && vendorId[2] == ‘letn’)

{

return !!(regEdx & 0x10000000);

}

}

return false;

}

void QueryVendorString(char* string)

{

char vendorId[12];

__asm{

mov eax, 0 ; request for feature flags

_emit 0x0F ; CPUID on Pentiums is 0f,a2

_emit 0xA2

mov dword ptr vendorId, ebx

mov dword ptr vendorId[+4], edx

mov dword ptr vendorId[+8], ecx

};

memcpy(string,vendorId,12);

string[12]=0;

}

unsigned char QueryCPUStepping()

{

unsigned char _stepping;

__asm{

mov eax, 1 ; request for feature flags

_emit 0x0F ; CPUID on Pentiums is 0f,a2

_emit 0xA2

and eax, 0x0F

mov _stepping, al

};

return _stepping;

}

unsigned char QueryCPUModel()

{

unsigned char _model;

__asm{

mov eax, 1 ; request for feature flags

_emit 0x0F ; CPUID on Pentiums is 0f,a2

_emit 0xA2

shr eax, 4

and eax, 0x0F

mov _model, al

};

return _model;

}

unsigned char QueryCPUFamily()

{

unsigned char _family;

__asm{

mov eax, 1 ; request for feature flags

_emit 0x0F ; CPUID on Pentiums is 0f,a2

_emit 0xA2

shr eax, 8

and eax, 0x0F

mov _family, al

};

return _family;

}

unsigned char QueryCPUType()

{

char _type;

__asm{

mov eax, 1 ; request for feature flags

_emit 0x0F ; CPUID on Pentiums is 0f,a2

_emit 0xA2

shr eax, 12

and eax, 0x03

mov _type, al

};

return _type;

}

unsigned long QueryCPUCount()

{

SYSTEM_INFO info;

GetSystemInfo(&info;);

return info.dwNumberOfProcessors;

}

bool LookUpL2CacheSize(int infoFlag, unsigned long& cacheSize)

{

int cacheFlag = infoFlag;

cacheFlag &= 0xFF;

while (infoFlag > 0)

{

switch (cacheFlag)

{

case 0x80:

case 0x40:

cacheSize = 0;

return true;

case 0x81:

case 0x41:

cacheSize = 128;

return true;

case 0x82:

case 0x42:

cacheSize = 256;

return true;

case 0x83:

case 0x43:

cacheSize = 512;

return true;

case 0x84:

case 0x44:

cacheSize = 1024;

return true;

case 0x85:

case 0x45:

cacheSize = 2048;

return true;

}

infoFlag = infoFlag >> 8;

cacheFlag = infoFlag & 0xFF;

}

return false;

}

unsigned long QueryCacheSize()

{

char cacheRepeatCount=0;

int eaxCacheDescriptor=0;

int ebxCacheDescriptor=0;

int ecxCacheDescriptor=0;

int edxCacheDescriptor=0;

unsigned long cacheSize=0;

__asm{

//Let’s find out the amount of the cache.

//That will help us later on figure out which processor we are running…

mov eax, 2

_emit 0x0f

_emit 0xa2

mov cacheRepeatCount, al

cmp al, 1

je DONE_CACHE_CHECK

REPEAT_CACHE_DETECT:

mov eax, 2

_emit 0x0f

_emit 0xa2

dec cacheRepeatCount

jnz REPEAT_CACHE_DETECT

DONE_CACHE_CHECK:

mov eaxCacheDescriptor, eax

mov ebxCacheDescriptor, ebx

mov ecxCacheDescriptor, ecx

mov edxCacheDescriptor, edx

};

if (LookUpL2CacheSize(eaxCacheDescriptor,cacheSize))

return cacheSize;

if (LookUpL2CacheSize(ebxCacheDescriptor,cacheSize))

return cacheSize;

if (LookUpL2CacheSize(ecxCacheDescriptor,cacheSize))

return cacheSize;

if (LookUpL2CacheSize(edxCacheDescriptor,cacheSize))

return cacheSize;

return 0;

}

bool QuerySerialNumber(char* string)

{

char serialString[32];

bool isValid=false;

unsigned long one=0;

unsigned long two=0;

unsigned long three=0;

if (QueryCPUID())

{

__asm {

mov eax, 0

_emit 0x0f

_emit 0xa2

cmp eax, 3

jl DONE

mov eax, 1

_emit 0x0f

_emit 0xa2

and edx, 0x20000

jz DONE

mov one, eax

mov eax, 3

_emit 0x0f

_emit 0xa2

mov two, edx

mov three, ecx

mov isValid, 1

DONE:

};

}

if (isValid)

{

wsprintf(serialString,”%04x-%04x-%04x-%04x-%04x-%04x”,

one >> 16, one & 0x0000FFFF,

two >> 16, two & 0x0000FFFF,

three >> 16, three & 0x0000FFFF);

}

else

strcpy(serialString,”###DISABLED OR NOT PRESENT###”);

strcpy(string,serialString);

return isValid;

}

//If type==0x10, then it’s a dual processor system…

//Also, if it’s a P2, you need to check the L2 cache size to see if

//it’s a celeron or a real P2. If it’s zero, it’s a Celery.

const int cCPULookupTableSize=28;

#define MakeFingerprint(a,b,c)           ((((unsigned long)a) << 24) | \

(((unsigned long)b) << 16) | (((unsigned long)c) << 8) | ((unsigned long)0))

struct CPUFingerprint

{

//Fingerprint is (family | model | type )

unsigned long fingerprint;

char vendorID[16];

char description[64];

};

CPUFingerprint cpuLookupTable[cCPULookupTableSize]=

{

//The first four entries in the table are reserved for special processors.

{ MakeFingerprint(0x00, 0x00, 0x00), “Unknown vendor”, “Unknown processor”},

{ MakeFingerprint(0x00, 0x00, 0x00), “Unknown vendor”, “Intel8086”},

{ MakeFingerprint(0x00, 0x00, 0x00), “Unknown vendor”, “Intel80286”},

{ MakeFingerprint(0x00, 0x00, 0x00), “Unknown vendor”, “Intel80386”},

//These are the ones that support CPUID, so we start the “real”

//lookup here. Currently, this is offset number 4 in the array.

{ MakeFingerprint(0x04, 0x00, 0x00), “Unknown vendor”, “Intel486 DX”},

{ MakeFingerprint(0x04, 0x01, 0x00), “Unknown vendor”, “Intel486 DX”},

{ MakeFingerprint(0x04, 0x02, 0x00), “Unknown vendor”, “Intel486 SX”},

{ MakeFingerprint(0x04, 0x03, 0x00), “Unknown vendor”, “Intel487 or DX2”},

{ MakeFingerprint(0x04, 0x04, 0x00), “Unknown vendor”, “Intel486 SL”},

{ MakeFingerprint(0x04, 0x05, 0x00), “Unknown vendor”, “IntelSX2”},

{ MakeFingerprint(0x04, 0x07, 0x00), “Unknown vendor”, “Write-Back Enhanced IntelDX2”},

{ MakeFingerprint(0x04, 0x08, 0x00), “Unknown vendor”, “IntelDX4”},

{ MakeFingerprint(0x04, 0x08, 0x00), “Unknown vendor”, “IntelDX4 OverDrive”},

{ MakeFingerprint(0x05, 0x01, 0x00), “Unknown vendor”, “Pentium (60,66)”},

{ MakeFingerprint(0x05, 0x02, 0x00), “Unknown vendor”, “Pentium (75 – 200)”},

{ MakeFingerprint(0x05, 0x01, 0x00), “Unknown vendor”, “Pentium Overdrive (60,66)”},

{ MakeFingerprint(0x05, 0x02, 0x00), “Unknown vendor”, “Pentium Overdrive (75 – 133)”},

{ MakeFingerprint(0x05, 0x03, 0x00), “Unknown vendor”, “Pentium Overdrive for Intel486”},

{ MakeFingerprint(0x05, 0x01, 0x00), “Unknown vendor”, “Pentium Overdrive (60,66)”},

{ MakeFingerprint(0x05, 0x04, 0x00), “Unknown vendor”, “Pentium with MMX (166,200)”},

{ MakeFingerprint(0x05, 0x04, 0x00), “Unknown vendor”, “Pentium MMX Overdrive (75 – 133)”},

{ MakeFingerprint(0x06, 0x01, 0x00), “Unknown vendor”, “PentiumPro”},

{ MakeFingerprint(0x06, 0x03, 0x00), “Unknown vendor”, “PentiumII model 3”},

{ MakeFingerprint(0x06, 0x05, 0x00), “Unknown vendor”, “PentiumII model 5 or Celeron”},

{ MakeFingerprint(0x06, 0x08, 0x00), “Unknown vendor”, “PentiumII or Celeron”},

{ MakeFingerprint(0x0F, 0x00, 0x08), “Unknown vendor”, “Pentium 4” },

{ MakeFingerprint(0x0F, 0x01, 0x08), “Unknown vendor”, “Pentium 4” },

{ MakeFingerprint(0x0F, 0x02, 0x09), “Unknown vendor”, “Pentium 4” }

};

void GetCPUInfoString(char* string)

{

long tableEntry=0;

if (Is8086())

tableEntry=1;

else if (Is80286())

tableEntry=2;

else if (Is80386())

tableEntry=3;

else if (QueryCPUID())

{

unsigned char family=QueryCPUFamily();

unsigned char model=QueryCPUModel();

unsigned char type=QueryCPUType();

//unsigned char stepping=QueryCPUStepping();

unsigned long fingerprint = MakeFingerprint(family, model, type);

//Start the lookup at four to skip the reserved entries…

for (int x=4; x < cCPULookupTableSize; x++)

{

if (fingerprint == cpuLookupTable[x].fingerprint)

tableEntry=x;

}

//Fill in the vendor string…

QueryVendorString(cpuLookupTable[tableEntry].vendorID);

}

unsigned long cacheSize = QueryCacheSize();

bool hasMMX = QueryMMX();

unsigned long cpuCount=QueryCPUCount();

char serialId[64];

QuerySerialNumber(serialId);

bool hyperThreading = QueryHyperThreading();

wsprintf(string,”———————————————————\n”

“Primary cpu = %s\n”

“CPUs present: %d\n”

“Vendor string: %s\n”

“L2 cache size: %d\n”

“MMX capable: %d\n”

“Serial ID: %s\n”

“HyperThread: %d\n”

“———————————————————\n”,

cpuLookupTable[tableEntry].description,

cpuCount,

cpuLookupTable[tableEntry].vendorID,

cacheSize,

hasMMX,

serialId,

hyperThreading);

}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s