CPUID

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

CPUIDオペコードは、x86アーキテクチャの機械語命令の一つである(この名前はCPUの識別 (IDentification) に由来する)。この命令は1990年代にインテルによって486チップの後期のステッピングで導入され、Pentiumプロセッサで完全に公開された[1]

CPUIDオペコードを使用することで、ソフトウェアはプロセッサの形式と機能(例えば、MMX/SSE命令など)を識別することが出来る。CPUIDオペコードの値は0FA2hであり、EAXレジスタの値でどのような情報を取得するかを指定する。

CPUID命令が使用可能になるまで、プログラマはプロセッサのモデルを区別するために、CPUの振る舞いの微妙な違いを利用する難解な機械語を使用していた[2][3]


目次

CPUID命令の呼び出し [編集]

アセンブリ言語では、CPUIDは暗黙にEAXレジスタを使用するので、CPUID命令ではパラメータは使用しない。EAXレジスタはどのような情報を返すべきかを指定する値を保持する必要がある。まずEAX = 0でCPUIDを呼び出し、CPUでサポートされている最大のパラメータを取得するべきである。CPUIDの拡張機能情報を取得する場合は、EAXのビット31をセットしてCPUIDを呼び出す。拡張機能情報でサポートされている最大の機能番号を得るためには、EAX = 8000000hでCPUIDを呼び出す。

EAX=0: ベンダIDの取得 [編集]

これは、CPUベンダのID文字列を返す。12文字のASCII文字列がEBX, EDX, ECXの順序で格納される。基本機能の最大機能番号がEAXに格納される。

既知のCPUベンダのID文字列は以下のとおり:

例えば、ベンダIDが"GenuineIntel"の場合、EBXが0x756e6547、EDXが0x49656e69、ECXが0x6c65746eとなる。

.section        .data
s0:             .string "Largest Standard Function Number Supported: %i\n"
s1:             .string "Vendor ID: %s\n"
.text
        .global main
 
        .type   main, @function
main:
        pushq   %rbp
        movq    %rsp, %rbp
 
        subl    %eax, %eax
        cpuid
 
        subq    $8, %rsp
        movl    %ebx, (%rsp)
        movl    %edx, 4(%rsp)
        movl    %ecx, 8(%rsp)
        movl    $s0, %edi
        movl    %eax, %esi
        subl    %eax, %eax
        call    printf
 
        movq    $s1, %rdi
        movq    %rsp, %rsi
        subl    %eax, %eax
        call    printf
 
        subl    %eax, %eax
        movq    %rbp, %rsp
        popq    %rbp
        ret

EAX=1: プロセッサ情報とプロセッサの機能 [編集]

これはCPUのステッピング、モデル、ファミリーをEAXに返す(これはCPUのシグネチャとも呼ばれる)。また、機能フラグをEDXとECXに、追加の機能情報をEBXに返す。

EAXに格納される情報のフォーマットは以下のとおり:

  • 3:0 - ステッピング
  • 7:4 - モデル
  • 11:8 - ファミリー
  • 13:12 - プロセッサタイプ
  • 19:16 - 拡張モデル
  • 27:20 - 拡張ファミリー

インテルAMDは、CPUのファミリーを上記のファミリー拡張ファミリーの合計で表示し、モデルを上記のモデルと4ビット左シフトした拡張モデルの合計で表示するように提案した。

プロセッサ情報と機能フラグはメーカ個別のものであるが、通常は互換性のためにインテルの値を他のメーカも使用している。

EAX=2: キャッシュとTLBディスクリプタ情報 [編集]

これは、キャッシュとTLBの機能を示すディスクリプタのリストをEAX, EBX, ECX, EDXレジスタに格納する。

EAX=3: プロッセッサ・シリアル・ナンバ [編集]

これは、プロセッサのシリアル番号を返す。プロセッサ・シリアル・ナンバは、インテルがPentium IIIで導入したが、プライバシーの懸念のためにこの後のモデルでは実装されていない(PSN機能ビットは常にクリアされている)。トランスメタのEfficeonとCrusoeプロセッサはこの機能を提供している。AMDは、この機能をどのCPUにも実装しなかった。

インテルPentium IIIでは、シリアル番号はEDX:ECXレジスタに格納される。トランスメタのEfficeonではEBX:EAXレジスタに、CrusoeではEBXレジスタだけに格納される。

