|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef IA32DETECT_H
#define IA32DETECT_H
#ifdef PLATFORM_WINDOWS_PC
#include <intrin.h>
#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;
int data[4 + 1]; tchar * s1;
s1 = (tchar *) &data[1]; __cpuid(data, 0); data[4] = 0; // Returns something like this:
// data[0] = 0x0000000b
// data[1] = 0x756e6547 Genu
// data[2] = 0x6c65746e ntel
// data[3] = 0x49656e69 ineI
// data[4] = 0x00000000
m = data[0]; int t = data[2]; data[2] = data[3]; data[3] = t; vendor_name = s1; 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
|