Logged in as Guest   Fri, Mar. 26th, 4:18 AM.      
Visitor Map
Recent Entries:
My Dev Setup Lately
Three Ways To Randomize on the iPhone
How to Remove .svn Directories On a Mac
How To Detect The iPhone Simulator
iPhoneMom Likes Doodle Games!
Updates To the Doodle Games Line
Three Jacks Now Tweets
Second iPhone App Submitted For Approval!
Pinch Media Analytics for iPhone
New iPhone Game Coming Soon!

Archive:
January - 2010
November - 2009
October - 2009
September - 2009
August - 2009
July - 2009
June - 2009
April - 2009
March - 2009
January - 2009
May - 2008
April - 2008
March - 2008
October - 2007
August - 2007
July - 2007
June - 2007
May - 2007
April - 2007
December - 2006
November - 2006
September - 2006
August - 2006
July - 2006
March - 2006
February - 2006
January - 2006
December - 2005
November - 2005
October - 2005
September - 2005
August - 2005
July - 2005
June - 2005
May - 2005
April - 2005
February - 2005
January - 2005
December - 2004
November - 2004
October - 2004
September - 2004
August - 2004
July - 2004
June - 2004
May - 2004
April - 2004
March - 2004
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);
}