C语言调用Intel处理器CPUID指令的实例
C语言调用Intel处理器CPUID指令的实例
来源 https://blog.csdn.net/subfate/article/details/50789905
在Linux环境下,使用C语言内嵌汇编的手段使用CPUID指令,进而在高级语言层面上看到获取的信息。
实现文件cpuid.c代码如下:
struct cpuid_result { uint32_t eax; uint32_t ebx; uint32_t ecx; uint32_t edx; }; /* * Generic CPUID function */ static inline struct cpuid_result cpuid(unsigned int op) { struct cpuid_result result; __asm volatile( "mov %%ebx, %%edi;" "cpuid;" "mov %%ebx, %%esi;" "mov %%edi, %%ebx;" : "=a" (result.eax), "=S" (result.ebx), "=c" (result.ecx), "=d" (result.edx) : "0" (op) : "edi"); return result; } static inline unsigned int cpuid_eax(unsigned int op) { //unsigned int eax, ebx, ecx, edx; struct cpuid_result regs; regs = cpuid(op); return regs.eax; } void get_cpu_vendor(char* cpu_vendor, unsigned int* cpuid_level) { unsigned int cpuid_op = 0x00000000; char vendor_name[16] = {'\0'}; struct cpuid_result result; unsigned int level = 0; vendor_name[0] = '\0'; /* Unset */ result = cpuid(cpuid_op); // eax为0表示读取vendor id,一共12字节,依次在ebx、edx、ecx。 level = result.eax; vendor_name[0] = (result.ebx >> 0) & 0xff; vendor_name[1] = (result.ebx >> 8) & 0xff; vendor_name[2] = (result.ebx >> 16) & 0xff; vendor_name[3] = (result.ebx >> 24) & 0xff; vendor_name[4] = (result.edx >> 0) & 0xff; vendor_name[5] = (result.edx >> 8) & 0xff; vendor_name[6] = (result.edx >> 16) & 0xff; vendor_name[7] = (result.edx >> 24) & 0xff; vendor_name[8] = (result.ecx >> 0) & 0xff; vendor_name[9] = (result.ecx >> 8) & 0xff; vendor_name[10] = (result.ecx >> 16) & 0xff; vendor_name[11] = (result.ecx >> 24) & 0xff; vendor_name[12] = '\0'; strcpy(cpu_vendor, vendor_name); *cpuid_level = level; } void get_cpu_id(char* cpu_id, unsigned int* cpu_sign) { unsigned int cpuid_op = 0x00000001; struct cpuid_result result; unsigned int sign = 0, id = 0; unsigned int tmp = 0; result = cpuid(cpuid_op); sign = result.eax; id = result.edx; sprintf(cpu_id, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", (sign >> 0) & 0xff, (sign >> 8) & 0xff, (sign >> 16) & 0xff, (sign >> 24) & 0xff, (id >> 0) & 0xff, (id >> 8) & 0xff, (id >> 16) & 0xff, (id >> 24) & 0xff); *cpu_sign = sign; } struct cpuinfo_x86 { uint8_t x86; /* CPU family */ uint8_t x86_vendor; /* CPU vendor */ uint8_t x86_model; /* CPU model */ uint8_t x86_step; /* CPU stepping */ }; // 参考IA32开发手册第2卷第3章。CPUID exa==0x01的图3-6 static inline void get_fms(struct cpuinfo_x86 *c, uint32_t tfms) { c->x86 = (tfms >> 8) & 0xf; c->x86_model = (tfms >> 4) & 0xf; c->x86_step = tfms & 0xf; if (c->x86 == 0xf) c->x86 += (tfms >> 20) & 0xff; if (c->x86 >= 0x6) c->x86_model += ((tfms >> 16) & 0xF) << 4; } void get_cpu_fms(unsigned int* family, unsigned int* model, unsigned int* stepping) { unsigned int cpuid_op = 0x00000001; struct cpuinfo_x86 c; unsigned int ver = 0; ver = cpuid_eax(cpuid_op); get_fms(&c, ver); *family = c.x86; *model = c.x86_model; *stepping = c.x86_step; } void get_cpu_name(char* processor_name) { unsigned int cpuid_op = 0x80000002; struct cpuid_result regs; char temp_processor_name[49]; char* processor_name_start; unsigned int *name_as_ints = (unsigned int *)temp_processor_name; unsigned int i; /* 用cpuid指令,eax传入0x80000002/0x80000003/0x80000004, 共3个,每个4个寄存器,每个寄存器4字节,故一共48字节。 参考IA32开发手册第2卷第3章。 */ for (i = 0; i < 3; i++) { regs = cpuid(cpuid_op + i); name_as_ints[i * 4 + 0] = regs.eax; name_as_ints[i * 4 + 1] = regs.ebx; name_as_ints[i * 4 + 2] = regs.ecx; name_as_ints[i * 4 + 3] = regs.edx; } temp_processor_name[49] = '\0'; // 最后的字节为0,结束 /* Skip leading spaces. */ processor_name_start = temp_processor_name; while (*processor_name_start == ' ') processor_name_start++; memset(processor_name, 0, 49); strcpy(processor_name, processor_name_start); } void get_address_bits(unsigned int* linear, unsigned int* physical) { unsigned int cpuid_op = 0x80000008; unsigned int tmp = 0; tmp = cpuid_eax(cpuid_op); *linear = (tmp >> 8) & 0xff; *physical = (tmp >> 0) & 0xff; }
主函数实现代码如下:
void get_hw_cpu(void) { char buffer[49] = { '\0' }; unsigned int num = 0; unsigned int f = 0, m = 0, s = 0; unsigned int phy_bits = 0, vir_bits = 0; memset((void *)buffer, '\0', sizeof(buffer)); num = 0; get_cpu_vendor(buffer, &num); fprintf(stdout, "vendor_id \t: %s\n", buffer); fprintf(stdout, "cpuid level \t: %u\n", num); memset((void *)buffer, '\0', sizeof(buffer)); num = 0; get_cpu_id(buffer, &num); fprintf(stdout, "cpu_id serial \t: %s\n", buffer); fprintf(stdout, "cpuid sign \t: %u\n", num); memset((void *)buffer, '\0', sizeof(buffer)); get_cpu_name(buffer); fprintf(stdout, "model name \t: %s\n", buffer); get_cpu_fms(&f, &m, &s); fprintf(stdout, "cpu family \t: %u(0x%0X)\n", f, f); fprintf(stdout, "cpu model \t: %u(0x%0X)\n", m, m); fprintf(stdout, "cpu stepping \t: %u(0x%0X)\n", s, s); get_address_bits(&vir_bits, &phy_bits); fprintf(stdout, "address sizes \t: %u bits physical - %u bits virtual\n", phy_bits, vir_bits); }
Intel处理器的CPUID远不止上文所述,详情请参考Intel IA32软件开发手册。
在GCC中获取CPUID信息(兼容VC) https://www.cnblogs.com/zyl910/archive/2012/08/06/getcpuid_gcc.html
=========================== End