개요

CPUID는 x86 아키텍처를 위한 프로세서 기계 명령어이다. 인텔이 펜티엄과 SL 강화 486 프로세서를 내세운 1993년에 도입하였다.[1] [2]

CPUID opcode를 사용하여 소프트웨어는 프로세서 종류와 MMX, SIMD와 같은 기능들을 결정할 수 있다. CPUID opcode는 0FA2h이며 EAX 레지스터 값은 어떠한 정보를 반환할지를 결정한다.

CPUID 명령을 일반적으로 사용하기까지 프로그래머들은 프로세서 메이커와 모델을 결정하기 위하여 CPU 동작에 사소한 차이를 불러일으킬 수 있는 하드웨어 Specific한 명령어나, 일련의 과정을 통해서 알아냈어야 하였다. 그러나 CPUID를 통해서 이러한 일들을 하나의 인스트럭션으로 쉽게 전달 할 수 있게 되었다.

CPUID 호출

어셈블리어에서 CPUID 명령은 CPUID가 EAX 레지스터를 그대로 사용하므로 매개변수를 이용하지 않는다. EAX 레지스터는 어떠한 정보를 반환할지를 지정하는 값과 함께 로드되어야 한다. CPUID는 EAX = 0으로 먼저 호출되어야 하는데, 이는 CPU가 지원하는 가장 높은 호출 변수를 반환할 것이기에 그러한 것이다. 확장 정보를 가져오려면 CPUID는 비트 31의 EAX 집합을 사용하여 호출되어야 한다. 가장 높은 확장 명령 호출 변수를 결정하려면 EAX = 80000000h를 사용하여 CPUID를 호출하면 된다.

EAX=0: 제조업체 ID 가져오기

이것은 CPU의 제조업체 ID 문자열을 반환한다. 이 문자열은 EBX, EDX, ECX 순으로 저장된 12자리 아스키 문자열이다. 가장 높은 기본 호출 변수는 EAX로 반환된다.

다음은 잘 알려진 제조업체 ID 문자열이다.

  • "AMDisbetter!" - AMD K5 프로세서 초기 샘플
  • "AuthenticAMD" - AMD
  • "CentaurHauls" - Centaur
  • "CyrixInstead" - 사이릭스
  • "GenuineIntel" - 인텔
  • "GenuineTMx86", "TransmetaCPU" - Transmeta
  • "Geode by NSC" - 내셔널 세미컨덕터
  • "NexGenDriven" - NexGen
  • "RiseRiseRise" - Rise
  • "SiS SiS SiS " - SiS
  • "UMC UMC UMC " - UMC
  • "VIA VIA VIA " - 비아 테크놀로지스

이를테면 GenuineIntel 프로세서 값은 EBX로 0x756e6547를, EDX로 0x49656e69를 ECX로 0x6c65746e로 반환된다.

EAX=1
프로세서 정보 및 기능 비트
CPU의 스테핑, 모델, 계열 정보를 EAX(CPU 서명이라고도 불림)로, 기능 플래그를 EDX와 ECX로, 부가 기능 정보를 EBX로 반환한다.
EAX로 반환되는 정보 형태는 다음과 같다:
  • 3:0 - 스테핑
  • 7:4 - 모델
  • 11:8 - 계열
  • 13:12 - 프로세서 유형
  • 19:16 - 확장 모델
  • 27:20 - 확장 계열
EAX=2
캐시 및 TLB 서술자 정보
EAX=3
프로세서 일련 번호
EAX=80000000h
가장 높은 확장 함수 가져오기
EAX=80000001h
확장 프로세서 정보 및 기능 비트
EAX=80000002h,80000003h,80000004h
프로세서 브랜드 문자열
프로세서 브랜드 문자열은 EAX, EBX, ECX, EDX로 반환된다.
EAX=80000005h
1차 캐시 및 TLB ID
EAX=80000006h
확장 2차 캐시 기능
ECX의 2차 캐시의 자세한 내용을 반환한다.
EAX=80000007h
고급 전원 관리 정보
EAX=80000008h
선형 및 물리 주소 크기
해당 정보는 EAX 레지스터에 반환된다.
  • 7:0 - 프로세서가 지원하는 물리적 주소 크기(MAXPHYADDR 이라고 하며 최대 52)
  • 15:8 - 프로세서가 지원하는 선형 주소 너비
  • 31:16 - 예약된 영역

다른 언어로부터 ID 접근

이 정보는 다른 언어로부터 접근하기 쉽다. 이를테면 아래의 C++ (gcc) 코드는 cpuid가 반환하는 처음 다섯 개의 값을 인쇄한다.

#include <iostream>

int main(int argc, char **argv) {
  int b;
  for (int a = 0; a < 5; a++) {
    asm ( "mov %1, %%eax; " // a → eax
          "cpuid;"
          "mov %%eax, %0;" // eeax → b
          :"=r"(b) /* 출력 */
          :"r"(a) /* 입력 */
          :"%eax" /* 레지스터 표시 */
         );
    std::cout << "코드 " << a << "은(는) 다음을 제공한다: " << b << std::endl;
  }
  return 0;
}

마이크로소프트 비주얼 C 컴파일러는 함수 __cpuid()를 내장하고 있으므로 cpuid 명령은 인라인 어셈블리를 사용하지 않아도 추가할 수 있다. x64 버전의 MSVC가 인라인 어셈블리를 아예 허용하지 않으므로 다루기 쉽다. MSVC의 경우 다음과 같이 하면 된다:

#include <iostream>
#include <intrin.h>

int main(int argc, char **argv) {
  int b[4];
  for (int a = 0; a < 5; a++) {
    __cpuid(b,a);
    std::cout << "코드 " << a << "은(는) 다음을 제공한다: " << b[0] << std::endl;
  }
  return 0;
}

참고