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

 

posted @ 2018-08-29 11:43  lsgxeva  阅读(2618)  评论(0编辑  收藏  举报