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, &reg); 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, &reg); 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, &reg); support = reg.eax; if(support >= 0x80000004){ //Processor name cpuid(0x80000002, &reg); 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, &reg); 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, &reg); 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, &reg); 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