Intel CPU中有很多不同的指令集,如:MMX,SSE,SSE2,AVX,AES,VT-x等。而其中有一些与大数计算和密码算法相关的指令集,如AES-NI,SHA,RDRAND等,这些指令集可使得我们的加解密等密码学中的计算更快速并且更安全。
那我们该如何检测CPU中所支持的指令集呢?CPUID指令。
我们使用它来得到CPU的各种信息,并会根据不同的参数把相关信息存到eax,ebx,ecx和edx四个寄存器中。
在Windows中,我们可以直接使用__cpuid()和__cpuidex()函数。
函数:
void __cpuid(int CPUInfo[4], int InfoType);void __cpuidex( int CPUInfo[4], int InfoType, int ECXValue);
参数
[out] CPUInfo 包含有关支持的功能和 CPU 的集合的信息的四个整数。
[in] InfoType 指示的代码的信息此命令检索。
[in] ECXValue ECX 寄存器值在内部之前的生成 cpuid 命令。
头文件 <intrin.h>
而在linux上,我们可以用内嵌汇编编写同样的__cpuid()和__cpuidex()函数。代码如下:
#ifndef __linux__
#include <intrin.h>
#elsestatic void __cpuidex(unsigned int where[4], unsigned int leaf, unsigned int ECXValue) {
asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)), "=c"(*(where+2)),"=d"(*(where+3)):"a"(leaf), "c"(ECXValue));
return;
}static void __cpuid(unsigned int where[4], unsigned int leaf) {
asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)), "=c"(*(where+2)),"=d"(*(where+3)):"a"(leaf));
return;
}
#endif
在使用CPUID指令时,可设给与下列表格相同的eax和ecx的值,来得到对应的CPU信息:
EAX | ECX | RETURN |
0x00 | 0 | Get vendor ID |
0x01 | 0 | Processor Info and Feature Bits |
0x02 | 0 | Cache and TLB Descriptor information |
0x03 | 0 | Processor Serial Number |
0x07 | 0 | Structured Extended Feature Flags Enumeration Leaf (Output depends on ECX input value) |
我们可以使用下列代码,检测CPU是否为INTEL生产:
unsigned int cpuid_results[4];
__cpuid(cpuid_results,0);if (cpuid_results[0] < 1)
return 0;
/*
* MSB LSB
* EBX = 'u' 'n' 'e' 'G'
* EDX = 'I' 'e' 'n' 'i'
* ECX = 'l' 'e' 't' 'n'
*/
/* According to http://en.wikipedia.org/wiki/CPUID */
if (memcmp((unsigned char *)&cpuid_results[1], "Genu", 4) != 0 ||
memcmp((unsigned char *)&cpuid_results[3], "ineI", 4) != 0 ||
memcmp((unsigned char *)&cpuid_results[2], "ntel", 4) != 0)
return 0;
我们所关心的CPU功能信息主要是CPUID.1.0(EAX=1,ECX=0)和CPUID.7.0(EAX=7,ECX=0)这两个分支。
CPUID.1.0(EAX=1,ECX=0)
功能信息主要存于ECX和EDX寄存器中。与安全相关的指令有:
PCLMULQDQ | CPUID.1.0.ECX[1] |
AES-NI | CPUID.1.0.ECX[25] |
RDRAND | CPUID.1.0.ECX[30] |
检测代码如下:
__cpuid(cpuid_results,1);
if ((cpuid_results[2] & (1 << 1)) != 0) {
// CPUID.1.ECX[1]
g_cpu_features |= CPU_X86_FEATURE_PCLMULQDQ;
}
if ((cpuid_results[2] & (1 << 25)) != 0) {
g_cpu_features |= CPU_X86_FEATURE_AESNI; // aes-ni
}
if ((cpuid_results[2] & (1 << 30)) != 0) {
//RDRAND is not an AVX instruction. It is a normal instruction.
g_cpu_features |= CPU_X86_FEATURE_RDRND; // secure key
}
CPUID.7.0(EAX=7,ECX=0)
功能信息主要存于EBX寄存器中。与安全相关的指令有:
OS Guard(SMEP) | CPUID.7.0.EBX[7] |
RDSEED | CPUID.7.0.EBX[18] |
ADX | CPUID.7.0.EBX[19] |
SHA | CPUID.7.0.EBX[29] |
检测代码如下:
// Look for CPUID.7.0.EBX
// EAX = 7, ECX = 0
__cpuidex(cpuid_results,7,0);
printf("CPUID.7.0.EBX 0x%08x:\n", cpuid_results[1]);
if ((cpuid_results[1] & (1 << 7)) != 0) {
// SMEP is identified by CPUID leaf 7 EBX[7], which is 0 before
// CPUID.7.0.EBX[7]
g_cpu_features |= CPU_X86_FEATURE_SMEP;
}
if ((cpuid_results[1] & (1 << 18)) != 0) {
// Intel® RDSEED Extensions
// CPUID.7.0.EBX[18]
g_cpu_features |= CPU_X86_FEATURE_RDSEED;
}
if ((cpuid_results[1] & (1 << 19)) != 0) {
// Intel® ADX Extensions
// CPUID.7.0.EBX[19]
g_cpu_features |= CPU_X86_FEATURE_ADX;
}
if ((cpuid_results[1] & (1 << 29)) != 0) {
// Intel® SHA Extensions
// CPUID.7.0.EBX[29]
g_cpu_features |= CPU_X86_FEATURE_SHA;
}
相关链接:
[1] CPUID http://en.wikipedia.org/wiki/CPUID
[2] Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2A
[3] PCLMULQDQ Instruction and Elliptic Curve Cryptography: Paper
[4] Intel® Advanced Encryption Standard Instructions (AES-NI)
http://software.intel.com/en-us/articles/intel-advanced-encryption-standard-instructions-aes-ni/
[5] What is Intel(r) Secure Key Technology?
http://software.intel.com/en-us/blogs/2012/05/14/what-is-intelr-secure-key-technology
[6] New Instructions Supporting Large Integer Arithmetic on Intel® Architecture Processors
[7] Intel? SHA Extensions
http://software.intel.com/en-us/articles/intel-sha-extensions
[8] The Difference Between RDRAND and RDSEED
http://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
[9] INTRODUCTION TO INTEL® AES-NI AND INTEL® SECURE KEY INSTRUCTIONS
[10] Performance Impact of Intel® Secure Key on OpenSSL
http://software.intel.com/en-us/articles/performance-impact-of-intel-secure-key-on-openssl
[11] SMEP: What is it, and how to beat it on Windows
http://j00ru.vexillium.org/?p=783
[12] Windows Compiler Intrinsics: __cpuid, __cpuidex
http://msdn.microsoft.com/en-us/library/hskdteyh(v=vs.90).aspx
http://bbs.xwh.cn/thread-8285132-1-1.html