mirror of
https://github.com/OpenTrespasser/JurassicParkTrespasser.git
synced 2024-12-19 23:21:56 +00:00
1466 lines
37 KiB
C++
1466 lines
37 KiB
C++
/***********************************************************************************************
|
|
*
|
|
* Copyright © DreamWorks Interactive. 1997
|
|
*
|
|
* Contents:
|
|
* Processor detect DLL
|
|
*
|
|
* Bugs:
|
|
*
|
|
* To do:
|
|
*
|
|
* Notes:
|
|
*
|
|
***********************************************************************************************
|
|
*
|
|
* $Log:: /JP2_PC/Source/Tools/Processor Detect/Detect.cpp $
|
|
*
|
|
* 3 9/23/98 12:11p Rwyatt
|
|
*
|
|
* 2 9/23/98 12:11p Rwyatt
|
|
* Added support for K6-3and K7. Detection code is now future proof with respect to new models.
|
|
*
|
|
* 1 9/01/98 12:31a Rwyatt
|
|
* Added support for IDT WinChip and 3d now instructions are identified by feature and not
|
|
* maker.
|
|
*
|
|
* 3 10/24/97 1:51a Rwyatt
|
|
* Changed the 3DX/Cedar ID string to make it different from the standard K6.
|
|
*
|
|
* 2 10/24/97 1:17a Rwyatt
|
|
* Now detects K6 3DX/Cedar extentions
|
|
*
|
|
* 1 10/24/97 1:16a Rwyatt
|
|
* Initial implementation
|
|
*
|
|
***********************************************************************************************/
|
|
|
|
#include "Windows.h"
|
|
|
|
#ifdef _BUILD_EXTERNAL_
|
|
#include "..\DWITypes.h"
|
|
#include "..\Processor.hpp"
|
|
#else
|
|
#include "Lib/Std/UTypes.hpp"
|
|
#include "Lib/Sys/Processor.hpp"
|
|
#endif
|
|
|
|
|
|
//*********************************************************************************************
|
|
// This ststic is filled and then copied onto the one passed in, this is so we get another
|
|
// free register within the code.
|
|
//
|
|
static CPUInfo cpu;
|
|
static char strIntel[] = "GenuineIntel";
|
|
static char strAMD[] = "AuthenticAMD";
|
|
static char strCyrix[] = "CyrixInstead";
|
|
static char strIDT[] = "CentaurHauls";
|
|
|
|
static void SetGenericFlags(void);
|
|
static void DetectProcessor(void);
|
|
static void DetectFPU(void);
|
|
static uint32 u4CPUSpeed(int clocks);
|
|
static void MakeName(void);
|
|
static uint32 u4QueryCPUIDName(void);
|
|
|
|
|
|
//*********************************************************************************************
|
|
// Start of detection code
|
|
//*********************************************************************************************
|
|
|
|
//*********************************************************************************************
|
|
//
|
|
bool WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*********************************************************************************************
|
|
// Declare the function below as extern "C" so it does not get its name mangled. This is the
|
|
// function that will be used in the call to GetProcAddress.
|
|
//
|
|
extern "C"
|
|
{
|
|
__declspec(dllexport) bool _cdecl bGetProcessorInfo(CPUInfo* pcpuProcessorInfo);
|
|
}
|
|
|
|
|
|
//*********************************************************************************************
|
|
//
|
|
__declspec(dllexport) bool _cdecl bGetProcessorInfo(CPUInfo* pcpuProcessorInfo)
|
|
{
|
|
// clear the destination structure.
|
|
memset(&cpu,0,sizeof(CPUInfo));
|
|
|
|
// we don't know anything about the chip
|
|
cpu.cpufamProcessorFamily = cpufamUNKNOWN;
|
|
cpu.cpufamFPUFamily = cpufamUNKNOWN;
|
|
cpu.cpumanProcessorManufacture = cpumanUNKNOWN;
|
|
|
|
DetectProcessor();
|
|
|
|
if (cpu.cpufamProcessorFamily == cpufamUNKNOWN)
|
|
return false;
|
|
|
|
// we need to do some adjusting for the non-Intel processors.
|
|
|
|
if (cpu.cpumanProcessorManufacture == cpumanAMD)
|
|
{
|
|
if (cpu.cpufamProcessorFamily == 4)
|
|
{
|
|
// a model 4 AMD is a AM486
|
|
cpu.cpufamProcessorFamily = cpufamAM486;
|
|
}
|
|
else if (cpu.cpufamProcessorFamily == 5)
|
|
{
|
|
// a model 5 AMD is either a K5 or K6, we need to check the stepping
|
|
switch ((cpu.u4Model & (0x0f<<4))>>4)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
cpu.cpufamProcessorFamily = cpufamK5;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
cpu.cpufamProcessorFamily = cpufamUNKNOWN;
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
cpu.cpufamProcessorFamily = cpufamK6;
|
|
break;
|
|
case 8:
|
|
cpu.cpufamProcessorFamily = cpufamK62;
|
|
break;
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
cpu.cpufamProcessorFamily = cpufamK63;
|
|
break;
|
|
}
|
|
}
|
|
else if (cpu.cpufamProcessorFamily >= 6)
|
|
{
|
|
// Family model 6 on AMD are at least a K7
|
|
cpu.cpufamProcessorFamily = cpufamK7;
|
|
}
|
|
}
|
|
|
|
|
|
if (cpu.cpumanProcessorManufacture == cpumanCYRIX)
|
|
{
|
|
if (cpu.cpufamProcessorFamily == 5)
|
|
{
|
|
// model 5 Cyrix is the 686
|
|
cpu.cpufamProcessorFamily = cpufam686;
|
|
}
|
|
else if (cpu.cpufamProcessorFamily == 6)
|
|
{
|
|
// model 6 Cyrix is the M2
|
|
cpu.cpufamProcessorFamily = cpufamM2;
|
|
}
|
|
else if (cpu.cpufamProcessorFamily > 6)
|
|
{
|
|
// Future family is at least an M2
|
|
cpu.cpufamProcessorFamily = cpufamM2;
|
|
}
|
|
else
|
|
{
|
|
// If it is cyrix of model 4 or less the we do not know what
|
|
// it is.
|
|
cpu.cpufamProcessorFamily = cpufamUNKNOWN;
|
|
}
|
|
}
|
|
|
|
|
|
if (cpu.cpumanProcessorManufacture == cpumanIDT)
|
|
{
|
|
if (cpu.cpufamProcessorFamily == 5)
|
|
{
|
|
// a pentium class IDT chip is either a C6 or a WinChip
|
|
if ( (cpu.u4Model & (0x0f<<4))>>4 >= 8 )
|
|
{
|
|
cpu.cpufamProcessorFamily = cpufamWINCHIP2;
|
|
}
|
|
else if ( (cpu.u4Model & (0x0f<<4))>>4 == 4 )
|
|
{
|
|
cpu.cpufamProcessorFamily = cpufamWINCHIPC6;
|
|
}
|
|
else
|
|
{
|
|
cpu.cpufamProcessorFamily = cpufamUNKNOWN;
|
|
}
|
|
}
|
|
else if (cpu.cpufamProcessorFamily > 5)
|
|
{
|
|
// Future winchips muct be compatible with the WinChip2 so return it
|
|
cpu.cpufamProcessorFamily = cpufamWINCHIP2;
|
|
}
|
|
else
|
|
{
|
|
// IDT will never make a processor that has a family type less than 5.
|
|
// If they do then we have no idea what it is or what it is compatible
|
|
// with.
|
|
cpu.cpufamProcessorFamily = cpufamUNKNOWN;
|
|
}
|
|
|
|
}
|
|
|
|
// now we have identified the processor lets go and look for an FPU
|
|
// if CPUID is supported then this is simple we just chekc the bit and
|
|
// we can assume the FPU version is the same as the processor. The only
|
|
// device that varies is the 80386 which can use the FPU of the 80286.
|
|
|
|
if (cpu.u4CPUFlags & CPU_CPUID)
|
|
{
|
|
// if CPUID says that there is a FPU then it must be the same family
|
|
// as the processor
|
|
if (cpu.u4Feature & 1)
|
|
{
|
|
cpu.u4CPUFlags |= CPU_FPUPRESENT;
|
|
cpu.cpufamFPUFamily = cpu.cpufamProcessorFamily;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this will detect a FPU on other processors without the CPUID instrucion
|
|
// The 386 is a special case because it can have a 287 attached to it,
|
|
// the DetectFPU function handles this and sets the result so only copy
|
|
// the family type into the FPU type if we are not a 386.
|
|
|
|
// this will also set the bit for an FPU present
|
|
DetectFPU();
|
|
|
|
if (cpu.u4CPUFlags & CPU_FPUPRESENT)
|
|
{
|
|
// if an FPU is present then set the FPU family
|
|
if (cpu.cpufamProcessorFamily != 3)
|
|
{
|
|
cpu.cpufamFPUFamily = cpu.cpufamProcessorFamily;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Now lets derive the cache information in this machine
|
|
if (cpu.cpumanProcessorManufacture == cpumanINTEL)
|
|
{
|
|
// with an intel processor we much check if we can call CPUID with an input of 2
|
|
if (cpu.u4MaxCPUID>=2)
|
|
{
|
|
char cache[16];
|
|
int i;
|
|
|
|
// now call CPUID with an input of 2 to get the descriptors
|
|
cpu.u4CPUFlags |= CPU_CACHEINFO;
|
|
|
|
_asm
|
|
{
|
|
mov eax,2
|
|
cpuid
|
|
|
|
mov cl,al
|
|
dec cl
|
|
je short GOT_INTEL_CACHE
|
|
// ECX is the number of times we need to call CPUID
|
|
NEXT_ID:
|
|
mov eax,2
|
|
cpuid
|
|
|
|
dec cl
|
|
jnz short NEXT_ID
|
|
|
|
GOT_INTEL_CACHE:
|
|
// the registers are now set with the results of the CPUID[2]
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+0], eax
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+4], ebx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+8], ecx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+12], edx
|
|
mov al,0
|
|
mov DWORD PTR [cache+0], eax
|
|
mov DWORD PTR [cache+4], ebx
|
|
mov DWORD PTR [cache+8], ecx
|
|
mov DWORD PTR [cache+12], edx
|
|
}
|
|
|
|
for (i=0; i<16 ; i++)
|
|
{
|
|
// if the top bit of the cahce descriptors is clear then it is valid
|
|
if ((cache[i] & 0x80) == 0)
|
|
{
|
|
switch (cache[i])
|
|
{
|
|
case 0x06:
|
|
cpu.u4CodeCacheSize = 8;
|
|
cpu.u4CodeCacheLineSize = 32;
|
|
cpu.u4CodeCacheAssoc = 4;
|
|
break;
|
|
|
|
case 0x08:
|
|
cpu.u4CodeCacheSize = 16;
|
|
cpu.u4CodeCacheLineSize = 32;
|
|
cpu.u4CodeCacheAssoc = 4;
|
|
break;
|
|
|
|
case 0x0A:
|
|
cpu.u4DataCacheSize = 8;
|
|
cpu.u4DataCacheLineSize = 32;
|
|
cpu.u4DataCacheAssoc = 2;
|
|
break;
|
|
|
|
case 0x0C:
|
|
cpu.u4DataCacheSize = 16;
|
|
cpu.u4DataCacheLineSize = 32;
|
|
cpu.u4DataCacheAssoc = 2;
|
|
break;
|
|
|
|
case 0x40:
|
|
cpu.u4L2CacheSize = 0;
|
|
cpu.u4L2CacheLineSize = 0;
|
|
cpu.u4L2CacheAssoc = 0;
|
|
break;
|
|
|
|
case 0x41:
|
|
cpu.u4L2CacheSize = 128;
|
|
cpu.u4L2CacheLineSize = 32;
|
|
cpu.u4L2CacheAssoc = 4;
|
|
break;
|
|
|
|
case 0x42:
|
|
cpu.u4L2CacheSize = 256;
|
|
cpu.u4L2CacheLineSize = 32;
|
|
cpu.u4L2CacheAssoc = 4;
|
|
break;
|
|
|
|
case 0x43:
|
|
cpu.u4L2CacheSize = 512;
|
|
cpu.u4L2CacheLineSize = 32;
|
|
cpu.u4L2CacheAssoc = 4;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((cpu.cpumanProcessorManufacture == cpumanAMD) || (cpu.cpumanProcessorManufacture == cpumanIDT))
|
|
{
|
|
uint32 u4_level2 = 0;
|
|
|
|
// AMD and IDT are different to obtain the cache information, both of these manufactures use
|
|
// CPUID operation 0x80000005
|
|
_asm
|
|
{
|
|
mov eax,0x80000000 // extended AMD CPUID function
|
|
cpuid
|
|
|
|
cmp eax,0x80000005
|
|
jb short EXIT_AMD_CACHE // functions upto 0x80000005 must be present
|
|
|
|
mov eax,0x80000005 // extended AMD CPUID function
|
|
cpuid
|
|
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+56], eax
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+60], ebx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+64], ecx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+68], edx
|
|
|
|
or DWORD PTR [cpu.u4CPUFlags],CPU_CACHEINFO
|
|
|
|
mov eax,0x80000000 // extended AMD CPUID function
|
|
cpuid
|
|
|
|
cmp eax,0x80000006
|
|
jb short EXIT_AMD_CACHE // functions upto 0x80000006 must be present
|
|
|
|
mov eax,0x80000006 // extended AMD CPUID function for level 2 cache info
|
|
cpuid
|
|
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+72], eax
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+76], ebx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+80], ecx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+84], edx
|
|
|
|
// set the local flag saying we got level 2 cache info
|
|
mov DWORD PTR [u4_level2],0xffffffff
|
|
EXIT_AMD_CACHE:
|
|
}
|
|
|
|
if (u4_level2!=0)
|
|
{
|
|
// this device can get the size of the L2 cache
|
|
cpu.u4L2CacheSize = (cpu.au4ProcessorSpecific[20] & 0xffff0000)>>16;
|
|
cpu.u4L2CacheAssoc = (cpu.au4ProcessorSpecific[20] & 0x0000f000)>>12;
|
|
cpu.u4L2CacheLineSize = (cpu.au4ProcessorSpecific[20] & 0xf);
|
|
}
|
|
else
|
|
{
|
|
// this device cannot get the size of the L2 cache because it does
|
|
// not support CPUID 0x80000006
|
|
cpu.u4L2CacheSize = 0xffffffff;
|
|
}
|
|
|
|
cpu.u4DataCacheSize = (cpu.au4ProcessorSpecific[16] & 0xff000000)>>24;
|
|
cpu.u4DataCacheAssoc = (cpu.au4ProcessorSpecific[16] & 0x00ff0000)>>16;
|
|
cpu.u4DataCacheLineSize = (cpu.au4ProcessorSpecific[16] & 0xff);
|
|
|
|
cpu.u4CodeCacheSize = (cpu.au4ProcessorSpecific[17] & 0xff000000)>>24;
|
|
cpu.u4CodeCacheAssoc = (cpu.au4ProcessorSpecific[17] & 0x00ff0000)>>16;
|
|
cpu.u4CodeCacheLineSize = (cpu.au4ProcessorSpecific[17] & 0xff);
|
|
}
|
|
else
|
|
{
|
|
// unknown processor, cannot get cache info
|
|
cpu.u4CPUFlags &= ~CPU_CACHEINFO;
|
|
}
|
|
|
|
// measure the speed of this processor
|
|
cpu.u4CPUSpeed = u4CPUSpeed(0);
|
|
|
|
// finish off by doing general feature determination
|
|
switch(cpu.cpumanProcessorManufacture)
|
|
{
|
|
case cpumanINTEL:
|
|
SetGenericFlags();
|
|
|
|
// Some Pentium Pro's incorrectly set bit 11 in the feature flags when they could not do the
|
|
// fast system call operation. This code will sort it out.
|
|
if (cpu.u4Feature & (1<<11))
|
|
{
|
|
if ( (cpu.cpufamProcessorFamily == 6) && ( ((cpu.u4Model & (0x0f<<4))>>4) < 3) && ((cpu.u4Model & 0x04) < 3) )
|
|
{
|
|
cpu.u4CPUFlags &= ~CPU_SEP;
|
|
}
|
|
else
|
|
{
|
|
cpu.u4CPUFlags |= CPU_SEP;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case cpumanAMD:
|
|
_asm
|
|
{
|
|
mov eax,0x80000000 // extended CPUID function
|
|
cpuid
|
|
mov [cpu.au4ProcessorSpecific+0], eax
|
|
|
|
cmp eax,0x80000001
|
|
jb short EXIT_AMD_EXT // functions upto 0x80000001 must be present
|
|
|
|
mov eax,0x80000001 // extended AMD CPUID function
|
|
cpuid
|
|
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+4], edx
|
|
}
|
|
|
|
// SEP
|
|
cpu.u4CPUFlags &= ~CPU_SEP;
|
|
if (cpu.au4ProcessorSpecific[1] & (1<<11) )
|
|
{
|
|
cpu.u4CPUFlags |= CPU_SEP;
|
|
}
|
|
|
|
// PAT
|
|
cpu.u4CPUFlags &= ~CPU_PAT;
|
|
if (cpu.au4ProcessorSpecific[1] & (1<<16) )
|
|
{
|
|
cpu.u4CPUFlags |= CPU_PAT;
|
|
}
|
|
|
|
// 3DX/CEDAR extentions..
|
|
if (cpu.au4ProcessorSpecific[1] & (1<<31) )
|
|
{
|
|
cpu.u4CPUFlags |= CPU_3DNOW;
|
|
}
|
|
|
|
EXIT_AMD_EXT:
|
|
SetGenericFlags();
|
|
|
|
if ((cpu.cpufamProcessorFamily >= cpufamK5) && (cpu.cpufamProcessorFamily < cpufamK7))
|
|
{
|
|
//These flags are reserved on K5 and all K6 processors so the feature cannot be
|
|
//present
|
|
cpu.u4CPUFlags &= ~(CPU_PAE|CPU_MCA);
|
|
}
|
|
|
|
if (cpu.cpufamProcessorFamily == cpufamK5)
|
|
{
|
|
// On the K5 model 0, bit 13 (global paging extentions) is reserved and bit 9
|
|
// is used to indicate global page extentions, which is usually used for APIC
|
|
// support.
|
|
|
|
// K5 Cannotsupport an APIC
|
|
cpu.u4CPUFlags &= ~CPU_APIC;
|
|
cpu.u4CPUFlags &= ~CPU_GPE;
|
|
|
|
if (cpu.u4Feature & (1<<9))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_GPE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
//
|
|
// This is either an IDT WinChip, a cyrix or a completely unknown processor
|
|
//
|
|
|
|
if (cpu.u4CPUFlags & CPU_CPUID)
|
|
{
|
|
//
|
|
// We have a CPUID instruction, lets check some extened features that
|
|
// this clone may support.
|
|
//
|
|
_asm
|
|
{
|
|
mov eax,0x80000000 // extended CPUID function
|
|
cpuid
|
|
|
|
mov [cpu.au4ProcessorSpecific+0], eax
|
|
cmp eax,0x80000001
|
|
jb short NO_EXT // functions upto 0x80000001 must be present
|
|
|
|
|
|
mov edx,0
|
|
mov eax,0x80000001 // extended CPUID function
|
|
cpuid
|
|
|
|
cmp eax,0
|
|
je short NO_EXT // the feature word cannot be zero
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+4], edx
|
|
}
|
|
|
|
// 3DX/CEDAR extentions..
|
|
if (cpu.au4ProcessorSpecific[1] & (1<<31) )
|
|
{
|
|
cpu.u4CPUFlags |= CPU_3DNOW;
|
|
}
|
|
NO_EXT:;
|
|
}
|
|
|
|
//
|
|
// Parse the flags supported by the normal CPUID feature word
|
|
//
|
|
SetGenericFlags();
|
|
break;
|
|
}
|
|
|
|
// make a friendly string for this processor
|
|
MakeName();
|
|
|
|
// copy the final results into the structure passed in.
|
|
memcpy(pcpuProcessorInfo,&cpu,sizeof(CPUInfo));
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//*********************************************************************************************
|
|
//
|
|
static void SetGenericFlags(void)
|
|
{
|
|
//
|
|
// We have no idea who made this chip so lets just check for some general features,
|
|
// if the CPUID instruction is present.
|
|
//
|
|
if (cpu.u4CPUFlags & CPU_CPUID)
|
|
{
|
|
// check for VME
|
|
if (cpu.u4Feature & (1<<1))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_VME;
|
|
}
|
|
|
|
// check for extened DEBUG registers
|
|
if (cpu.u4Feature & (1<<2))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_DEBUG;
|
|
}
|
|
|
|
// check for PSE
|
|
if (cpu.u4Feature & (1<<3))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_PSE;
|
|
}
|
|
|
|
// check for RDTSC
|
|
if (cpu.u4Feature & (1<<4))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_RDTSC;
|
|
}
|
|
|
|
// check for MSR
|
|
if (cpu.u4Feature & (1<<5))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_MSR;
|
|
}
|
|
|
|
// check for PAE (physical address extentions)
|
|
if (cpu.u4Feature & (1<<6))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_PAE;
|
|
}
|
|
|
|
// Machine Check exception
|
|
if (cpu.u4Feature & (1<<7))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_MCE;
|
|
}
|
|
|
|
// check for the CMPXCHG8B instruction
|
|
if (cpu.u4Feature & (1<<8))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_CMPXCHG8B;
|
|
}
|
|
|
|
// check for an APIC
|
|
if (cpu.u4Feature & (1<<9))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_APIC;
|
|
}
|
|
|
|
// check for Fast system calls
|
|
if (cpu.u4Feature & (1<<11))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_SEP;
|
|
}
|
|
|
|
// check for memory type range registers
|
|
if (cpu.u4Feature & (1<<12))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_MTRR;
|
|
}
|
|
|
|
// check for Global paging extentions
|
|
if (cpu.u4Feature & (1<<13))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_GPE;
|
|
}
|
|
|
|
// check for Machine check architecture
|
|
if (cpu.u4Feature & (1<<14))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_MCA;
|
|
}
|
|
|
|
// check for CMOV instructions
|
|
if (cpu.u4Feature & (1<<15))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_CMOV;
|
|
}
|
|
|
|
// check for Page Attribute Table
|
|
if (cpu.u4Feature & (1<<16))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_PAT;
|
|
}
|
|
|
|
// check for MMX
|
|
if (cpu.u4Feature & (1<<23))
|
|
{
|
|
cpu.u4CPUFlags |= CPU_MMX;
|
|
}
|
|
}
|
|
|
|
if ( ((cpu.u4Model>>8) & 0xf) >= 5)
|
|
{
|
|
//Model is 5 or above so we say we can say we execute pentium code.
|
|
cpu.u4CPUFlags |= CPU_PENTIUM;
|
|
|
|
if (cpu.u4CPUFlags & CPU_CMOV)
|
|
{
|
|
// We have the Pentium pro conditional instructions so we say we
|
|
// can execute Pentium pro code.
|
|
cpu.u4CPUFlags |= CPU_PENTIUMPRO;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
//
|
|
static void DetectProcessor(void)
|
|
{
|
|
_asm
|
|
{
|
|
// CHECK 8086 : Bits 12-15 are always set on the 8086 processor
|
|
pushad
|
|
|
|
pushf // save EFLAGS
|
|
pop bx // store EFLAGS in BX
|
|
mov ax,0fffh // clear bits 12-15
|
|
and ax,bx // in EFLAGS
|
|
push ax // store new EFLAGS value on stack
|
|
popf // replace current EFLAGS value
|
|
pushf // set new eflags
|
|
pop ax // store new eflags in AX
|
|
and ax,0f000h // if bits 12-15 are set then its a 8086
|
|
cmp ax,0f000h // test if its an 8086
|
|
mov cpu.cpufamProcessorFamily,cpufam8086
|
|
je short END_CPUID // if CPU is 8086/8088 check for 8087 FPU
|
|
|
|
|
|
// Check for 80286
|
|
// Bits 12-15 are always clear on the 80286 processor
|
|
|
|
pushf // Keep a copy of the flags
|
|
pushf
|
|
pop cx
|
|
mov bx, cx
|
|
or cx, 0f000h // Try to set bits 12-15
|
|
push cx // Save new FLAGS value on stack
|
|
popf // Replace current FLAGS value
|
|
pushf // Get new FLAGS
|
|
pop ax // Store new FLAGS in AX
|
|
popf // restore original flags to prevent task switch
|
|
and ax, 0f000h // If bits 12-15 are clear
|
|
mov cpu.cpufamProcessorFamily,cpufam80286
|
|
je short END_CPUID
|
|
|
|
|
|
// Intel386 CPU check
|
|
// The AC bit, bit #18, is a new bit introduced in the EFLAGS
|
|
// register on the Intel386 DX CPU to generate alignment faults.
|
|
// This bit can not be set on the Intel386 CPU
|
|
|
|
pushfd
|
|
pop eax // get original EFLAGS
|
|
mov ecx,eax // save origninal EFLAGS
|
|
xor eax,40000h // flip AC bit in EFLAGS
|
|
push eax // save for EFLAGS
|
|
popfd // copy to EFLAGS
|
|
pushfd // push EFLAGS
|
|
pop eax // get new EFLAGS value
|
|
xor eax,ecx // cant toggle AC bit, CPU=Intel386
|
|
mov cpu.cpufamProcessorFamily,cpufam80386
|
|
je short END_CPUID
|
|
|
|
|
|
// Intel486 DX CPU, Intel487 SX MCP, and Intel486 SX CPU checking
|
|
// Checking for ability to set/clear ID flag (bit 21) in EFLAGS
|
|
// which differentiates between a Pentium CPU or other processor
|
|
// with the ability to use the CPUID instruction. If this bit
|
|
// cannot be set, CPU=Intel486.
|
|
|
|
pushfd // Get original EFLAGS
|
|
pop eax
|
|
mov ecx, eax
|
|
xor eax, 200000h // Flip ID bit in EFLAGS
|
|
push eax // Save new EFLAGS value on stack
|
|
popfd // Replace current EFLAGS value
|
|
pushfd // Get new EFLAGS
|
|
pop eax // Store new EFLAGS in EAX
|
|
xor eax, ecx // Can not toggle ID bit,
|
|
jz short END_CPUID // Processor=80486
|
|
|
|
|
|
// Otherwise, execute CPUID instruction
|
|
// AMD devices K5 and K6 will all get to this stage, earlier devices will not but will
|
|
// recognized as intel devices
|
|
|
|
or cpu.u4CPUFlags,CPU_CPUID // set the bit for CPUID instruction
|
|
xor eax,eax // set up for CPUID instruction
|
|
|
|
cpuid
|
|
|
|
mov cpu.u4MaxCPUID, eax // maximum input function for CPUID
|
|
|
|
mov DWORD PTR [cpu.strManufactureID],ebx
|
|
mov DWORD PTR [cpu.strManufactureID+4],edx
|
|
mov DWORD PTR [cpu.strManufactureID+8],ecx
|
|
|
|
mov esi,OFFSET [cpu.strManufactureID]
|
|
mov edi,OFFSET strIntel
|
|
mov ecx,12
|
|
|
|
// compare for intel
|
|
repe cmpsb
|
|
cmp ecx,0 // must be GenuineIntel if ecx = 0
|
|
jne short NOT_INTEL
|
|
|
|
mov cpu.cpumanProcessorManufacture, cpumanINTEL
|
|
jmp short CPU_FEATURE
|
|
|
|
NOT_INTEL:
|
|
mov esi,OFFSET [cpu.strManufactureID]
|
|
mov edi,OFFSET strAMD
|
|
mov ecx,12
|
|
// compare for amd
|
|
repe cmpsb
|
|
cmp ecx,0 // must be AuthenticAMD if ecx = 0
|
|
jne short NOT_AMD
|
|
|
|
mov cpu.cpumanProcessorManufacture, cpumanAMD
|
|
jmp short CPU_FEATURE
|
|
|
|
NOT_AMD:
|
|
mov esi,OFFSET [cpu.strManufactureID]
|
|
mov edi,OFFSET strCyrix
|
|
mov ecx,12
|
|
// compare for cyrix
|
|
repe cmpsb
|
|
cmp ecx,0 // must be cyrix if ecx = 0
|
|
jne short NOT_CYRIX
|
|
|
|
mov cpu.cpumanProcessorManufacture, cpumanCYRIX
|
|
NOT_CYRIX:
|
|
mov esi,OFFSET [cpu.strManufactureID]
|
|
mov edi,OFFSET strIDT
|
|
mov ecx,12
|
|
// compare for Win Chip
|
|
repe cmpsb
|
|
cmp ecx,0 // must be cyrix if ecx = 0
|
|
jne short NOT_IDT
|
|
|
|
mov cpu.cpumanProcessorManufacture, cpumanIDT
|
|
NOT_IDT:
|
|
|
|
CPU_FEATURE:
|
|
// feature determination
|
|
mov eax,1
|
|
cpuid
|
|
|
|
// store the results of the instruction
|
|
mov cpu.u4Model, eax
|
|
mov cpu.u4Feature, edx
|
|
|
|
// get the model number
|
|
mov ebx,eax
|
|
shr ebx,8
|
|
and ebx,0x0f
|
|
|
|
// not the processor just the instruction family, for Intel these are the same
|
|
// but for the other devices they are not and this needs to be adjusted.
|
|
mov cpu.cpufamProcessorFamily, ebx
|
|
|
|
END_CPUID:
|
|
popad
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
// Co-processor cheching begins here for the 8086,
|
|
// Intel 286, and Intel 386 CPUS, The algoritm is to
|
|
// detemine whether or not the floating-point status
|
|
// and control words can be written to.
|
|
// If they are not, no coprocessor exists. If the status
|
|
// and control words can be written to, the correct processor
|
|
// is then determined depending on the processor id. Coprocessor
|
|
// checks are first performed for an 8086, Intel 286 and an
|
|
// Intel486 DX CPU. If the coprocessor id is still undetermined, the
|
|
// system must contain an Intel386 CPU. The Intel386 CPU may work with
|
|
// either an Intel287 or an Intel387 math coprocessor. The infinity of the
|
|
// coprocessor must be checked to determine the correct coprocessor id.
|
|
//
|
|
static void DetectFPU(void)
|
|
{
|
|
WORD fp_status;
|
|
|
|
_asm
|
|
{
|
|
pushad // check for 8087, Intel287, or
|
|
// Intel387 math coprocessor
|
|
fninit // reset FP status word
|
|
mov [fp_status],5a5ah // initialise temp word to non-zero value
|
|
fnstsw [fp_status] // save FP status word
|
|
mov ax,[fp_status] // check FP status word
|
|
cmp al,0 // see if correct status with written
|
|
jne short END_CHECK_FPU
|
|
|
|
fnstcw [fp_status] // save FP control word
|
|
mov ax,[fp_status] // check FP control word
|
|
and ax,103fh // see if seleced parts look OK
|
|
cmp ax,3fh // check that 1s & 0s correctly read
|
|
jne END_CHECK_FPU
|
|
or cpu.u4CPUFlags, CPU_FPUPRESENT // set the bit for an FPU present
|
|
|
|
//
|
|
// Intel287 and Intel387 math coprocessor check for the Intel386 CPU
|
|
//
|
|
cmp cpu.cpufamProcessorFamily,3
|
|
jne short END_CHECK_FPU
|
|
fld1 // must use default control from FNINIT
|
|
fldz // form infinity
|
|
fdiv // 8087 and Intel287 MCP says +inf = -inf
|
|
fld st // form negative infinity
|
|
fchs // Intel387 MCP says +inf <>-inf
|
|
fcompp // see if they are the same and remove them
|
|
fstsw [fp_status] // look at the status from FCOMPP
|
|
mov ax,[fp_status]
|
|
mov cpu.cpufamFPUFamily,2 // store Intel287
|
|
sahf // see if infinities matched
|
|
jz short END_CHECK_FPU // jump if 8087 or Intel287 MCP is present
|
|
mov cpu.cpufamFPUFamily,3 // store Intel387 MCP for fpu IntelFPUType
|
|
|
|
END_CHECK_FPU:
|
|
popad
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
// cycles*10 to execute a BSF instruciton on each processor
|
|
//
|
|
static uint32 IntelProcessorCycles[] =
|
|
{
|
|
000, 000, 000, 1150, 470, 430,
|
|
33, 33, 33, 33, 33, 33,
|
|
};
|
|
|
|
static uint32 AMDProcessorCycles[] =
|
|
{
|
|
470,430,302
|
|
};
|
|
|
|
static uint32 CyrixProcessorCycles[] =
|
|
{
|
|
330,330
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
//
|
|
#define MAXCLOCKS 150 // Maximum number of cycles per BSF instruction
|
|
#define ITERATIONS 4000 // Number of times to repeat BSF instruction in samplings.
|
|
#define INITIAL_DELAY 3 // Number of ticks to wait through before starting test sampling.
|
|
#define SAMPLING_DELAY 60 // Number of ticks to allow to elapse during sampling.
|
|
#define TOLERANCE 1 // Number of MHz to allow samplings to deviate from average of samplings.
|
|
#define MAX_TRIES 40 // Maximum number of samplings to allow before giving up and returning current average
|
|
#define SAMPLINGS 10 // Number of BSF sequence samplings to make.
|
|
|
|
|
|
//*********************************************************************************************
|
|
//
|
|
static uint32 u4CPUSpeed(int clocks)
|
|
{
|
|
|
|
uint32 ticks; // Microseconds elapsed during test
|
|
uint32 cycles; // Clock cycles elapsed during test
|
|
uint32 stamp0, stamp1; // Time Stamp Variable for beginning and end of test
|
|
LARGE_INTEGER t0,t1; // Variables for High-Resolution Performance Counter reads
|
|
|
|
uint32 freq =0; // Most current frequ. calculation
|
|
uint32 freq2 =0; // 2nd most current frequ. calc.
|
|
uint32 freq3 =0; // 3rd most current frequ. calc.
|
|
|
|
uint32 total; // Sum of previous three frequency calculations
|
|
|
|
// Specifies whether the user manually entered the number of cycles for the BSF instruction.
|
|
int manual=0;
|
|
|
|
// Number of times a calculation has been made on this call to cpuspeed
|
|
int tries=0;
|
|
|
|
LARGE_INTEGER count_freq; // High Resolution Performance Counter frequency
|
|
|
|
// Check for manual BSF instruction clock count
|
|
if (clocks == 0)
|
|
{
|
|
switch (cpu.cpumanProcessorManufacture)
|
|
{
|
|
case cpumanINTEL:
|
|
cycles = ITERATIONS * IntelProcessorCycles[cpu.cpufamProcessorFamily];
|
|
break;
|
|
|
|
case cpumanAMD:
|
|
cycles = ITERATIONS * AMDProcessorCycles[cpu.cpufamProcessorFamily - cpufamAM486];
|
|
break;
|
|
|
|
case cpumanCYRIX:
|
|
cycles = ITERATIONS * CyrixProcessorCycles[cpu.cpufamProcessorFamily - cpufam686];
|
|
break;
|
|
}
|
|
}
|
|
else if (0 < clocks && clocks <= MAXCLOCKS)
|
|
{
|
|
// Toggle manual control flag. Note that this mode will not work properly with processors
|
|
// which can process multiple BSF instructions at a time. For example, manual mode
|
|
// will not work on a PentiumPro(R)
|
|
cycles = ITERATIONS * clocks;
|
|
manual = 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Checks whether the high-resolution counter exists and returns an error if it does not exist.
|
|
if ( !QueryPerformanceFrequency ( &count_freq ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( ( cpu.u4Feature & 0x00000010 ) && !(manual) )
|
|
{
|
|
// On processors supporting the Read Time Stamp opcode, compare elapsed time on the
|
|
// High-Resolution Counter with elapsed cycles on the Time Stamp Register.
|
|
do
|
|
{
|
|
// This do loop runs up to 20 times or until the average of the previous three calculated
|
|
// frequencies is within 1 MHz of each of the individual calculated frequencies.
|
|
// This resampling increases the accuracy of the results since outside factors could affect
|
|
// this calculation
|
|
tries++; // Increment number of times sampled on this call to cpuspeed
|
|
freq3 = freq2; // Shift frequencies back to make
|
|
freq2 = freq; // room for new frequency measurement
|
|
|
|
//Get high-resolution performance counter time
|
|
QueryPerformanceCounter(&t0);
|
|
|
|
t1.LowPart = t0.LowPart; // Set Initial time
|
|
t1.HighPart = t0.HighPart;
|
|
|
|
|
|
// Loop until 50 ticks have passed since last read of hi-res counter.
|
|
// This accounts for overhead later.
|
|
while ( (uint32)t1.LowPart - (uint32)t0.LowPart<50)
|
|
{
|
|
QueryPerformanceCounter(&t1);
|
|
}
|
|
|
|
_asm
|
|
{
|
|
rdtsc
|
|
mov stamp0, EAX
|
|
}
|
|
|
|
t0.LowPart = t1.LowPart; // Reset Initial
|
|
t0.HighPart = t1.HighPart; // Time
|
|
|
|
// Loop until 1000 ticks have passed since last read of hi-res counter.
|
|
// This allows for elapsed time for sampling.
|
|
while ((uint32)t1.LowPart-(uint32)t0.LowPart<1000 )
|
|
{
|
|
QueryPerformanceCounter(&t1);
|
|
}
|
|
|
|
|
|
_asm
|
|
{
|
|
rdtsc
|
|
mov stamp1, EAX
|
|
}
|
|
|
|
cycles = stamp1 - stamp0;
|
|
ticks = (uint32) t1.LowPart - (uint32) t0.LowPart;
|
|
|
|
// Note that some seemingly arbitrary mulitplies and divides are done below.
|
|
// This is to maintain a high level of precision without truncating the most
|
|
// significant data. According to what value ITERATIIONS is set to, these
|
|
// multiplies and divides might need to be shifted for optimal precision.
|
|
|
|
ticks = ticks * 100000;
|
|
ticks = ticks / ( count_freq.LowPart/10 );
|
|
|
|
if ( ticks%count_freq.LowPart > count_freq.LowPart/2 )
|
|
{
|
|
ticks++; // Round up if necessary
|
|
}
|
|
|
|
freq = cycles/ticks; // Cycles / us = MHz
|
|
|
|
if ( cycles%ticks > ticks/2 )
|
|
{
|
|
freq++; // Round up if necessary
|
|
}
|
|
|
|
total = ( freq + freq2 + freq3 );
|
|
|
|
} while ( (tries < 3 ) || (tries < 20) && ((abs(3 * freq -total) > 3*TOLERANCE ) ||
|
|
(abs(3 * freq2-total) > 3*TOLERANCE ) || (abs(3 * freq3-total) > 3*TOLERANCE )));
|
|
|
|
if ( total / 3 != ( total + 1 ) / 3 )
|
|
{
|
|
total ++; // Round up if necessary
|
|
}
|
|
freq = total / 3;
|
|
}
|
|
else if ( cpu.cpufamProcessorFamily >= 3 )
|
|
{
|
|
// If processor does not support time stamp reading, but is at least a 386 or above,
|
|
// utilize method of timing a loop of BSF instructions which take a known number of
|
|
// cycles to run on i386(tm), i486(tm), and Pentium(R) processors.
|
|
|
|
int i; // Temporary Variable
|
|
uint32 current = 0;
|
|
uint32 lowest = 0xffffffff;
|
|
|
|
for ( i = 0; i < SAMPLINGS; i++ )
|
|
{
|
|
QueryPerformanceCounter(&t0); // Get start time
|
|
_asm
|
|
{
|
|
mov eax, 80000000h
|
|
mov bx, ITERATIONS
|
|
LOOP1: bsf ecx,eax
|
|
dec bx
|
|
jnz LOOP1
|
|
}
|
|
|
|
QueryPerformanceCounter(&t1); // Get end time
|
|
|
|
current = (uint32) t1.LowPart - (uint32) t0.LowPart;
|
|
if ( current < lowest )
|
|
lowest = current;
|
|
}
|
|
ticks = lowest;
|
|
|
|
ticks = ticks * 100000;
|
|
ticks = ticks / ( count_freq.LowPart/10 );
|
|
if ( ticks%count_freq.LowPart > count_freq.LowPart/2 )
|
|
{
|
|
ticks++; // Round up if necessary
|
|
}
|
|
|
|
freq = cycles/ticks; // Cycles / us = MHz
|
|
|
|
if ( cycles%ticks > ticks/2 )
|
|
freq++; // Round up if necessary
|
|
|
|
freq/=10;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
// Make the correct textual name for the processor
|
|
// AMD has some instructions to get this from the device itself!!
|
|
//
|
|
void MakeName(void)
|
|
{
|
|
uint32 u4_name;
|
|
|
|
if (cpu.u4CPUFlags & CPU_CPUID)
|
|
{
|
|
switch (cpu.cpumanProcessorManufacture)
|
|
{
|
|
case cpumanINTEL:
|
|
switch ((cpu.u4Model>>4) & 0xff)
|
|
{
|
|
case 0x040:
|
|
case 0x041:
|
|
strcat(&cpu.strProcessor[0],"Intel 486 DX");
|
|
break;
|
|
|
|
case 0x042:
|
|
strcat(&cpu.strProcessor[0],"Intel 486 SX");
|
|
break;
|
|
|
|
case 0x043:
|
|
strcat(&cpu.strProcessor[0],"Intel 486 DX2");
|
|
break;
|
|
|
|
case 0x044:
|
|
strcat(&cpu.strProcessor[0],"Intel 486 SL");
|
|
break;
|
|
|
|
case 0x045:
|
|
strcat(&cpu.strProcessor[0],"Intel 486 SX2");
|
|
break;
|
|
|
|
case 0x047:
|
|
strcat(&cpu.strProcessor[0],"Intel 486 DX2 Write-Back Enhanced");
|
|
break;
|
|
|
|
case 0x048:
|
|
strcat(&cpu.strProcessor[0],"Intel 486 DX4");
|
|
break;
|
|
|
|
case 0x050:
|
|
case 0x051:
|
|
case 0x052:
|
|
case 0x053:
|
|
strcat(&cpu.strProcessor[0],"Intel Pentium Processor");
|
|
break;
|
|
|
|
case 0x054:
|
|
case 0x055:
|
|
case 0x056:
|
|
case 0x057:
|
|
case 0x058:
|
|
case 0x059:
|
|
case 0x05A:
|
|
case 0x05B:
|
|
case 0x05C:
|
|
case 0x05D:
|
|
case 0x05E:
|
|
case 0x05F:
|
|
strcat(&cpu.strProcessor[0],"Intel Pentium Processor with MMX Technology");
|
|
break;
|
|
|
|
case 0x060:
|
|
case 0x061:
|
|
case 0x062:
|
|
strcat(&cpu.strProcessor[0],"Intel Pentium Pro Processor");
|
|
break;
|
|
|
|
case 0x063:
|
|
case 0x064:
|
|
case 0x065:
|
|
case 0x066:
|
|
case 0x067:
|
|
case 0x068:
|
|
case 0x069:
|
|
case 0x06A:
|
|
case 0x06B:
|
|
case 0x06C:
|
|
case 0x06D:
|
|
case 0x06E:
|
|
case 0x06F:
|
|
strcat(&cpu.strProcessor[0],"Intel Pentium II Processor with MMX Technology");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case cpumanAMD:
|
|
u4_name = u4QueryCPUIDName();
|
|
|
|
if (u4_name == 0)
|
|
{
|
|
// we failed to get a name from the CPUID instruction..
|
|
switch (cpu.cpufamProcessorFamily)
|
|
{
|
|
case cpufamAM486:
|
|
strcpy(&cpu.strProcessor[0],"AMD-AM486");
|
|
break;
|
|
|
|
case cpufamK5:
|
|
strcpy(&cpu.strProcessor[0],"AMD-K5");
|
|
break;
|
|
|
|
case cpufamK6:
|
|
strcpy(&cpu.strProcessor[0],"AMD-K6");
|
|
break;
|
|
|
|
}
|
|
|
|
if (cpu.u4Feature & (1<<23))
|
|
{
|
|
strcat(&cpu.strProcessor[0]," with multimedia extentions");
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case cpumanIDT:
|
|
u4_name = u4QueryCPUIDName();
|
|
|
|
if (u4_name == 0)
|
|
{
|
|
// we failed to get a name from the CPUID instruction..
|
|
switch (cpu.cpufamProcessorFamily)
|
|
{
|
|
case cpufamWINCHIPC6:
|
|
strcpy(&cpu.strProcessor[0],"IDT WinChip C6");
|
|
break;
|
|
|
|
case cpufamWINCHIP2:
|
|
strcpy(&cpu.strProcessor[0],"IDT WinChip2");
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case cpumanCYRIX:
|
|
if (cpu.cpufamProcessorFamily == 5)
|
|
{
|
|
strcat(&cpu.strProcessor[0],"Cyrix 686");
|
|
}
|
|
else if (cpu.cpufamProcessorFamily == 6)
|
|
{
|
|
strcat(&cpu.strProcessor[0],"Cyrix M2");
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
// We do not know what processor is present but we can look for
|
|
// the extended CPUID functions that give the name on some
|
|
// processors.
|
|
u4_name = u4QueryCPUIDName();
|
|
|
|
if (u4_name == 0)
|
|
{
|
|
// Processor does not support the exteneded CPUID so we do
|
|
// not know what it is
|
|
strcpy(&cpu.strProcessor[0],"Cannot Determine");
|
|
}
|
|
else
|
|
{
|
|
// Processor returned something for the extended CPUID functions
|
|
// so we will return that with an unsure comment.
|
|
strcat(&cpu.strProcessor[0]," (Uncertain)");
|
|
}
|
|
break;
|
|
}
|
|
|
|
// check for an overdrive
|
|
if ((cpu.u4Model & 0x1000) == 0x1000 )
|
|
{
|
|
strcat(&cpu.strProcessor[0]," [OverDrive]");
|
|
}
|
|
|
|
if ((cpu.u4Model & 0x2000) == 0x2000 )
|
|
{
|
|
strcat(&cpu.strProcessor[0]," [Slave]");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// NO CPUID - we need to just do the best we can with whta we have
|
|
switch (cpu.cpufamProcessorFamily)
|
|
{
|
|
case cpufam8086:
|
|
strcpy(&cpu.strProcessor[0],"8086");
|
|
if (cpu.u4CPUFlags & CPU_FPUPRESENT)
|
|
{
|
|
strcat(&cpu.strProcessor[0]," with an 8087");
|
|
}
|
|
break;
|
|
|
|
case cpufam80286:
|
|
strcpy(&cpu.strProcessor[0],"80286");
|
|
if (cpu.u4CPUFlags & CPU_FPUPRESENT)
|
|
{
|
|
strcat(&cpu.strProcessor[0]," with an 80287");
|
|
}
|
|
break;
|
|
|
|
case cpufam80386:
|
|
strcpy(&cpu.strProcessor[0],"80386");
|
|
if (cpu.u4CPUFlags & CPU_FPUPRESENT)
|
|
{
|
|
if (cpu.cpufamFPUFamily == 2)
|
|
{
|
|
strcat(&cpu.strProcessor[0]," with an 80287");
|
|
}
|
|
else
|
|
{
|
|
strcat(&cpu.strProcessor[0]," with an 80387");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case cpufam80486:
|
|
strcpy(&cpu.strProcessor[0],"80386");
|
|
if (cpu.u4CPUFlags & CPU_FPUPRESENT)
|
|
{
|
|
strcat(&cpu.strProcessor[0]," DX");
|
|
}
|
|
else
|
|
{
|
|
strcat(&cpu.strProcessor[0]," SX");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
strcat(&cpu.strProcessor[0],"Cannot Determine");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
// Look for the CPUID name functions and use if they are present.
|
|
//
|
|
uint32 u4QueryCPUIDName(void)
|
|
{
|
|
uint32 u4_name;
|
|
|
|
// No CPUID instruction then there are no extended names.
|
|
if ((cpu.u4CPUFlags & CPU_CPUID) == 0)
|
|
return 0;
|
|
|
|
_asm
|
|
{
|
|
mov eax,0x80000000 // extended CPUID function,AMD and IDT support it
|
|
|
|
//CPUID
|
|
_emit 0x0f
|
|
_emit 0xa2
|
|
|
|
cmp eax,0x80000004
|
|
jb short EXIT_AMD_NAME // functions upto 0x80000004 must be present
|
|
|
|
mov eax,0x80000002 // extended CPUID function
|
|
//CPUID
|
|
_emit 0x0f
|
|
_emit 0xa2
|
|
|
|
mov DWORD PTR [cpu.strProcessor+0],eax
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+8], eax
|
|
mov DWORD PTR [cpu.strProcessor+4],ebx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+12], ebx
|
|
mov DWORD PTR [cpu.strProcessor+8],ecx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+16], ecx
|
|
mov DWORD PTR [cpu.strProcessor+12],edx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+20], edx
|
|
|
|
mov eax,0x80000003 // extended CPUID function
|
|
//CPUID
|
|
_emit 0x0f
|
|
_emit 0xa2
|
|
|
|
mov DWORD PTR [cpu.strProcessor+16],eax
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+24], eax
|
|
mov DWORD PTR [cpu.strProcessor+20],ebx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+28], ebx
|
|
mov DWORD PTR [cpu.strProcessor+24],ecx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+32], ecx
|
|
mov DWORD PTR [cpu.strProcessor+28],edx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+36], edx
|
|
|
|
mov eax,0x80000004 // extended CPUID function
|
|
//CPUID
|
|
_emit 0x0f
|
|
_emit 0xa2
|
|
|
|
mov DWORD PTR [cpu.strProcessor+32],eax
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+40], eax
|
|
mov DWORD PTR [cpu.strProcessor+36],ebx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+44], ebx
|
|
mov DWORD PTR [cpu.strProcessor+40],ecx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+48], ecx
|
|
mov DWORD PTR [cpu.strProcessor+44],edx
|
|
mov DWORD PTR [cpu.au4ProcessorSpecific+52], edx
|
|
|
|
mov u4_name, 1 // we have got the name
|
|
jmp short DONE
|
|
EXIT_AMD_NAME:
|
|
mov u4_name, 0 // there is no name function, must get make the name
|
|
DONE:
|
|
}
|
|
|
|
return u4_name;
|
|
} |