cpuidを使ったサンプルプログラム
(CPUから情報を取得する)
cpuid命令を使用してCPUからCPU情報を取得します。インラインアセンブラを使用してcpuid命令を実行、各レジスタに情報が設定されていることを確認します。cpuid命令の詳しい資料についてはintelのデータシート等を参照してください。 |
/*
* cpuid sample program
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
}reg_t;
void cpuid(unsigned int eax, reg_t *r)
{
asm volatile (
"cpuid"
:"=a"(r->eax), "=b"(r->ebx), "=c"(r->ecx), "=d"(r->edx)
:"a"(eax)
);
return;
}
int main(void)
{
reg_t reg;
char vendorid[16]={0}, cpuname[48]={0};
int cpunum = 0, L2 = 0, L3 = 0;
unsigned int support = 0;
//EAX=0x00000000
cpuid(0x00, ®);
support = reg.eax;
memcpy(vendorid, &(reg.ebx), 4);
memcpy(&vendorid[4], &(reg.edx), 4);
memcpy(&vendorid[8], &(reg.ecx), 4);
printf("vendor_id\t: %s\n", vendorid);
if(support >= 0x01){
//EAX=0x00000001
cpuid(0x01, ®);
printf("Family\t\t: %d\n", (((reg.eax) >> 8)&0x0f));
printf("Model\t\t: %d\n", (((reg.eax) >> 4)&0x0f));
printf("Stepping\t: %d\n", ((reg.eax)&0x0f));
printf("Processor Type\t: %d\n", (((reg.eax) >> 12)&0x0f));
cpunum = ((reg.ebx) >> 16) & 0xff;
printf("CPU cores\t: %d\n", cpunum);
printf("flags\t\t: ");
if(((reg.edx) >> 23) & 0x01)
printf("MMX ");
if(((reg.edx) >> 25) & 0x01)
printf("SSE ");
if(((reg.edx) >> 26) & 0x01)
printf("SSE2 ");
if(reg.ecx & 0x01)
printf("SSE3 ");
if(((reg.edx) >> 28) & 0x01)
printf("HT ");
printf("\n");
}
//EX check
cpuid(0x80000000, ®);
support = reg.eax;
if(support >= 0x80000004){
//Processor name
cpuid(0x80000002, ®);
memcpy(cpuname, &(reg.eax), 4);
memcpy(&cpuname[4], &(reg.ebx), 4);
memcpy(&cpuname[8], &(reg.ecx), 4);
memcpy(&cpuname[12], &(reg.edx), 4);
cpuid(0x80000003, ®);
memcpy(&cpuname[16], &(reg.eax), 4);
memcpy(&cpuname[20], &(reg.ebx), 4);
memcpy(&cpuname[24], &(reg.ecx), 4);
memcpy(&cpuname[28], &(reg.edx), 4);
cpuid(0x80000004, ®);
memcpy(&cpuname[32], &(reg.eax), 4);
memcpy(&cpuname[36], &(reg.ebx), 4);
memcpy(&cpuname[40], &(reg.ecx), 4);
memcpy(&cpuname[44], &(reg.edx), 4);
printf("CPU name\t: %s\n", cpuname);
}
if(support >= 0x80000006){
//EAX=0x80000006(cache information)
cpuid(0x80000006, ®);
L2 = (reg.ecx) >> 16;
L3 = (reg.edx) >> 16;
printf("L2 cache\t: %d KB\n", L2);
printf("L3 cache\t: %d KB\n", L3);
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
(プログラムの概要)
レジスタeaxに値を設定し、cpuid命令を実行するとeax,ebx,ecx,edxの各レジスタに情報が設定されます。これを利用してCPU名称やベンダー名、サポートしている機能やキャッシュ容量を表示してみます。
15L-23L:cpuid()cpuid命令を実行するインラインアセンブラのラッパー関数です。引数eaxで渡された値をレジスタeaxに設定しcpuid命令を実行、レジスタeax,ebx,ecx,edxに設定された値を引数で渡されたrに代入しています。 32L-37L:ベンダーコード取得
eaxを0x00でcpuidを実行すると、eaxに基本命令の使用可能な最大値(cpuidを使用する場合に使える引数eaxの最大値)が設定され、ebx,ecx,edxにベンダーコードの文字列が返されます。 39L-60L:CPU情報取得
eax=0x01としてcpuidを実行すると、CPUのファミリー、モデル、ステッピングやサポートしている命令等が取得できます。 63L-64L:拡張命令の実行
eax=0x80000000からcpuidの拡張命令になります。0x80000000で実行すると、eaxに使用可能な拡張命令の最大値が返されます。 65L-83L:CPU名称の取得
eax=0x80000002-4でcpuidを実行すると、各レジスタにCPU名称の文字が設定されます。 84L-91L:キャッシュ情報取得
eax=0x80000006でcpuidを実行してL2/L3キャッシュの情報が取得しています。
(コンパイルと動作)
gcc -Wall -Werror -o cpuid cpuid.c
実行すると以下のように出力されます。(Intel Core 2プロセッサの場合)
vendor_id : GenuineIntel
Family : 6
Model : 15
Stepping : 6
Processor Type : 0
CPU cores : 2
flags : MMX SSE SSE2 SSE3 HT
CPU name : Intel(R) Core(TM)2 CPU 6700 @ 2.66GHz
L2 cache : 4096 KB
L3 cache : 0 KB