Intel x86_64使用cpuid指令获取CPU信息

本文阅读 2 分钟
首页 Linux,系统 正文

写了一个简易版的Linux 系统下获取cpu的信息,后面会完善,目前先获取一些最基本的处理器信息,代码主要参考Linux内核源码,基本是移植过来的。。。。。。 在这篇文章我介绍过cpuid指令: Intel x86_64 CPUID指令介绍 这里就不介绍那么详细啦。

1.1 cpuid指令功能

主要用来获取处理器身份和特征信息。 img

1.2 cpuid指令代码

我在应用层使用内嵌汇编 asm volatile,调用cpuid指令,根据输入不同的值,将处理器的信息作为返回值写在eax、ebx、ecx、edx中。

static void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
{ 
    *eax = op;
    *ecx = 0;
    asm volatile("cpuid"            //内嵌汇编指令 cpuid
        : "=a" (*eax),                //输出参数
          "=b" (*ebx),
          "=c" (*ecx),
          "=d" (*edx)
        : "0" (*eax), "2" (*ecx)    //输入参数
        : "memory");
}

2.1 输入参数为0H

当输入参数为0H时,用来获取厂商标识字符串信息,如Intel,AMD等等。 Intel:“GenuineIntel” AMD:“AuthenticAMD” img

img

代码如下:

int    cpuid_level;
char x86_vendor_id[16] = { 0};
cpuid(0x00000000, (unsigned int *)&cpuid_level,
                    (unsigned int *)&x86_vendor_id[0],
                  (unsigned int *)&x86_vendor_id[8],
                  (unsigned int *)&x86_vendor_id[4]);

这样供应商的信息就存放在x86_vendor_id数组中了。

2.2 输入参数为01H

当输入参数为01H时,在返回值EAX寄存器中就可以获得处理器的 DisplayFamily_DisplayModel,DisplayFamily_DisplayModel 信息通常用以识别特定的处理器。 img img

代码如下(示例):

unsigned int x86_family(unsigned int sig)
{ 
    unsigned int x86;

    x86 = (sig >> 8) & 0xf;

    if (x86 == 0xf)
        x86 += (sig >> 20) & 0xff;

    return x86;
}

unsigned int x86_model(unsigned int sig)
{ 
    unsigned int fam, model;

    fam = x86_family(sig);

    model = (sig >> 4) & 0xf;

    if (fam >= 0x6)
        model += ((sig >> 16) & 0xf) << 4;

    return model;
}

unsigned int x86_stepping(unsigned int sig)
{ 
    return sig & 0xf;
}

2.3 输入参数为0x80000002H

当输入参数为0x80000002H,0x80000003H,0x80000004H时用来获取处理器品牌字符串,如: img img

static void get_model_name()
{ 
    char x86_model_id[64] = { 0};
    unsigned int *v = (unsigned int *)x86_model_id;
    cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
    cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
    cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
    x86_model_id[48] = 0;
}

2.4 输入参数为0x80000008H

当输入参数为0x80000008H时,获取物理地址大小信息和虚拟地址信息大小。如: img

img

void get_cpu_address_sizes()
{ 
    unsigned int eax, ebx, ecx, edx;
    cpuid(0x80000008, &eax, &ebx, &ecx, &edx);

    x86_virt_bits = (eax >> 8) & 0xff;
    x86_phys_bits = eax & 0xff;
}
#include <stdio.h>
#include <string.h>

struct cpuinfo_x86 { 
    unsigned char            x86;            
    unsigned char            x86_vendor;        
    unsigned char            x86_model;
    unsigned char            x86_stepping;
    int                         cpuid_level;
    char                    x86_vendor_id[16];
    char                    x86_model_id[64];
    int                        x86_cache_alignment;    
    unsigned short            x86_clflush_size;
    unsigned char            x86_virt_bits;
    unsigned char            x86_phys_bits;
    unsigned char            x86_cache_bits;
};


static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
                             unsigned int *ecx, unsigned int *edx)
{ 
    *eax = op;
    *ecx = 0;

    asm volatile("cpuid"
        : "=a" (*eax),
          "=b" (*ebx),
          "=c" (*ecx),
          "=d" (*edx)
        : "0" (*eax), "2" (*ecx)
        : "memory");
}

