📄 cpu_info.cpp
字号:
// Camel - CPU Identifying Tool
// Copyright (C) 2002, Iain Chesworth
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "cpu_info.h"
// --------------------------------------------------------
//
// Constructor Functions - CPUInfo Class
//
// --------------------------------------------------------
CPUInfo::CPUInfo ()
{
// Check to see if this processor supports CPUID.
if (DoesCPUSupportCPUID ()) {
// Retrieve the CPU details.
RetrieveCPUIdentity ();
RetrieveCPUFeatures ();
if (!RetrieveCPUClockSpeed ()) RetrieveClassicalCPUClockSpeed ();
// Attempt to retrieve cache information.
if (!RetrieveCPUCacheDetails ()) RetrieveClassicalCPUCacheDetails ();
// Retrieve the extended CPU details.
if (!RetrieveExtendedCPUIdentity ()) RetrieveClassicalCPUIdentity ();
RetrieveExtendedCPUFeatures ();
// Now attempt to retrieve the serial number (if possible).
RetrieveProcessorSerialNumber ();
}
}
CPUInfo::~CPUInfo ()
{
}
// --------------------------------------------------------
//
// Public Functions - CPUInfo Class
//
// --------------------------------------------------------
char * CPUInfo::GetVendorString ()
{
// Return the vendor string.
return ChipID.Vendor;
}
char * CPUInfo::GetVendorID ()
{
// Return the vendor ID.
switch (ChipManufacturer) {
case Intel:
return "Intel Corporation";
case AMD:
return "Advanced Micro Devices";
case NSC:
return "National Semiconductor";
case Cyrix:
return "Cyrix Corp., VIA Inc.";
case NexGen:
return "NexGen Inc., Advanced Micro Devices";
case IDT:
return "IDT\\Centaur, Via Inc.";
case UMC:
return "United Microelectronics Corp.";
case Rise:
return "Rise";
case Transmeta:
return "Transmeta";
default:
return "Unknown Manufacturer";
}
}
char * CPUInfo::GetTypeID ()
{
// Return the type ID of the CPU.
char * szTypeID = new char [32];
itoa (ChipID.Type, szTypeID, 10);
return szTypeID;
}
char * CPUInfo::GetFamilyID ()
{
// Return the family of the CPU present.
char * szFamilyID = new char [32];
itoa (ChipID.Family, szFamilyID, 10);
return szFamilyID;
}
char * CPUInfo::GetModelID ()
{
// Return the model of CPU present.
char * szModelID = new char [32];
itoa (ChipID.Model, szModelID, 10);
return szModelID;
}
char * CPUInfo::GetSteppingCode ()
{
// Return the stepping code of the CPU present.
char * szSteppingCode = new char [32];
itoa (ChipID.Revision, szSteppingCode, 10);
return szSteppingCode;
}
char * CPUInfo::GetExtendedProcessorName ()
{
// Return the stepping code of the CPU present.
return ChipID.ProcessorName;
}
char * CPUInfo::GetProcessorSerialNumber ()
{
// Return the serial number of the processor in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx.
return ChipID.SerialNumber;
}
int CPUInfo::GetLogicalProcessorsPerPhysical ()
{
// Return the logical processors per physical.
return Features.ExtendedFeatures.LogicalProcessorsPerPhysical;
}
int CPUInfo::GetProcessorClockFrequency ()
{
// Return the processor clock frequency.
if (Speed != NULL)
return Speed->CPUSpeedInMHz;
else
// Display the error condition.
return -1;
}
int CPUInfo::GetProcessorAPICID ()
{
// Return the APIC ID.
return Features.ExtendedFeatures.APIC_ID;
}
int CPUInfo::GetProcessorCacheXSize (DWORD dwCacheID)
{
// Return the chosen cache size.
switch (dwCacheID) {
case L1CACHE_FEATURE:
return Features.L1CacheSize;
case L2CACHE_FEATURE:
return Features.L2CacheSize;
case L3CACHE_FEATURE:
return Features.L3CacheSize;
}
// The user did something strange just return and error.
return -1;
}
bool CPUInfo::DoesCPUSupportFeature (DWORD dwFeature)
{
bool bHasFeature = false;
// Check for MMX instructions.
if (((dwFeature & MMX_FEATURE) != 0) && Features.HasMMX) bHasFeature = true;
// Check for MMX+ instructions.
if (((dwFeature & MMX_PLUS_FEATURE) != 0) && Features.ExtendedFeatures.HasMMXPlus) bHasFeature = true;
// Check for SSE FP instructions.
if (((dwFeature & SSE_FEATURE) != 0) && Features.HasSSE) bHasFeature = true;
// Check for SSE FP instructions.
if (((dwFeature & SSE_FP_FEATURE) != 0) && Features.HasSSEFP) bHasFeature = true;
// Check for SSE MMX instructions.
if (((dwFeature & SSE_MMX_FEATURE) != 0) && Features.ExtendedFeatures.HasSSEMMX) bHasFeature = true;
// Check for SSE2 instructions.
if (((dwFeature & SSE2_FEATURE) != 0) && Features.HasSSE2) bHasFeature = true;
// Check for 3DNow! instructions.
if (((dwFeature & AMD_3DNOW_FEATURE) != 0) && Features.ExtendedFeatures.Has3DNow) bHasFeature = true;
// Check for 3DNow+ instructions.
if (((dwFeature & AMD_3DNOW_PLUS_FEATURE) != 0) && Features.ExtendedFeatures.Has3DNowPlus) bHasFeature = true;
// Check for IA64 instructions.
if (((dwFeature & IA64_FEATURE) != 0) && Features.HasIA64) bHasFeature = true;
// Check for MP capable.
if (((dwFeature & MP_CAPABLE) != 0) && Features.ExtendedFeatures.SupportsMP) bHasFeature = true;
// Check for a serial number for the processor.
if (((dwFeature & SERIALNUMBER_FEATURE) != 0) && Features.HasSerial) bHasFeature = true;
// Check for a local APIC in the processor.
if (((dwFeature & APIC_FEATURE) != 0) && Features.HasAPIC) bHasFeature = true;
// Check for CMOV instructions.
if (((dwFeature & CMOV_FEATURE) != 0) && Features.HasCMOV) bHasFeature = true;
// Check for MTRR instructions.
if (((dwFeature & MTRR_FEATURE) != 0) && Features.HasMTRR) bHasFeature = true;
// Check for L1 cache size.
if (((dwFeature & L1CACHE_FEATURE) != 0) && (Features.L1CacheSize != -1)) bHasFeature = true;
// Check for L2 cache size.
if (((dwFeature & L2CACHE_FEATURE) != 0) && (Features.L2CacheSize != -1)) bHasFeature = true;
// Check for L3 cache size.
if (((dwFeature & L3CACHE_FEATURE) != 0) && (Features.L3CacheSize != -1)) bHasFeature = true;
// Check for ACPI capability.
if (((dwFeature & ACPI_FEATURE) != 0) && Features.HasACPI) bHasFeature = true;
// Check for thermal monitor support.
if (((dwFeature & THERMALMONITOR_FEATURE) != 0) && Features.HasThermal) bHasFeature = true;
// Check for temperature sensing diode support.
if (((dwFeature & TEMPSENSEDIODE_FEATURE) != 0) && Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) bHasFeature = true;
// Check for frequency ID support.
if (((dwFeature & FREQUENCYID_FEATURE) != 0) && Features.ExtendedFeatures.PowerManagement.HasFrequencyID) bHasFeature = true;
// Check for voltage ID support.
if (((dwFeature & VOLTAGEID_FREQUENCY) != 0) && Features.ExtendedFeatures.PowerManagement.HasVoltageID) bHasFeature = true;
return bHasFeature;
}
// --------------------------------------------------------
//
// Private Functions - CPUInfo Class
//
// --------------------------------------------------------
bool __cdecl CPUInfo::DoesCPUSupportCPUID ()
{
int CPUIDPresent = 0;
#ifdef _WIN32
// Use SEH to determine CPUID presence
__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>>
mov eax, 0
CPUID_INSTRUCTION
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
// Stop the class from trying to use CPUID again!
CPUIDPresent = false;
return false;
}
#else
// The "right" way, which doesn't work under certain Windows versions
__try {
_asm {
pushfd ; save EFLAGS to stack.
pop eax ; store EFLAGS in eax.
mov edx, eax ; save in ebx for testing later.
xor eax, 0200000h ; switch bit 21.
push eax ; copy "changed" value to stack.
popfd ; save "changed" eax to EFLAGS.
pushfd
pop eax
xor eax, edx ; See if bit changeable.
jnz short cpuid_present ; if so, mark
mov eax, -1 ; CPUID not present - disable its usage
jmp no_features
cpuid_present:
mov eax, 0 ; CPUID capable CPU - enable its usage.
no_features:
mov CPUIDPresent, eax ; Save the value in eax to a variable.
}
}
// A generic catch-all just to be sure...
__except (1) {
// Stop the class from trying to use CPUID again!
CPUIDPresent = false;
return false;
}
#endif
// Return true to indicate support or false to indicate lack.
return (CPUIDPresent == 0) ? true : false;
}
bool __cdecl CPUInfo::RetrieveCPUFeatures ()
{
int CPUFeatures = 0;
int CPUAdvanced = 0;
// 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 = 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 CPUFeatures, edx
mov CPUAdvanced, ebx
#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;
}
// Retrieve the features of CPU present.
Features.HasFPU = ((CPUFeatures & 0x00000001) != 0); // FPU Present --> Bit 0
Features.HasTSC = ((CPUFeatures & 0x00000010) != 0); // TSC Present --> Bit 4
Features.HasAPIC = ((CPUFeatures & 0x00000200) != 0); // APIC Present --> Bit 9
Features.HasMTRR = ((CPUFeatures & 0x00001000) != 0); // MTRR Present --> Bit 12
Features.HasCMOV = ((CPUFeatures & 0x00008000) != 0); // CMOV Present --> Bit 15
Features.HasSerial = ((CPUFeatures & 0x00040000) != 0); // Serial Present --> Bit 18
Features.HasACPI = ((CPUFeatures & 0x00400000) != 0); // ACPI Capable --> Bit 22
Features.HasMMX = ((CPUFeatures & 0x00800000) != 0); // MMX Present --> Bit 23
Features.HasSSE = ((CPUFeatures & 0x02000000) != 0); // SSE Present --> Bit 25
Features.HasSSE2 = ((CPUFeatures & 0x04000000) != 0); // SSE2 Present --> Bit 26
Features.HasThermal = ((CPUFeatures & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29
Features.HasIA64 = ((CPUFeatures & 0x40000000) != 0); // IA64 Present --> Bit 30
// Retrieve extended SSE capabilities if SSE is available.
if (Features.HasSSE) {
// Attempt to __try some SSE FP instructions.
__try {
// Perform: orps xmm0, xmm0
_asm {
_emit 0x0f
_emit 0x56
_emit 0xc0
}
// SSE FP capable processor.
Features.HasSSEFP = true;
}
// A generic catch-all just to be sure...
__except (1) {
// bad instruction - processor or OS cannot handle SSE FP.
Features.HasSSEFP = false;
}
} else {
// Set the advanced SSE capabilities to not available.
Features.HasSSEFP = false;
}
// Retrieve Intel specific extended features.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -