在之前写的文章中,仅简单讲了一下CPUID指令,通过该指令可以获取很多和处理器相关的信息,如处理器的系列、型号、内存地址是多少位,等等。本文在Linux环境下,使用C语言内嵌汇编的手段使用CPUID指令,进而在高级语言层面上看到获取的信息。

头文件cpuid.h代码如下 :

/** 假设执行程序所在PC是支持CPUID指令的
*/#ifndef _CPUID_H
#define _CPUID_H#include <stdint.h>void get_cpu_vendor(char* cpu_vendor, int* cpuid_level);void get_cpu_version(unsigned int* version);void get_cpu_fms(int* family, int* model, int* stepping);void get_cpu_name(char *processor_name);void get_address_bits(int* linear, int* physical);struct cpuid_result {uint32_t eax;uint32_t ebx;uint32_t ecx;uint32_t edx;
};/** Generic CPUID function*/
static inline struct cpuid_result cpuid(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)
{struct cpuid_result regs;regs = cpuid(op);return regs.eax;
}

注:感谢网友五年一剑指正cpuid.h文件缺少的cpuid_eax函数,已补充。

实现文件cpuid.c代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>#include "cpuid.h"void get_cpu_vendor(char* cpu_vendor, int* cpuid_level)
{char vendor_name[16];vendor_name[0] = '\0'; /* Unset */int level = 0;struct cpuid_result result;result = cpuid(0x00000000); // 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';//printf("vendor_name: %s\n", vendor_name);strcpy(cpu_vendor, vendor_name);*cpuid_level = level;
}void get_cpu_version(unsigned int* version)
{unsigned int tmp = 0;tmp = cpuid_eax(0x00000001);*version = tmp;
}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(int* family, int* model, int* stepping)
{struct cpuinfo_x86 c;unsigned int ver = 0;ver = cpuid_eax(0x00000001);get_fms(&c, ver);*family = c.x86;*model = c.x86_model;*stepping = c.x86_step;
}void get_cpu_name(char* processor_name)
{struct cpuid_result regs;char temp_processor_name[49];char* processor_name_start;unsigned int *name_as_ints = (unsigned int *)temp_processor_name;int i;/* 用cpuid指令,eax传入0x80000002/0x80000003/0x80000004,共3个,每个4个寄存器,每个寄存器4字节,故一共48字节。参考IA32开发手册第2卷第3章。*/for (i = 0; i < 3; i++) {regs = cpuid(0x80000002 + 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(int* linear, int* physical)
{unsigned int tmp = 0;tmp = cpuid_eax(0x80000008);*linear = (tmp>>8) & 0xff;*physical = (tmp>>0) & 0xff;}

主函数实现代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>#include "cpuid.h"
#include "msr.h"int main(void)
{char buffer[49] = {0};unsigned int version = 0;int cpuid_level;get_cpu_vendor(buffer, &cpuid_level);printf("vendor_id\t: %s\n", buffer);printf("cpuid level\t: %d\n", cpuid_level);get_cpu_name(buffer);printf("model name\t: %s\n", buffer);get_cpu_version(&version);int f,m,s;get_cpu_fms(&f, &m, &s);printf("cpu family\t: %d(0x%X)\n", f, f);printf("model\t\t: %d(0x%X)\n", m, m);printf("stepping\t: %d(0x%X)\n", s, s);int phy_bits = 0;int vir_bits = 0;get_address_bits(&vir_bits, &phy_bits);printf("address sizes\t: %d bits physical, %d bits virtual\n", phy_bits, vir_bits);return 0;
}

在Linux系统中,有现成的方法获取CPU信息,比如使用lscpu命令。另外还可以直接查看/proc/cpuinfo文件。使用“cat /proc/cpuinfo”命令查看CPU信息如下(有精简):

# cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 58
model name      : Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
stepping        : 9
physical id     : 0
siblings        : 8
core id         : 3
cpu cores       : 4
apicid          : 7
initial apicid  : 7
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
bogomips        : 6784.28
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:

上述程序运行结果如下:

vendor_id       : GenuineIntel
level           : 13
model name      : Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz
cpu family      : 6(0x6)
model           : 58(0x3A)
stepping        : 9(0x9)
address sizes   : 36 bits physical, 48 bits virtual

可以看到,两者信息高度一致。

Intel处理器的CPUID远不止上文所述,详情请参考Intel IA32软件开发手册。

李迟 2016.3.7 周一 晚

linux C语言调用Intel处理器CPUID指令的实例相关推荐

  1. Intel处理器CPUID指令学习

    前文<Intel处理器Family.Model.Stepping等的学习>只是简单讲了CPU的标识等内容(仅针对Intel,本文也是),但其读取方法未涉及.本文就此未完事宜来了解读取的方法 ...

  2. Linux C语言调用C++动态链接库

    Linux C语言调用C++动态链接库 标签: C调用C++库 2014-03-10 22:56 3744人阅读 评论(0) 收藏 举报 分类: [Linux应用开发](48) 版权声明:本文为博主原 ...

  3. Intel x86_64 CPUID指令介绍

    Intel CPUID指令简介 一.CPUID简介 1.1 CPUID 功能简介 1.2 处理器是否支持 CPUID指令 1.3 指令返回基本信息 1.4 指令返回扩展信息 二.CPUID指令参数输入 ...

  4. Linux C语言调用C++动态链接库-改

    如果你有一个c++做的动态链接库.so文件,而你只有一些相关类的声明, 那么你如何用c调用呢,别着急,本文通过一个小小的例子,让你能够很爽的搞定. 一.编译生成一个供测试使用的C++动态库: 链接库头 ...

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

    文章目录 前言 一.cpuid指令简介 1.1 cpuid指令功能 1.2 cpuid指令代码 二.获取处理器信息 2.1 输入参数为0H 2.2 输入参数为01H 2.3 输入参数为0x800000 ...

  6. Intel CPU的CPUID指令

    Intel有一个超过100页的文档,专门介绍cpuid这条指令,可见这条指令涉及内容的丰富. 记得去年的时候,曾经有个"英布之剑"问过我这条指令,当时并没有给出一个满意的回答,现在 ...

  7. 通过CPUID指令读取处理器信息

    一.CPUID简介 CPUID操作码是一个面向x86架构的处理器补充指令,它的名称派生自CPU识别,作用是允许软件通过CPUID指令读取处理器的详细信息. 二.CPUID基本原理 CPUID有很多fu ...

  8. INTEL处理器识别和CPUID指令(二) CPUID指令

    CPUID指令有两套函数,第一套函数返回处理器的基本信息,第二套函数返回处理器的扩展信息.图一总结了CPUID指令所能输出的处理器的基本信息.CPUID指令的输出完全依赖于EAX寄存器的内容,根据EA ...

  9. INTEL处理器识别和CPUID指令(一) CPUID指令与状态寄存器的演变

    按:本系列翻译自INTEl官方的CPUID指令文档<Intel® Processor Identification and the CPUID Instruction>,由于我自身英语水平 ...

最新文章

  1. python运行界面英文翻译_python使用百度api翻译中英文
  2. dijkstra邻接表_掌握算法-图论-最短路径算法-Dijkstra算法
  3. 完全开源im框架_【行业资讯】移动端开源 IM 框架 MobileIMSDK v5.0 发布!
  4. 万物皆可爬系列查看翻页翻到最后是什么
  5. Unity寻路的功能总结
  6. 经典算法-(六)老鼠走迷宫
  7. 军用计算机通用规范测试试验,军用装备环境可靠性试验项目表
  8. python离线安装whl文件.
  9. 保持简单----纪念丹尼斯里奇(Dennis Ritchie) (zz.is2120.BG57IV3)
  10. 人不成熟的几大特征-----海尔集团CEO张瑞敏演讲稿
  11. java jmf 教程_JMF入门(Java Media Framework)
  12. 头条搜索官网认证说明
  13. Echarts折线图的平移假动画
  14. SQL1054错误Unknown column .... in on clause
  15. C/C++ 操作ini文件(SinpleIni 跨平台库)
  16. margin-top、padding-top的值为百分比
  17. 【C51】基于C51单片机的定时闹钟(含代码,电路,拿走即可用)
  18. Module use of python36.dll conflicts with this version of Python
  19. setuptools已安装仍报错No module named ‘setuptools‘
  20. UG技巧,适合初学者

热门文章

  1. vue.js koa2 mysql_nodejs-koa2-mysql-sequelize-jwt
  2. 苹果2024年推出真全面屏iPhone 但可能只是高端版
  3. 中国好岳父?女婿亏掉公司半个亿 岳父3天还清!涉事公司回应了
  4. 研究机构称iPhone 12 mini可能已停产 因销量不佳
  5. 三星显示、LG已开始为苹果iPhone 13生产OLED屏幕
  6. 十大下班最晚城市,四个在广东
  7. 三星Galaxy S21系列将搭载One UI3.1系统:首发声音解锁
  8. 消息称苹果正开发基于自研ARM芯片的游戏主机
  9. 索尼发布工业设备用SWIR图像传感器 采用5微米像素尺寸
  10. 2020胡润全球80后白手起家富豪榜:前三名两位中国人