378 lines
6.7 KiB
C++
378 lines
6.7 KiB
C++
//========= 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
|