sqwarmed/sdk_src/public/tier0/ia32detect.h

384 lines
7.1 KiB
C++

//===== 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