You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
383 lines
6.7 KiB
383 lines
6.7 KiB
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//===========================================================================// |
|
#ifndef IA32DETECT_H |
|
#define IA32DETECT_H |
|
|
|
#ifdef COMPILER_MSVC64 |
|
extern "C" void __cpuid(int* CPUInfo, int InfoType); |
|
#pragma intrinsic (__cpuid) |
|
#endif |
|
/* |
|
This section from http://iss.cs.cornell.edu/ia32.htm |
|
|
|
|
|
*/ |
|
typedef unsigned bit; |
|
|
|
enum CPUVendor |
|
{ |
|
INTEL, |
|
AMD, |
|
UNKNOWN_VENDOR |
|
}; |
|
class ia32detect |
|
{ |
|
public: |
|
|
|
enum type_t |
|
{ |
|
type_OEM, |
|
type_OverDrive, |
|
type_Dual, |
|
type_reserved |
|
}; |
|
|
|
enum brand_t |
|
{ |
|
brand_na, |
|
brand_Celeron, |
|
brand_PentiumIII, |
|
brand_PentiumIIIXeon, |
|
brand_reserved1, |
|
brand_reserved2, |
|
brand_PentiumIIIMobile, |
|
brand_reserved3, |
|
brand_Pentium4, |
|
brand_invalid |
|
}; |
|
|
|
# pragma pack(push, 1) |
|
|
|
struct version_t |
|
{ |
|
bit Stepping : 4; |
|
bit Model : 4; |
|
bit Family : 4; |
|
bit Type : 2; |
|
bit Reserved1 : 2; |
|
bit XModel : 4; |
|
bit XFamily : 8; |
|
bit Reserved2 : 4; |
|
}; |
|
|
|
struct misc_t |
|
{ |
|
byte Brand; |
|
byte CLFLUSH; |
|
byte Reserved; |
|
byte APICId; |
|
}; |
|
|
|
struct feature_t |
|
{ |
|
bit FPU : 1; // Floating Point Unit On-Chip |
|
bit VME : 1; // Virtual 8086 Mode Enhancements |
|
bit DE : 1; // Debugging Extensions |
|
bit PSE : 1; // Page Size Extensions |
|
bit TSC : 1; // Time Stamp Counter |
|
bit MSR : 1; // Model Specific Registers |
|
bit PAE : 1; // Physical Address Extension |
|
bit MCE : 1; // Machine Check Exception |
|
bit CX8 : 1; // CMPXCHG8 Instruction |
|
bit APIC : 1; // APIC On-Chip |
|
bit Reserved1 : 1; |
|
bit SEP : 1; // SYSENTER and SYSEXIT instructions |
|
bit MTRR : 1; // Memory Type Range Registers |
|
bit PGE : 1; // PTE Global Bit |
|
bit MCA : 1; // Machine Check Architecture |
|
bit CMOV : 1; // Conditional Move Instructions |
|
bit PAT : 1; // Page Attribute Table |
|
bit PSE36 : 1; // 32-bit Page Size Extension |
|
bit PSN : 1; // Processor Serial Number |
|
bit CLFSH : 1; // CLFLUSH Instruction |
|
bit Reserved2 : 1; |
|
bit DS : 1; // Debug Store |
|
bit ACPI : 1; // Thermal Monitor and Software Controlled Clock Facilities |
|
bit MMX : 1; // Intel MMX Technology |
|
bit FXSR : 1; // FXSAVE and FXRSTOR Instructions |
|
bit SSE : 1; // Intel SSE Technology |
|
bit SSE2 : 1; // Intel SSE2 Technology |
|
bit SS : 1; // Self Snoop |
|
bit HTT : 1; // Hyper Threading |
|
bit TM : 1; // Thermal Monitor |
|
bit Reserved3 : 1; |
|
bit PBE : 1; // Pending Brk. EN. |
|
}; |
|
|
|
# pragma pack(pop) |
|
|
|
tstring vendor_name; |
|
CPUVendor vendor; |
|
tstring brand; |
|
version_t version; |
|
misc_t misc; |
|
feature_t feature; |
|
byte *cache; |
|
|
|
ia32detect () |
|
{ |
|
|
|
cache = 0; |
|
uint32 m = init0(); |
|
|
|
uint32 *d = new uint32[m * 4]; |
|
|
|
for (uint32 i = 1; i <= m; i++) |
|
{ |
|
|
|
#ifdef COMPILER_MSVC64 |
|
__cpuid((int *) (d + (i-1) * 4), i); |
|
|
|
#else |
|
uint32 *t = d + (i - 1) * 4; |
|
__asm |
|
{ |
|
mov eax, i; |
|
mov esi, t; |
|
|
|
cpuid; |
|
|
|
mov dword ptr [esi + 0x0], eax; |
|
mov dword ptr [esi + 0x4], ebx; |
|
mov dword ptr [esi + 0x8], ecx; |
|
mov dword ptr [esi + 0xC], edx; |
|
} |
|
#endif |
|
} |
|
|
|
if (m >= 1) |
|
init1(d); |
|
|
|
if (m >= 2) |
|
init2(d[4] & 0xFF); |
|
|
|
delete [] d; |
|
|
|
init0x80000000(); |
|
|
|
|
|
//----------------------------------------------------------------------- |
|
// Get the vendor of the processor |
|
//----------------------------------------------------------------------- |
|
if (_tcscmp(vendor_name.c_str(), _T("GenuineIntel")) == 0) |
|
{ |
|
vendor = INTEL; |
|
|
|
} |
|
else if (_tcscmp(vendor_name.c_str(), _T("AuthenticAMD")) == 0) |
|
{ |
|
vendor = AMD; |
|
|
|
} |
|
else |
|
{ |
|
vendor = UNKNOWN_VENDOR; |
|
} |
|
} |
|
|
|
const tstring version_text () const |
|
{ |
|
tchar b[128]; |
|
|
|
_stprintf(b, _T("%d.%d.%d %s XVersion(%d.%d)"), |
|
version.Family, version.Model, version.Stepping, type_text(), version.XFamily, version.XModel); |
|
|
|
return tstring(b); |
|
} |
|
|
|
protected: |
|
|
|
const tchar * type_text () const |
|
{ |
|
static const tchar *text[] = |
|
{ |
|
_T("Intel OEM Processor"), |
|
_T("Intel OverDrive(R) Processor"), |
|
_T("Intel Dual Processor"), |
|
_T("reserved") |
|
}; |
|
|
|
return text[version.Type]; |
|
} |
|
|
|
const tstring brand_text () const |
|
{ |
|
static const tchar *text[] = |
|
{ |
|
_T("n/a"), |
|
_T("Celeron"), |
|
_T("Pentium III"), |
|
_T("Pentium III Xeon"), |
|
_T("reserved (4)"), |
|
_T("reserved (5)"), |
|
_T("Pentium III Mobile"), |
|
_T("reserved (7)"), |
|
_T("Pentium 4") |
|
}; |
|
|
|
if (misc.Brand < brand_invalid) |
|
return tstring(text[misc.Brand]); |
|
else |
|
{ |
|
tchar b[32]; |
|
|
|
_stprintf(b, _T("Brand %d (Update)"), misc.Brand); |
|
|
|
return tstring(b); |
|
} |
|
} |
|
|
|
private: |
|
|
|
uint32 init0 () |
|
{ |
|
uint32 m; |
|
|
|
#ifdef COMPILER_MSVC64 |
|
int data[4]; |
|
tchar * s1; |
|
|
|
s1 = (tchar *) &data[1]; |
|
s1[12] = '\0'; |
|
__cpuid(data, 0); |
|
m = data[0]; |
|
vendor_name = s1; |
|
#else |
|
tchar s1[13]; |
|
|
|
s1[12] = '\0'; |
|
__asm |
|
{ |
|
xor eax, eax; |
|
cpuid; |
|
mov m, eax; |
|
mov dword ptr s1 + 0, ebx; |
|
mov dword ptr s1 + 4, edx; |
|
mov dword ptr s1 + 8, ecx; |
|
} |
|
vendor_name = s1; |
|
#endif |
|
return m; |
|
} |
|
|
|
void init1 (uint32 *d) |
|
{ |
|
version = *(version_t *)&d[0]; |
|
misc = *(misc_t *)&d[1]; |
|
feature = *(feature_t *)&d[3]; |
|
} |
|
|
|
void process2 (uint32 d, bool c[]) |
|
{ |
|
if ((d & 0x80000000) == 0) |
|
for (int i = 0; i < 32; i += 8) |
|
c[(d >> i) & 0xFF] = true; |
|
} |
|
|
|
void init2 (byte count) |
|
{ |
|
uint32 d[4]; |
|
bool c[256]; |
|
|
|
for (int ci1 = 0; ci1 < 256; ci1++) |
|
c[ci1] = false; |
|
|
|
for (int i = 0; i < count; i++) |
|
{ |
|
#ifdef COMPILER_MSVC64 |
|
__cpuid((int *) d, 2); |
|
#else |
|
__asm |
|
{ |
|
mov eax, 2; |
|
lea esi, d; |
|
cpuid; |
|
mov [esi + 0x0], eax; |
|
mov [esi + 0x4], ebx; |
|
mov [esi + 0x8], ecx; |
|
mov [esi + 0xC], edx; |
|
} |
|
#endif |
|
|
|
if (i == 0) |
|
d[0] &= 0xFFFFFF00; |
|
|
|
process2(d[0], c); |
|
process2(d[1], c); |
|
process2(d[2], c); |
|
process2(d[3], c); |
|
} |
|
|
|
int m = 0; |
|
|
|
for (int ci2 = 0; ci2 < 256; ci2++) |
|
if (c[ci2]) |
|
m++; |
|
|
|
cache = new byte[m]; |
|
|
|
m = 0; |
|
|
|
for (int ci3 = 1; ci3 < 256; ci3++) |
|
if (c[ci3]) |
|
cache[m++] = ci3; |
|
|
|
cache[m] = 0; |
|
} |
|
|
|
void init0x80000000 () |
|
{ |
|
uint32 m; |
|
|
|
#ifdef COMPILER_MSVC64 |
|
int data[4]; |
|
__cpuid(data, 0x80000000); |
|
m = data[0]; |
|
#else |
|
__asm |
|
{ |
|
mov eax, 0x80000000; |
|
cpuid; |
|
mov m, eax |
|
} |
|
#endif |
|
|
|
if ((m & 0x80000000) != 0) |
|
{ |
|
uint32 *d = new uint32[(m - 0x80000000) * 4]; |
|
|
|
for (uint32 i = 0x80000001; i <= m; i++) |
|
{ |
|
uint32 *t = d + (i - 0x80000001) * 4; |
|
|
|
#ifdef COMPILER_MSVC64 |
|
__cpuid((int *) (d + (i - 0x80000001) * 4), i); |
|
#else |
|
__asm |
|
{ |
|
mov eax, i; |
|
mov esi, t; |
|
cpuid; |
|
mov dword ptr [esi + 0x0], eax; |
|
mov dword ptr [esi + 0x4], ebx; |
|
mov dword ptr [esi + 0x8], ecx; |
|
mov dword ptr [esi + 0xC], edx; |
|
} |
|
#endif |
|
} |
|
|
|
if (m >= 0x80000002) |
|
brand = (tchar *)(d + 4); |
|
|
|
// note the assignment to brand above does a copy, we need to delete |
|
delete[] d; |
|
} |
|
} |
|
}; |
|
|
|
#endif // IA32DETECT_H
|
|
|