プロセッサ・シリアル・ナンバ機能を使用するためには、BIOSの設定を有効にする必要があることに注意すべきである。

.section        .data
s0:             .string "Processor serial number: %.4hX-%.4hX-%.4hX-%.4hX-%.4hX-%.4hX\n"
.text
        .global main
 
        .type   main, @function
main:
        pushq   %rbp
        movq    %rsp, %rbp
 
        movl    $1, %eax
        cpuid
 
        subq    $4, %rsp
        movl    %eax, (%rsp)
        movq    2(%rsp), %rbx
        movw    %bx, (%rsp)
        movw    %ax, 2(%rsp)
 
        movl    $3, %eax
        cpuid
 
        movl    %edx, 4(%rsp)
        movq    6(%rsp), %rax
        movw    %ax, 4(%rsp)
        movw    %dx, 6(%rsp)
        movl    %ecx, 8(%rsp)
 
        movl    $s0, %edi
        movw    (%rsp), %si
        movw    2(%rsp), %dx
        movw    4(%rsp), %cx
        movw    6(%rsp), %r8w
        movw    8(%rsp), %r8w
        movw    10(%rsp), %r9w
        movw    %r9w, (%rsp)
        subl    %eax, %eax
        call    printf
 
        subl %eax, %eax
        movq    %rbp, %rsp
        popq    %rbp
        ret

EAX=80000000h: サポートする最大拡張機能番号の取得 [編集]

最大の拡張機能番号をEAXに格納する。

EAX=80000001h: 拡張プロセッサ情報とプロセッサの機能 [編集]

拡張機能フラグをEDXとECXに格納する。

EAX=80000002h,80000003h,80000004h: プロセッサブランド文字列 [編集]

プロセッサブランド文字列をEAX, EBX, ECX, EDXに格納する。全体で48バイトのNULL終端アスキー文字列のプロセッサブラント文字列を得るために、各パラメータを順番に設定しCPUIDを呼び出す必要がある。

.section        .data
s0:             .string "Processor Brand String: %s\n"
.text
        .global main
 
        .type   main, @function
main:
        pushq   %rbp
        movq    %rsp, %rbp
 
        subq    $44, %rsp
        movl    $0x80000002, %eax
        cpuid
 
        movl    %eax, (%rsp)
        movl    %ebx, 4(%rsp)
        movl    %ecx, 8(%rsp)
        movl    %edx, 12(%rsp)
        addq    $16, %rsp
 
        movl    $0x80000003, %eax
        cpuid
 
        movl    %eax, (%rsp)
        movl    %ebx, 4(%rsp)
        movl    %ecx, 8(%rsp)
        movl    %edx, 12(%rsp)
        addq    $16, %rsp
 
        movl    $0x80000004, %eax
        cpuid
 
        movl    %eax, (%rsp)
        movl    %ebx, 4(%rsp)
        movl    %ecx, 8(%rsp)
        movl    %edx, 12(%rsp)
        subq    $32, %rsp
 
        movl    $s0, %edi
        movq    %rsp, %rsi
        subl    %eax, %eax
        call    printf
 
        subl    %eax, %eax
        movq    %rbp, %rsp
        popq    %rbp
        ret

EAX=80000005h: 予約 [編集]

この機能は使用されていない。

EAX=80000006h: 拡張L2キャッシュ情報 [編集]

ECXにL2キャッシュの詳細情報を格納する。2種類の方法で表したキャッシュサイズと、キャッシュとメモリの対応を示すコードを含む。

.section        .data
s0:             .string "L2 Cache: %iMB\n"
.text
        .global main
 
        .type   main, @function
main:
        pushq   %rbp
        movq    %rsp, %rbp
 
        movl    $0x80000006, %eax
        cpuid
 
        subl    %edx, %edx
        movl    %ecx, (%rsp)
        movl    2(%rsp), %eax
        movl    $1024, %ecx
        divl    %ecx
 
        movl    $s0, %edi
        movl    %eax, %esi
        subl    %eax, %eax
        call    printf
 
        subl %eax, %eax
        movq    %rbp, %rsp
        popq    %rbp
        ret

EAX=80000007h: 予約 [編集]

この機能は使用されていない。

EAX=80000008h: 仮想アドレスと物理アドレスのサイズ [編集]

最大の仮想アドレスサイズと物理アドレスサイズをEAXに格納する。

関連項目 [編集]

外部リンク [編集]