ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CPUID
    프로젝트/운영체제 만들기 2023. 8. 10. 23:30

    글의 참고

    - https://en.wikipedia.org/wiki/X86-64

    - https://wiki.osdev.org/X86-64

    - https://wiki.osdev.org/Setting_Up_Long_Mode

    - https://wiki.osdev.org/Creating_a_64-bit_kernel

    - https://wiki.osdev.org/CPUID

    - https://archive.techarp.com/showFreeBOGf954-2.html?lang=0&bogno=307 

    - http://datasheets.chipdb.org/Cyrix/New%20Folder/cpuid0.htm

    - https://iq.opengenus.org/cpuid/


    글의 전제

    - 밑줄로 작성된 글은 강조 표시를 의미한다.

    - 그림 출처는 항시 그림 아래에 표시했다.


    글의 내용

    - CPUID

    : `CPUID`는 인텔이 1993년 펜티엄 및 486 프로세서를 출시하면서 나온 명령어다. 이 명령어를 통해 프로세서 타입 및 지원 기능에 대해서 알 수 있다. CPUID는 2개의 타입으로 나뉜다. 

    1" Basic(Standard) - 기본 타입
    2" Extended - 확장 타입

    : 위 2개의 타입은 CPUID 명령어의 입력값에 따라 달라진다. CPUID 명령어에는 입력값을 직접 명시하지는 않는다. EAX 레지스터를 통해 입력값을 명시하게 된다.

     

    1" EAX의 MSB가 0이면 - Basic(Standard) : 0x0000_0000
    2" EAX의 MSB가 1이면 - Extended : 0x8000_0000

    : 각 타입에 따른 기능들이 굉장히 많이 존재한다.

     

    : CPUID 명령어는 맨 처음 호출할 때, 반드시 EAX값을 0x0000_0000으로 설정해서 실행해야 한다. 왜냐면, `기본 타입에서 지원하는 최대 기능 개수`(The highest basic calling parameter (the largest value that EAX can be set to before calling CPUID))를 알기 위해서는 초기에 아래와 같이 호출을 해야 한다. 즉, 현재 내가 사용하는 CPU가 최대 몇 개까지의 CPUID 기본 타입 기능을 지원하는지 알아야 한다는 말이다. 

    MOV EAX, 0x00000000
    CPUID

     

    : 확장 타입 CPUID 최대 기능 개수를 알기 위해서는 반드시 `EAX값을 0x8000_0000`으로 설정해서 실행해야 한다. CPUID 확장 기능 타입은 EAX에 MSB를 1로 세트한다.

    MOV EAX, 0x80000000
    CPUID

    : 위의 2개의 명령어를 실행하면 각 타입(기본, 확장)에 따라 최대 지원하는 기능들의 개수가 EAX 레지스터에 들어간다.

     

    - CPUID leaf

    : 인텔 문서양 자체가가 너무 많아서 `CPUID leaf`를 위키피디아에서 검색해봤다. `CPUID leaf`란 CPUID가 특정 파라미터(leaf)에 따라 여러 개의 기능을 할 수 있는 것을 의미한다. CPUID 같은 경우, EAX 값이 뭐냐에 따라 CPUID의 기능이 바뀐다. 여기서 EAX를 `leaf`라고 부른다. 이 글 맨 아래에 유용한 CPUID를 소개하고 있는데, 거기에 EAX에 0x00000001을 쓸 때와 0x80000001을 쓸 때와 0x80000008 쓸 때, 읽혀지는 내용이 다른 것을 확인할 수 있다.

    In assembly language, the CPUID instruction takes no parameters as CPUID implicitly uses the EAX register to determine the main category of information returned. In Intel's more recent terminology, this is called the `CPUID leaf`. CPUID should be called with EAX = 0 first, as this will store in the EAX register the highest EAX calling parameter (leaf) that the CPU implements.
    ....

    - 참고 : https://en.wikipedia.org/wiki/CPUID

    Most instructions do one thing - add, subtract, move, etc. Some (rare) instructions do completely different things in different situations. One example of this is the CPUID instruction, which does different things depending on the initial value of EAX (and sometimes ECX too). These "different things" are called leaves (by Intel).

    Intel's "GETSEC" instruction is like this. It's one instruction, but depending on the initial value of EAX it can do completely different things. For example, if you set EAX to zero beforehand the GETSEC instruction will do the "(get) CAPABILITIES leaf function", if you set EAX to 4 beforehand the GETSEC instruction will do the "SENTER leaf function", and if you set EAX to 5 beforehand the GETSEC instruction will do the "SEXIT leaf function".

    - 참고 : https://stackoverflow.com/questions/7962044/leaf-instructions-processor-assembly

     : `Brendan` 이 언급한 글에서 중요한 내용 몇 가지가 있다. 일단 `leaf`라는 표현은 인텔에서만 사용하는 표현이다. 그리고, `leaf`라는 개념은 CPUID 명령어에서만 사용하는 개념은 아니다. `GETSEC` 명령어 또한 EAX의 값에 따라 여러 가지 기능을 한다고 한다. 즉, `GETSEC`의 leaf 또한 EAX가 된다.

     

     

    : 아래 그림은 x86 프로세서에서 타입에 따라(기본, 확장) 지원하는 최대 기능 개수를 보여준다.

    출처 - https://en.wikipedia.org/wiki/CPUID#EAX=0:_Highest_Function_Parameter_and_Manufacturer_ID

    : Xeon 같은 경우, CPUID 기본 타입 기능은 2개(0x02)를 지원하고, 확장 기능은 4개(0x8000_0004)를 지원한다. Atom 같은 경우는 CPUID 기본 타입 기능은 10개(0x0A)를 지원하고, 확장 기능은 8개(0x8000_0008)를 지원한다.

     

    : CPUID 기능 중 몇 가지는 알아둘 필요가 있다.

     

     

    - CPUID 기능

    : EAX=0x0000_0000 - Highest Function Parameter and Manufacturer ID

    출처 - https://www.thomas-krenn.com/de/wiki/CPUID

    " `기본 타입중 CPUID EAX=0x0000_0000 기능`은 위의 그림을 보면 알겠지만, `EBX-EDX-ECX` 순으로 `LSB-MSB` 순으로 읽어야 제조사 ID를 정확하게 읽을 수 있다. 위의 제조사 ID를 읽으면 `GenuineIntel` 인을 알 수 있다. 대개 제조사 ID는 실제 물리적인 제조사 ID와 가상 에뮬리에터 제조사 ID로 나뉜다. QEMU는 `TCGTCGTCGTCG`를 사용하고 있고, VMWARE는 `VMwareVMware`를 사용하고 있다. 그리고 AMD 같은 경우는 `AuthenticAMD`를 사용하고 있다.

     

     

    : EAX=0x0000_0001 - Processor Info and Feature Bits

    " `기본 타입중 CPUID EAX=0x0000_0000 기능`은 정말 많은 정보들을 알려준다. 이 기능은 사용하면 EAX, EBX, ECX, EDX 레지스터에 정보들이 들어온다. 

     

     

    - CPUID 지원 여부

    : CPUID 명령어를 통해서 EFLAGS 레지스터의 ID 플래그(21번째) 비트를 바꿀 수 있다. 사실 EFLAGS를 직접 컨트롤하는 것은 매우 주의해야 하는 부분이다.

     

     

     

    - 롱 모드(x86_64) 진입 시, CPUID가 필요한 이유

    : 롱 모드로 진입할 때, CPUID 명령어를 사용하는 이유가 뭘까? 간단하다. 해당 CPU가 롱 모드를 지원하는지 여부를 CPUID를 통해서 알 수 있기 때문이다.

     

     

    - 알아놓으면 좋은 CPUID

    : 4MB 지원 여부

    " `기본 기능 CPUID 0x00000001`은 정말 많은 정보를 알려준다. 여기서 EDX 레지스터의 3번째 비트(PSE)는 32비트 CPU에서 4MB 페이지 크기를 지원하는지에 대한 여부를 알려준다.

    PSE: page-size extensions for 32-bit paging. If CPUID.01H:EDX.PSE [bit 3] = 1, CR4.PSE may be set to 1, enabling support for 4-MByte pages with 32-bit paging (see Section 4.3).

     

    : 1GB 지원 여부

    " `확장 기능 CPUID 0x80000001` 또한 굉장히 많은 정보들을 알려준다. 주로, 64비트 관련한 정보들은 확장 타입 CPUID에 많이 들어있다. 아래 내용을 보면 알 수 있다시피, EDX 레지스터 26번째 비트(PDPE1GB)는 64비트 CPU에서 1GB 페이지 크기를 지원하는지에 대한 여부를 알려준다.

    Page1GB: 1-GByte pages. If CPUID.80000001H:EDX.Page1GB [bit 26] = 1, 1-GByte pages are supported with IA-32e paging (see Section 4.5).

     

    : 64비트 지원 여부

    " `확장 기능 CPUID 0x80000001` EDX.LM[29]번 비트를 통해 `롱모드` 지원 여부를 확인할 수 있다.

    LM: IA-32e mode support. If CPUID.80000001H:EDX.LM [bit 29] = 1, IA32_EFER.LME may be set to 1, enabling IA-32e paging. (Processors that do not support CPUID function 80000001H do not allow IA32_EFER.LME to be set to 1.)

     

    : 지원되는 물리 주소 길이

    " `확장 기능 CPUID 0x80000008`  EAX[7:0]번 비트를 통해 현재 CPU가 주소 지정 가능한 물리 주소 범위를 알려준다. 대개 64비트 CPU는 52비트 인데, 48비트 일 수도 있다. 확장 기능 8번을 지원하지 않는 경우에는 `기본 기능 CPUID 0x00000001` EDX.PAE[6] 비트가 1이면, 1이면 36비트를 의미하고, 0이면 32비트를 의미한다. PAE는 디폴트로 0인 값이다. 저 값은 `READ/WRITE` 가능하기 때문에 상황에 따라 값을 바꿀 수 있다.

    CPUID.80000008H:EAX[7:0] reports the physical-address width supported by the processor. (For processors that do not support CPUID function 80000008H, the width is generally 36 if CPUID.01H:EDX.PAE [bit 6] = 1 and 32 otherwise.) This width is referred to as MAXPHYADDR. MAXPHYADDR is at most 52.

     

    : 지원되는 가상 주소 길이

    " `확장 기능 CPUID 0x80000008`  EAX[15:8] 비트를 통해서 현재 CPU가 주소 지정 가능한 가상 주소의 범위를 알려준다. 일반적으로,  EDX.LM [29] 비트가 1이면 48비트, 0이면 32비트를 의미한다. 만약, 확장 기능 8번을 지원하지 않을 경우, 주소 지정 가능한 가상 주소의 범위는 32비트다.

    CPUID.80000008H:EAX[15:8] reports the linear-address width supported by the processor. Generally, this value is 48 if CPUID.80000001H:EDX.LM [bit 29] = 1 and 32 otherwise. (Processors that do not support CPUID function 80000008H, support a linear-address width of 32.)

     

    : Local APIC 존재 여부

    " CPUID 기본 타입으로 EAX에 0x0000_0001을 실어서 `CPUID 명령어`를 실행하면 EDX의 9번째 비트가 1이면, Local APIC가 존재한다고 가정한다. 0이면 존재하지 않는다고 본다. 

    ....
    Beginning with the P6 family processors, the presence or absence of an on-chip local APIC can be detected using the CPUID instruction. When the CPUID instruction is executed with a source operand of 1 in the EAX register, bit 9 of the CPUID feature flags returned in the EDX register indicates the presence (set) or absence (clear) of a local APIC.
    ....

    - 참고 : 10.4.2 Presence of the Local APIC

    '프로젝트 > 운영체제 만들기' 카테고리의 다른 글

    C 상식  (2) 2023.08.08
    PIC  (0) 2023.08.07
    함수 호출 규약  (0) 2023.08.07
    코드 점프  (0) 2023.08.07
    BIOS  (0) 2023.08.07
Designed by Tistory.