unsigned int x86_family(unsigned int sig)
{ 
    unsigned int x86;

    x86 = (sig >> 8) & 0xf;

    if (x86 == 0xf)
        x86 += (sig >> 20) & 0xff;

    return x86;
}

unsigned int x86_model(unsigned int sig)
{ 
    unsigned int fam, model;

    fam = x86_family(sig);

    model = (sig >> 4) & 0xf;

    if (fam >= 0x6)
        model += ((sig >> 16) & 0xf) << 4;

    return model;
}

unsigned int x86_stepping(unsigned int sig)
{ 
    return sig & 0xf;
}


static void get_model_name(struct cpuinfo_x86 *c)
{ 
    unsigned int *v = (unsigned int *)c->x86_model_id;
    cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
    cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
    cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
    c->x86_model_id[48] = 0;
}

void cpu_detect(struct cpuinfo_x86 *c)
{ 
    /* Get vendor name */
    memset(c->x86_vendor_id, 0, sizeof(c->x86_vendor_id));
    cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
          (unsigned int *)&c->x86_vendor_id[0],
          (unsigned int *)&c->x86_vendor_id[8],
          (unsigned int *)&c->x86_vendor_id[4]);

    c->x86 = 4;
    /* Intel-defined flags: level 0x00000001 */
    if (c->cpuid_level >= 0x00000001) { 
        unsigned int junk, tfms, cap0, misc;

        cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
        c->x86        = x86_family(tfms);
        c->x86_model    = x86_model(tfms);
        c->x86_stepping    = x86_stepping(tfms);

        if (cap0 & (1<<19)) { 
            c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
            c->x86_cache_alignment = c->x86_clflush_size;
        }
    }
}

void get_cpu_address_sizes(struct cpuinfo_x86 *c)
{ 
    unsigned int eax, ebx, ecx, edx;

    cpuid(0x80000008, &eax, &ebx, &ecx, &edx);

    c->x86_virt_bits = (eax >> 8) & 0xff;
    c->x86_phys_bits = eax & 0xff;

    c->x86_cache_bits = c->x86_phys_bits;
}

int main()
{ 
    unsigned int eax = 0;
    unsigned int ebx = 0;
    unsigned int ecx = 0;
    unsigned int edx = 0;

    struct cpuinfo_x86 _cpuinfo_x86;

    cpuid(0, &eax, &ebx, &ecx, &edx);
    printf("EBX ← %x (“Genu”)EDX ← %x (“ineI”) ECX ← %x (“ntel”)\n", ebx, edx ,ecx);

    get_cpu_address_sizes(&_cpuinfo_x86);
    cpu_detect(&_cpuinfo_x86);
    get_model_name(&_cpuinfo_x86);

    printf("Address sizes: phys_bits = %d virt_bits = %d\n", _cpuinfo_x86.x86_phys_bits,  _cpuinfo_x86.x86_virt_bits);
    printf("Vendor Id= %s\n", _cpuinfo_x86.x86_vendor_id);
    printf("cpuid level = %d\n", _cpuinfo_x86.cpuid_level);
    printf("CPU family = %d\n", _cpuinfo_x86.x86);
    printf("Model = %d\n", _cpuinfo_x86.x86_model);
    printf("Stepping = %d\n", _cpuinfo_x86.x86_stepping);
    printf("Model name = %s\n", _cpuinfo_x86.x86_model_id);
    printf("clflush_size = %d\n", _cpuinfo_x86.x86_clflush_size);
    printf("cache_alignment = %d\n", _cpuinfo_x86.x86_cache_alignment);

     return 0;

}

看看结果: img 与lscpu显示的消息一致(也可以用cat /proc/cpuinfo查看): img

主要是参考了 Linux内核源码 5.13.0中获取CPU信息的代码:

arch/x86/kernel/cpu/common.c
 arch/x86/include/asm/processor.h

实验环境: vmware + ubuntu 20.04

Linux内核源码 5.13.0 Intel官方手册 vol2

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/weixin_45030965/article/details/124461693
-- 展开阅读全文 --
BUUCTF Web [极客大挑战 2019]Knife
« 上一篇 06-24
安全面试之XSS(跨站脚本攻击)
下一篇 » 07-24

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复