📄 cpu_info.cpp
字号:
}
} else {
// Set the advanced SSE capabilities to not available.
Features.HasSSEFP = false;
}
// Retrieve Intel specific extended features.
if (ChipManufacturer == Intel) {
Features.ExtendedFeatures.SupportsHyperthreading = ((CPUFeatures & 0x10000000) != 0); // Intel specific: Hyperthreading --> Bit 28
Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (Features.ExtendedFeatures.SupportsHyperthreading) ? ((CPUAdvanced & 0x00FF0000) >> 16) : 1;
if ((Features.ExtendedFeatures.SupportsHyperthreading) && (Features.HasAPIC)){
// Retrieve APIC information if there is one present.
Features.ExtendedFeatures.APIC_ID = ((CPUAdvanced & 0xFF000000) >> 24);
}
}
return true;
}
bool __cdecl CPUInfo::RetrieveCPUIdentity ()
{
int CPUVendor[3];
int CPUSignature;
// Use assembly to detect CPUID information...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 0 --> eax: maximum value of CPUID instruction.
; ebx: part 1 of 3; CPU signature.
; edx: part 2 of 3; CPU signature.
; ecx: part 3 of 3; CPU signature.
mov eax, 0
CPUID_INSTRUCTION
mov CPUVendor[0 * TYPE int], ebx
mov CPUVendor[1 * TYPE int], edx
mov CPUVendor[2 * TYPE int], ecx
; <<CPUID>>
; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision
; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
; edx: CPU feature flags
mov eax,1
CPUID_INSTRUCTION
mov CPUSignature, eax
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
// Process the returned information.
memcpy (ChipID.Vendor, &(CPUVendor[0]), sizeof (int));
memcpy (&(ChipID.Vendor[4]), &(CPUVendor[1]), sizeof (int));
memcpy (&(ChipID.Vendor[8]), &(CPUVendor[2]), sizeof (int));
ChipID.Vendor[12] = '\0';
// Attempt to retrieve the manufacturer from the vendor string.
if (strcmp (ChipID.Vendor, "GenuineIntel") == 0) ChipManufacturer = Intel; // Intel Corp.
else if (strcmp (ChipID.Vendor, "UMC UMC UMC ") == 0) ChipManufacturer = UMC; // United Microelectronics Corp.
else if (strcmp (ChipID.Vendor, "AuthenticAMD") == 0) ChipManufacturer = AMD; // Advanced Micro Devices
else if (strcmp (ChipID.Vendor, "AMD ISBETTER") == 0) ChipManufacturer = AMD; // Advanced Micro Devices (1994)
else if (strcmp (ChipID.Vendor, "CyrixInstead") == 0) ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
else if (strcmp (ChipID.Vendor, "NexGenDriven") == 0) ChipManufacturer = NexGen; // NexGen Inc. (now AMD)
else if (strcmp (ChipID.Vendor, "CentaurHauls") == 0) ChipManufacturer = IDT; // IDT/Centaur (now VIA)
else if (strcmp (ChipID.Vendor, "RiseRiseRise") == 0) ChipManufacturer = Rise; // Rise
else if (strcmp (ChipID.Vendor, "GenuineTMx86") == 0) ChipManufacturer = Transmeta; // Transmeta
else if (strcmp (ChipID.Vendor, "TransmetaCPU") == 0) ChipManufacturer = Transmeta; // Transmeta
else if (strcmp (ChipID.Vendor, "Geode By NSC") == 0) ChipManufacturer = NSC; // National Semiconductor
else ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
// Retrieve the family of CPU present.
ChipID.ExtendedFamily = ((CPUSignature & 0x0FF00000) >> 20); // Bits 27..20 Used
ChipID.ExtendedModel = ((CPUSignature & 0x000F0000) >> 16); // Bits 19..16 Used
ChipID.Type = ((CPUSignature & 0x0000F000) >> 12); // Bits 15..12 Used
ChipID.Family = ((CPUSignature & 0x00000F00) >> 8); // Bits 11..8 Used
ChipID.Model = ((CPUSignature & 0x000000F0) >> 4); // Bits 7..4 Used
ChipID.Revision = ((CPUSignature & 0x0000000F) >> 0); // Bits 3..0 Used
return true;
}
bool __cdecl CPUInfo::RetrieveCPUCacheDetails ()
{
int L1Cache[4] = { 0, 0, 0, 0 };
int L2Cache[4] = { 0, 0, 0, 0 };
// Check to see if what we are about to do is supported...
if (RetrieveCPUExtendedLevelSupport (0x80000005)) {
// Use assembly to retrieve the L1 cache information ...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 0x80000005 --> eax: L1 cache information - Part 1 of 4.
; ebx: L1 cache information - Part 2 of 4.
; edx: L1 cache information - Part 3 of 4.
; ecx: L1 cache information - Part 4 of 4.
mov eax, 0x80000005
CPUID_INSTRUCTION
mov L1Cache[0 * TYPE int], eax
mov L1Cache[1 * TYPE int], ebx
mov L1Cache[2 * TYPE int], ecx
mov L1Cache[3 * TYPE int], edx
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
// Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as data cache size from edx: bits 31..24.
Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24);
Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24);
} else {
// Store -1 to indicate the cache could not be queried.
Features.L1CacheSize = -1;
}
// Check to see if what we are about to do is supported...
if (RetrieveCPUExtendedLevelSupport (0x80000006)) {
// Use assembly to retrieve the L2 cache information ...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 0x80000006 --> eax: L2 cache information - Part 1 of 4.
; ebx: L2 cache information - Part 2 of 4.
; edx: L2 cache information - Part 3 of 4.
; ecx: L2 cache information - Part 4 of 4.
mov eax, 0x80000006
CPUID_INSTRUCTION
mov L2Cache[0 * TYPE int], eax
mov L2Cache[1 * TYPE int], ebx
mov L2Cache[2 * TYPE int], ecx
mov L2Cache[3 * TYPE int], edx
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
// Save the L2 unified cache size (in KB) from ecx: bits 31..16.
Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16);
} else {
// Store -1 to indicate the cache could not be queried.
Features.L2CacheSize = -1;
}
// Define L3 as being not present as we cannot test for it.
Features.L3CacheSize = -1;
// Return failure if we cannot detect either cache with this method.
return ((Features.L1CacheSize == -1) && (Features.L2CacheSize == -1)) ? false : true;
}
bool __cdecl CPUInfo::RetrieveClassicalCPUCacheDetails ()
{
int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, L2Unified = -1, L3Unified = -1;
int TLBCacheData[4] = { 0, 0, 0, 0 };
int TLBPassCounter = 0;
int TLBCacheUnit = 0;
do {
// Use assembly to retrieve the L2 cache information ...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 2 --> eax: TLB and cache information - Part 1 of 4.
; ebx: TLB and cache information - Part 2 of 4.
; ecx: TLB and cache information - Part 3 of 4.
; edx: TLB and cache information - Part 4 of 4.
mov eax, 2
CPUID_INSTRUCTION
mov TLBCacheData[0 * TYPE int], eax
mov TLBCacheData[1 * TYPE int], ebx
mov TLBCacheData[2 * TYPE int], ecx
mov TLBCacheData[3 * TYPE int], edx
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16);
// Process the returned TLB and cache information.
for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter ++) {
// First of all - decide which unit we are dealing with.
switch (nCounter) {
// eax: bits 8..15 : bits 16..23 : bits 24..31
case 0: TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); break;
case 1: TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); break;
case 2: TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); break;
// ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
case 3: TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); break;
case 4: TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); break;
case 5: TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); break;
case 6: TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); break;
// ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
case 7: TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); break;
case 8: TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); break;
case 9: TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); break;
case 10: TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); break;
// edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
case 11: TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); break;
case 12: TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); break;
case 13: TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); break;
case 14: TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); break;
// Default case - an error has occured.
default: return false;
}
// Now process the resulting unit to see what it means....
switch (TLBCacheUnit) {
case 0x00: break;
case 0x01: STORE_TLBCACHE_INFO (TLBCode, 4); break;
case 0x02: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
case 0x03: STORE_TLBCACHE_INFO (TLBData, 4); break;
case 0x04: STORE_TLBCACHE_INFO (TLBData, 4096); break;
case 0x06: STORE_TLBCACHE_INFO (L1Code, 8); break;
case 0x08: STORE_TLBCACHE_INFO (L1Code, 16); break;
case 0x0a: STORE_TLBCACHE_INFO (L1Data, 8); break;
case 0x0c: STORE_TLBCACHE_INFO (L1Data, 16); break;
case 0x10: STORE_TLBCACHE_INFO (L1Data, 16); break; // <-- FIXME: IA-64 Only
case 0x15: STORE_TLBCACHE_INFO (L1Code, 16); break; // <-- FIXME: IA-64 Only
case 0x1a: STORE_TLBCACHE_INFO (L2Unified, 96); break; // <-- FIXME: IA-64 Only
case 0x22: STORE_TLBCACHE_INFO (L3Unified, 512); break;
case 0x23: STORE_TLBCACHE_INFO (L3Unified, 1024); break;
case 0x25: STORE_TLBCACHE_INFO (L3Unified, 2048); break;
case 0x29: STORE_TLBCACHE_INFO (L3Unified, 4096); break;
case 0x39: STORE_TLBCACHE_INFO (L2Unified, 128); break;
case 0x3c: STORE_TLBCACHE_INFO (L2Unified, 256); break;
case 0x40: STORE_TLBCACHE_INFO (L2Unified, 0); break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 core).
case 0x41: STORE_TLBCACHE_INFO (L2Unified, 128); break;
case 0x42: STORE_TLBCACHE_INFO (L2Unified, 256); break;
case 0x43: STORE_TLBCACHE_INFO (L2Unified, 512); break;
case 0x44: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
case 0x45: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
case 0x50: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
case 0x51: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
case 0x52: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
case 0x5b: STORE_TLBCACHE_INFO (TLBData, 4096); break;
case 0x5c: STORE_TLBCACHE_INFO (TLBData, 4096); break;
case 0x5d: STORE_TLBCACHE_INFO (TLBData, 4096); break;
case 0x66: STORE_TLBCACHE_INFO (L1Data, 8); break;
case 0x67: STORE_TLBCACHE_INFO (L1Data, 16); break;
case 0x68: STORE_TLBCACHE_INFO (L1Data, 32); break;
case 0x70: STORE_TLBCACHE_INFO (L1Trace, 12); break;
case 0x71: STORE_TLBCACHE_INFO (L1Trace, 16); break;
case 0x72: STORE_TLBCACHE_INFO (L1Trace, 32); break;
case 0x77: STORE_TLBCACHE_INFO (L1Code, 16); break; // <-- FIXME: IA-64 Only
case 0x79: STORE_TLBCACHE_INFO (L2Unified, 128); break;
case 0x7a: STORE_TLBCACHE_INFO (L2Unified, 256); break;
case 0x7b: STORE_TLBCACHE_INFO (L2Unified, 512); break;
case 0x7c: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
case 0x7e: STORE_TLBCACHE_INFO (L2Unified, 256); break;
case 0x81: STORE_TLBCACHE_INFO (L2Unified, 128); break;
case 0x82: STORE_TLBCACHE_INFO (L2Unified, 256); break;
case 0x83: STORE_TLBCACHE_INFO (L2Unified, 512); break;
case 0x84: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
case 0x85: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
case 0x88: STORE_TLBCACHE_INFO (L3Unified, 2048); break; // <-- FIXME: IA-64 Only
case 0x89: STORE_TLBCACHE_INFO (L3Unified, 4096); break; // <-- FIXME: IA-64 Only
case 0x8a: STORE_TLBCACHE_INFO (L3Unified, 8192); break; // <-- FIXME: IA-64 Only
case 0x8d: STORE_TLBCACHE_INFO (L3Unified, 3096); break; // <-- FIXME: IA-64 Only
case 0x90: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
case 0x96: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
case 0x9b: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
// Default case - an error has occured.
default: return false;
}
}
// Increment the TLB pass counter.
TLBPassCounter ++;
} while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter);
// Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1)) Features.L1CacheSize = -1;
else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1)) Features.L1CacheSize = L1Trace;
else if ((L1Code != -1) && (L1Data == -1)) Features.L1CacheSize = L1Code;
else if ((L1Code == -1) && (L1Data != -1)) Features.L1CacheSize = L1Data;
else if ((L1Code != -1) && (L1Data != -1)) Features.L1CacheSize = L1Code + L1Data;
else Features.L1CacheSize = -1;
// Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
if (L2Unified == -1) Features.L2CacheSize = -1;
else Features.L2CacheSize = L2Unified;
// Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
if (L3Unified == -1) Features.L3CacheSize = -1;
else Features.L3CacheSize = L3Unified;
return true;
}
bool __cdecl CPUInfo::RetrieveCPUClockSpeed ()
{
// First of all we check to see if the RDTSC (0x0F, 0x31) instruction is supported.
if (!Features.HasTSC) return false;
// Get the clock speed.
Speed = new CPUSpeed ();
if (Speed == NULL) return false;
return true;
}
bool __cdecl CPUInfo::RetrieveClassicalCPUClockSpeed ()
{
LARGE_INTEGER liStart, liEnd, liCountsPerSecond;
double dFrequency, dDifference;
// Attempt to get a starting tick count.
QueryPerformanceCounter (&liStart);
__try {
_asm {
mov eax, 0x80000000
mov ebx, CLASSICAL_CPU_FREQ_LOOP
Timer_Loop:
bsf ecx,eax
dec ebx
jnz Timer_Loop
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -