Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CPUID implementations in C++

I would like to know if somebody around here has some good examples of a C++ CPUID implementation that can be referenced from any of the managed .net languages.

Also, should this not be the case, should I be aware of certain implementation differences between X86 and X64?

I would like to use CPUID to get info on the machine my software is running on (crashreporting etc...) and I want to keep everything as widely compatible as possible.

Primary reason I ask is because I am a total noob when it comes to writing what will probably be all machine instructions though I have basic knowledge about CPU registers and so on...

Before people start telling me to Google: I found some examples online, but usually they were not meant to allow interaction from managed code and none of the examples were aimed at both X86 and X64. Most examples appeared to be X86 specific.

like image 894
Kris Avatar asked Nov 03 '09 09:11

Kris


2 Answers

Accessing raw CPUID information is actually very easy, here is a C++ class for that which works in Windows, Linux and OSX:

#ifndef CPUID_H #define CPUID_H  #ifdef _WIN32 #include <limits.h> #include <intrin.h> typedef unsigned __int32  uint32_t;  #else #include <stdint.h> #endif  class CPUID {   uint32_t regs[4];  public:   explicit CPUID(unsigned i) { #ifdef _WIN32     __cpuid((int *)regs, (int)i);  #else     asm volatile       ("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])        : "a" (i), "c" (0));     // ECX is set to zero for CPUID function 4 #endif   }    const uint32_t &EAX() const {return regs[0];}   const uint32_t &EBX() const {return regs[1];}   const uint32_t &ECX() const {return regs[2];}   const uint32_t &EDX() const {return regs[3];} };  #endif // CPUID_H 

To use it just instantiate an instance of the class, load the CPUID instruction you are interested in and examine the registers. For example:

#include "CPUID.h"  #include <iostream> #include <string>  using namespace std;  int main(int argc, char *argv[]) {   CPUID cpuID(0); // Get CPU vendor    string vendor;   vendor += string((const char *)&cpuID.EBX(), 4);   vendor += string((const char *)&cpuID.EDX(), 4);   vendor += string((const char *)&cpuID.ECX(), 4);    cout << "CPU vendor = " << vendor << endl;    return 0; } 

This Wikipedia page tells you how to use CPUID: http://en.wikipedia.org/wiki/CPUID

EDIT: Added #include <intrin.h> for Windows, per comments.

like image 185
jcoffland Avatar answered Sep 22 '22 03:09

jcoffland


See this MSDN article about __cpuid.

There is a comprehensive sample that compiles with Visual Studio 2005 or better. For Visual Studio 6, you can use this instead of the compiler instrinsic __cpuid:

void __cpuid(int CPUInfo[4], int InfoType) {  __asm    {      mov    esi, CPUInfo      mov    eax, InfoType      xor    ecx, ecx        cpuid        mov    dword ptr [esi +  0], eax      mov    dword ptr [esi +  4], ebx        mov    dword ptr [esi +  8], ecx        mov    dword ptr [esi + 12], edx     } } 

For Visual Studio 2005, you can use this instead of the compiler instrinsic __cpuidex:

void __cpuidex(int CPUInfo[4], int InfoType, int ECXValue) {  __asm    {      mov    esi, CPUInfo      mov    eax, InfoType      mov    ecx, ECXValue      cpuid        mov    dword ptr [esi +  0], eax      mov    dword ptr [esi +  4], ebx        mov    dword ptr [esi +  8], ecx        mov    dword ptr [esi + 12], edx     } } 
like image 31
Jabberwocky Avatar answered Sep 26 '22 03:09

Jabberwocky