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);
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLwATN3kjMyQzMtETN0ETNxEzNxkjM4ADOxAjMtgjN0UjM48CX4ADOxAjMvwFO2QTNygzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
Intel處理器的CPUID遠不止上文所述,詳情請參考Intel IA32軟體開發手冊。
在GCC中擷取CPUID資訊(相容VC) https://www.cnblogs.com/zyl910/archive/2012/08/06/getcpuid_gcc.html
=========================== End