//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #ifndef IA32DETECT_H #define IA32DETECT_H #ifdef PLATFORM_WINDOWS_PC #include #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