Getting the machine serial number and CPU ID using C/C++ in Linux

后端 未结 5 614
[愿得一人]
[愿得一人] 2020-11-30 01:01

How can I get the machine serial number and CPU ID in a Linux system?

Sample code is highly appreciated.

相关标签:
5条回答
  • 2020-11-30 01:22
    #include <stdio.h>
    
    void getPSN(char *PSN)
    {
        int varEAX, varEBX, varECX, varEDX;
        char str[9];
        //%eax=1 gives most significant 32 bits in eax 
        __asm__ __volatile__ ("cpuid"   : "=a" (varEAX), "=b" (varEBX), "=c" (varECX), "=d" (varEDX) : "a" (1));
        sprintf(str, "%08X", varEAX); //i.e. XXXX-XXXX-xxxx-xxxx-xxxx-xxxx
        sprintf(PSN, "%C%C%C%C-%C%C%C%C", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7]);
        //%eax=3 gives least significant 64 bits in edx and ecx [if PN is enabled]
        __asm__ __volatile__ ("cpuid"   : "=a" (varEAX), "=b" (varEBX), "=c" (varECX), "=d" (varEDX) : "a" (3));
        sprintf(str, "%08X", varEDX); //i.e. xxxx-xxxx-XXXX-XXXX-xxxx-xxxx
        sprintf(PSN, "%s-%C%C%C%C-%C%C%C%C", PSN, str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7]);
        sprintf(str, "%08X", varECX); //i.e. xxxx-xxxx-xxxx-xxxx-XXXX-XXXX
        sprintf(PSN, "%s-%C%C%C%C-%C%C%C%C", PSN, str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7]);
    }
    
    int main()
    {
         char PSN[30]; //24 Hex digits, 5 '-' separators, and a '\0'
         getPSN(PSN);
        printf("%s\n", PSN); //compare with: lshw | grep serial:
         return 0;
    }
    
    0 讨论(0)
  • 2020-11-30 01:23

    There is a cpuinfo.h include in GCC. It is safe, use it.

    Sample (I have GCC 4.7+ and feel happy of using "auto" here):

    #include <cpuid.h>
    #include <iostream>
    #include <map>
    #include <string>
    
    using namespace std;
    
    struct CPUVendorID {
        unsigned int ebx;
        unsigned int edx;
        unsigned int ecx;
    
        string toString() const {
            return string(reinterpret_cast<const char *>(this), 12);
        }
    };
    
    int main() {
        unsigned int level = 0;
        unsigned int eax = 0;
        unsigned int ebx;
        unsigned int ecx;
        unsigned int edx;
    
        __get_cpuid(level, &eax, &ebx, &ecx, &edx);
    
        CPUVendorID vendorID { .ebx = ebx, .edx = edx, .ecx = ecx };
    
        map<string, string> vendorIdToName;
        vendorIdToName["GenuineIntel"] = "Intel";
        vendorIdToName["AuthenticAMD"] = "AMD";
        vendorIdToName["CyrixInstead"] = "Cyrix";
        vendorIdToName["CentaurHauls"] = "Centaur";
        vendorIdToName["SiS SiS SiS "] = "SiS";
        vendorIdToName["NexGenDriven"] = "NexGen";
        vendorIdToName["GenuineTMx86"] = "Transmeta";
        vendorIdToName["RiseRiseRise"] = "Rise";
        vendorIdToName["UMC UMC UMC "] = "UMC";
        vendorIdToName["Geode by NSC"] = "National Semiconductor";
    
        string vendorIDString = vendorID.toString();
    
        auto it = vendorIdToName.find(vendorIDString);
        string vendorName = (it == vendorIdToName.end()) ? "Unknown" : it->second;
    
        cout << "Max instruction ID: " << eax << endl;
        cout << "Vendor ID: " << vendorIDString << endl;
        cout << "Vendor name: " << vendorName << endl;
    }
    

    Output:

    $ make
    g++ --std=c++11 main.cc -o cpuid
    $ ./cpuid 
    Max instruction ID: 6
    Vendor ID: GenuineIntel
    Vendor name: Intel
    
    0 讨论(0)
  • 2020-11-30 01:25

    This program will help you run Linux commands programmatically:

    char* GetSystemOutput(char* cmd)
    {
        int buff_size = 32;
        char* buff = new char[buff_size];
    
        char* ret = NULL;
        string str = "";
    
        int fd[2];
        int old_fd[3];
        pipe(fd);
    
        old_fd[0] = dup(STDIN_FILENO);
        old_fd[1] = dup(STDOUT_FILENO);
        old_fd[2] = dup(STDERR_FILENO);
    
        int pid = fork();
        switch(pid)
        {
            case 0:
                   close(fd[0]);
                   close(STDOUT_FILENO);
                   close(STDERR_FILENO);
                   dup2(fd[1], STDOUT_FILENO);
                   dup2(fd[1], STDERR_FILENO);
                   system(cmd);
                   //execlp((const char*)cmd, cmd,0);
                   close (fd[1]);
                   exit(0);
                   break;
    
            case -1:
                   cerr << "GetSystemOutput/fork() error\n" << endl;
                   exit(1);
    
            default:
                   close(fd[1]);
                   dup2(fd[0], STDIN_FILENO);
    
                   int rc = 1;
                   while (rc > 0)
                   {
                       rc = read(fd[0], buff, buff_size);
                       str.append(buff, rc);
                       //memset(buff, 0, buff_size);
                   }
    
                   ret = new char [strlen((char*)str.c_str())];
    
                   strcpy(ret, (char*)str.c_str());
    
                   waitpid(pid, NULL, 0);
                   close(fd[0]);
        }
    
        dup2(STDIN_FILENO, old_fd[0]);
        dup2(STDOUT_FILENO, old_fd[1]);
        dup2(STDERR_FILENO, old_fd[2]);
    
        return ret;
    }
    

    API usage: GetSystemOutput("/usr/bin/lsb_release -a")

    And following the commands:

    cat /proc/cpuinfo = tells you CPU information
    
    0 讨论(0)
  • 2020-11-30 01:27

    The Informations about the processor you could extract from /proc/cpuinfo.

    To get the Serial Number you should have a look at dmidecode. I didn't look in there right now, but dmidecode is able to show you the serial number, so i would start there.

    0 讨论(0)
  • 2020-11-30 01:30

    Here is what the Linux kernel seems to use:

    static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
                                    unsigned int *ecx, unsigned int *edx)
    {
            /* ecx is often an input as well as an output. */
            asm volatile("cpuid"
                : "=a" (*eax),
                  "=b" (*ebx),
                  "=c" (*ecx),
                  "=d" (*edx)
                : "0" (*eax), "2" (*ecx));
    }
    

    which one then can use as e.g.:

    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
      unsigned eax, ebx, ecx, edx;
    
      eax = 1; /* processor info and feature bits */
      native_cpuid(&eax, &ebx, &ecx, &edx);
    
      printf("stepping %d\n", eax & 0xF);
      printf("model %d\n", (eax >> 4) & 0xF);
      printf("family %d\n", (eax >> 8) & 0xF);
      printf("processor type %d\n", (eax >> 12) & 0x3);
      printf("extended model %d\n", (eax >> 16) & 0xF);
      printf("extended family %d\n", (eax >> 20) & 0xFF);
    
      /* EDIT */
      eax = 3; /* processor serial number */
      native_cpuid(&eax, &ebx, &ecx, &edx);
    
      /** see the CPUID Wikipedia article on which models return the serial 
          number in which registers. The example here is for 
          Pentium III */
      printf("serial number 0x%08x%08x\n", edx, ecx);
    
    }
    

    Where a good reference on how to use the CPUID instruction is in this Wikipedia article.

    EDIT The Wikipedia article says that the serial number was introduced with the Pentium III but was not anymore implemented in later models due to privacy concerns. On a Linux system you can check for the presence of this feature (PSN bit) by doing:

    grep -i --color psn /proc/cpuinfo
    

    if this does not show anything, your system does not support a processor serial number.

    0 讨论(0)
提交回复
热议问题