您的位置:首页 > 产品设计 > UI/UE

Intel架构CPU的CPUID指令和Visual Studio的__cpuid/__cpuidex函数

2010-09-15 22:36 573 查看
摘要

简要介绍Intel架构处理器的CPUID指令的规范,在程序中的一般作用,以及微软Visual C++中对应的__cpuid / __cpuidex函数,和我对这两个函数做的简单的类封装。

下载 Intel® Processor Identification and the CPUID Instruction

CPUID 指令

具体描述参考上面的Intel官方文本,这里只做很简单的描述。加上一些Intel 241618文档里没有的内容。

CPUID汇编指令接受输入的寄存器是EAX,存放需要的子功能号,从0x00开始;存放输出的寄存器是EAX,EBX,ECX,EDX。CPUID的子功能集有两大类,基本和扩展。

基本功能:

EAX = 00H 获得最大可用的基本功能号,以及CPU Vendor ID

EAX = 01H 获得CPU各项基本属性,包括Family, Model, Stepping ID, 和其他特性支持描述符

EAX = 02H CPU缓存和TLB的基本描述

EAX = 03H CPU序列号 (由于隐私考虑,在Pentium III以后处理器中该功能被禁止)

扩展功能:

EAX = 80000000H 获得最大可用的扩展功能号

EAX = 80000001H 获得扩展CPU信息和支持的扩展CPU功能表

EAX = 80000002H,80000003H,80000004H 获得CPU描述字符串

EAX = 80000005H 获得CPU L1 Cache 和 TLB 属性描述

EAX = 80000006H 获得CPU L2 Cache 的属性描述

EAX = 80000007H 获得高级电源管理的属性描述 (APMI)

EAX = 80000008H 获得最大可能访问的机器物理地址和虚拟地址,在32位机器上,这个功能可以用来确定是否可以访问>4G内存。返回值存于EAX,0-7比特位存放物理地址比特位数,如果是32就是4G,如果是36就是64G;8-15比特位存放虚拟地址比特位数。

__cpuid / __cpuidex 函数

MSDN 链接 http://msdn.microsoft.com/en-us/library/hskdteyh(v=VS.100).aspx

这两个函数是微软对CPUID汇编指令的C++封装,易于使用,不再需要操作寄存器,而是int32数组,方便高级程序访问CPU信息。函数声明如下:

void __cpuid(
int CPUInfo[4],
int InfoType
);

void __cpuidex(
int CPUInfo[4],
int InfoType,
int ECXValue
);


InfoType就是输入的EAX值,CPUInfo就是输出的int数组,CPUInfo[0],CPUInfo[1],CPUInfo[2],CPUInfo[3]分别对应EAX,EBX,ECX,EDX寄存器。ECXValue就是输入的ECX寄存器值。

面向对象封装

CPU.h

#include <intrin.h>

namespace yshi
{

class CPUID
{
public:
enum Vendor {INTEL, AMD};
public:
CPUID();
public:
Vendor GetVendor() const;
const char* GetVendorString() const;
int GetProcessorSignature() const;
int GetProcessorFamily() const;
int GetProcessorModel() const;
int GetProcessorSteppingID() const;
private:
Vendor DoGetVendor() const;
int GetFamily() const;
int GetExtendedFamily() const;
int GetModel() const;
int GetExtendedModel() const;
private:
Vendor _vendor;
unsigned int _maxInfoType;
unsigned int _info[16][4];	// Can grow in future
unsigned int _maxInfoTypeEx;
unsigned int _infoEx[16][4];	// Can grow in future
};

}


CPU.cpp

#include "stdafx.h"
#include "CPU.h"
#include <exception>

namespace yshi
{

CPUID::CPUID()
{
// Get maximum value for the InfoType parameter that will return valid information
__cpuid((int*)_info[0], 0);
_maxInfoType = _info[0][0];
_vendor = DoGetVendor();

for (unsigned int i = 1; i <= _maxInfoType; i++)
{
__cpuid((int*)_info[i], i);
}

// Get maximum value for the extended InfoType parameter that will return valid information
__cpuid((int*)_infoEx[0], 0x80000000);
_maxInfoTypeEx = _infoEx[0][0];

// Get extended features
for (unsigned int i = 0x80000001; i <= _maxInfoTypeEx; i++)
{
__cpuid((int*)_infoEx[i], i);
}
}

CPUID::Vendor CPUID::DoGetVendor() const
{
if (_info[0][1] == 0x756E6547 &&
_info[0][2] == 0x6C65746E &&
_info[0][3] == 0x49656E69)
return INTEL;
else if (_info[0][1] == 0x68747541 &&
_info[0][2] == 0x444D4163 &&
_info[0][3] == 0x69746E65)
return AMD;
else
throw std::exception("Unsupported CPU vendor.");
}

CPUID::Vendor CPUID::GetVendor() const
{
return _vendor;
}

int CPUID::GetProcessorSignature() const
{
return _info[1][0] & 0x0FFF0FFF;
}

int CPUID::GetProcessorSteppingID() const
{
return _info[1][0] & 0x0000000F;
}

int CPUID::GetModel() const
{
return (_info[1][0] & 0x000000F0) >> 4;
}

int CPUID::GetExtendedModel() const
{
return (_info[1][0] & 0x000F0000) >> 16;
}

int CPUID::GetProcessorModel() const
{
return (GetExtendedModel() << 4) + GetModel();
}

int CPUID::GetFamily() const
{
return (_info[1][0] & 0x00000F00) >> 8;
}

int CPUID::GetExtendedFamily() const
{
return (_info[1][0] & 0x0FF00000) >> 20;
}

int CPUID::GetProcessorFamily() const
{
return GetFamily() + GetExtendedFamily();
}

}


主要用途

CPUID指令主要可用于判断Intel架构CPU的制造商,比如在一些细微的功能实现上,Intel和AMD有差别,要用到此功能的代码就需要先判断制造商.CPUID指令也可用来检测某功能是否支持,从而选择实现方式,比如判断当前CPU是否支持SSE2指令集,从而决定是采用优化浮点计算的SSE2,还是X87浮点计算.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: