수색…


리얼 모드

인텔이 원래의 x86 (8086 및 8088 파생물)을 설계했을 때, 16 비트 프로세서가 16 비트 이상의 주소에 액세스 할 수 있도록 해주는 분할 기능이 포함되었습니다. 이들은 16 비트 주소를 코드 세그먼트 ( CS ), 데이터 세그먼트 ( DS ), 엑스트라 세그먼트 ( ES ) 및 스택 세그먼트 ( SS )의 네 가지로 정의 된 16 비트 세그먼트 레지스터에 상대적으로 만들었습니다. .

Segment Register가 사용하는 대부분의 명령어는 코드 세그먼트 (Segment), PUSHPOP 에서 스택 세그먼트를 암시하고 간단한 데이터 참조가 데이터 세그먼트를 암시했음을 암시합니다. 다른 세그먼트의 메모리에 액세스 할 수는 있지만 오버라이드 될 수 있습니다.

구현은 간단합니다. 모든 메모리 액세스에 대해 CPU는 묵시적 (또는 명시 적) 세그먼트 레지스터를 가져 와서 네 위치를 왼쪽으로 이동 한 다음 지정된 주소를 추가합니다.

        +-------------------+---------+
Segment | 16-bit value      | 0 0 0 0 |
        +-------------------+---------+
                   PLUS
        +---------+-------------------+
Address | 0 0 0 0 | 16-bit value      |
        +---------+-------------------+
                  EQUALS
        +-----------------------------+
Result  |  20-bit memory address      |
        +-----------------------------+

이것은 다양한 기법을 허용했습니다 :

  • 코드, 데이터 및 스택에 모두 상호 액세스 가능하도록 허용 ( CS , DSSS 모두 동일한 값을 가짐).
  • 코드, 데이터 및 스택을 서로 완전히 분리하여 보관하십시오 ( CS , DSSS 모두 4K 이상) - 16 배로 64K가된다는 것을 기억하십시오.

기괴한 오버랩과 모든 종류의 이상한 것들도 허용했습니다!

80286이 발명되었을 때이 레거시 모드 (현재는 "리얼 모드"라고 함)를 지원했지만 "보호 모드"(qv)라는 새로운 모드가 추가되었습니다.

알아 두어야 할 중요한 사항은 리얼 모드에서입니다.

  • 모든 메모리 주소는 세그먼트 레지스터에 올바른 값을 넣고 16 비트 주소에 액세스하여 액세스 할 수있었습니다.
  • "보호"의 정도는 프로그래머가 다른 목적으로 여러 영역의 메모리를 분리 할 수있게 해주 었으며 실수로 잘못된 데이터를 쓰는 것을 더 어렵게 만들었습니다.

다른 말로하면 ... 전혀 보호되지 않습니다!

보호 모드

소개

80286이 발명되었을 때 레거시 8086 세그먼트 화 (현재는 "리얼 모드"라고 함)를 지원하고 "보호 모드"라는 새로운 모드를 추가했습니다. 이 모드는 32 및 64 비트 주소 지정과 같은 다양한 개선으로 향상되었지만 모든 x86 프로세서에서 사용되었습니다.

디자인

보호 모드에서는 단순한 "주소를 시프트 세그먼트 레지스터 값에 추가"가 완전히 완료되었습니다. 그들은 세그먼트 레지스터를 유지했지만 주소를 계산하는 대신 세그먼트를 사용하여 액세스 할 세그먼트를 정의한 테이블 (실제로는 두 개 중 하나)에 색인을 생성했습니다. 이 정의는 Segment가 (Base와 Limit를 사용하여) 메모리 내에서뿐만 아니라 어떤 유형 의 Segment (Code, Data, Stack 또는 System)인지 그리고 어떤 종류의 프로그램이 그것을 액세스 할 수 있는지를 설명했다 (OS Kernel, normal program , 장치 드라이버 등).

세그먼트 등록기

각 16 비트 세그먼트 레지스터는 다음 형식을 취했습니다.

+------------+-----+------+
| Desc Index | G/L | Priv |
+------------+-----+------+
 Desc Index = 13-bit index into a Descriptor Table (described below)
 G/L        = 1-bit flag for which Descriptor Table to Index: Global or Local
 Priv       = 2-bit field defining the Privilege level for access

글로벌 / 로컬

글로벌 / 로컬 비트는 액세스가 디스크립터의 글로벌 테이블 (놀랍지 않게 글로벌 디스크립터 테이블 또는 GDT라고 함) 또는 로컬 디스크립터 테이블 (LDT) 중 어디에 속하는지 정의합니다. LDT에 대한 아이디어는 모든 프로그램이 자체 디스크립터 표를 가질 수 있다는 것입니다. OS는 전역 세트의 세그먼트를 정의하고 각 프로그램은 자체 코드, 데이터 및 스택 세그먼트 세트를 갖습니다. 운영체제는 서로 다른 디스크립터 테이블 간의 메모리를 관리합니다.

기술자 표

각 디스크립터 테이블 (글로벌 또는 로컬)은 8,192 개의 디스크립터로 구성된 64K 어레이로, 설명하는 세그먼트의 여러 측면을 정의한 8 바이트 레코드입니다. 세그먼트 레지스터의 디스크립터 인덱스 필드는 8,192 개의 디스크립터에 허용된다 : 우연이 아닌!

기술자

Descriptor는 다음과 같은 정보를 담고 있습니다. - 새로운 프로세서가 릴리스 될 때 Descriptor의 형식이 변경되었지만 동일한 종류의 정보가 각각 유지되었습니다.

  • 베이스
    이것은 메모리 세그먼트의 시작 주소를 정의합니다.
  • 한도
    이것은 메모리 세그먼트의 크기를 정의합니다. 그들은 결정을 내려야 만했습니다 : 0x0000 의 크기는 0 의 크기를 의미하므로 액세스 할 수 없습니까? 또는 최대 크기?
    대신 그들은 세 번째 옵션을 선택했습니다 : 한계 필드는 세그먼트 내의 마지막 주소 지정 가능한 위치였습니다. 이는 1 바이 세분을 정의 할 수 있음을 의미합니다. 또는 주소 크기에 대한 최대 크기입니다.
  • 유형
    다양한 유형의 세그먼트가있었습니다. 기존 코드, 데이터 및 스택 (아래 참조)이지만 다른 시스템 세그먼트도 정의되었습니다.
    • 로컬 디스크립터 테이블 세그먼트는 액세스 할 수있는 로컬 디스크립터의 수를 정의합니다.
    • 작업 상태 세그먼트는 하드웨어 관리 컨텍스트 스위칭에 사용할 수 있습니다.
    • 프로그램이 운영 체제를 호출 할 수 있도록 제어되는 "Call Gates"제어 - 신중하게 관리되는 진입 점을 통해서만 가능합니다.
  • 속성
    관련성이있는 경우 세그먼트의 특정 속성도 유지되었습니다.
    • 읽기 전용 대 읽기 - 쓰기;
    • Segment가 현재 존재하는지 여부 - 주문형 메모리 관리 허용
    • 어떤 수준의 코드 (OS 대 드라이버 대 프로그램)가이 세그먼트에 액세스 할 수 있습니까?

마침내 진정한 보호!

운영체제가 단순한 프로그램으로는 액세스 할 수없는 세그먼트에 디스크립터 테이블을 보관한다면, 정의 된 세그먼트와 각 세그먼트에 할당되고 액세스 가능한 메모리를 엄격하게 관리 할 수 ​​있습니다. 프로그램은 좋아하는 어떤 세그먼트 레지스터 값을 제조 할 수 있었다 -하지만 실제로 등록 세그먼트에로드 할 수있는 대담하는 것이 있다면 ...는 CPU의 하드웨어는 제안 설명자 값이 규칙의 큰 숫자 중 하나를 부러 있음을 인식하고 것입니다! 요청을 완료하는 대신 오류가있는 프로그램을 처리 할 수 ​​있도록 운영 체제에 예외를 발생시킵니다.

이 예외는 일반적으로 Microsoft Windows에서 널리 알려진 일반 보호 예외가 적용된 세계 # 13이었습니다 ... (인텔 기술자는 누구나 미신적이라고 생각합니까?)

오류

발생할 수있는 오류의 종류는 다음과 같습니다.

  • 제안 된 디스크립터 색인이 표의 크기보다 큰 경우;

  • 제안 된 디스크립터가 코드, 데이터 또는 스택이 아닌 시스템 디스크립터 인 경우

  • 제안 된 디스크립터가 요청하는 프로그램보다 더 많은 권한을 가진 경우

  • 제안 된 디스크립터가 읽을 수 없음 (코드 세그먼트와 같은)으로 표시되었지만 실행보다는 읽기가 시도 된 경우

  • 제안 된 기술자가 존재하지 않음으로 표시된 경우.

    마지막으로 프로그램에 치명적인 문제는 아닐 수 있습니다. OS는 플래그를 기록하고 Segment를 복원 한 다음 Present로 표시 한 다음 오류가 발생한 명령을 성공적으로 진행할 수 있습니다.

또는 Descriptor가 Segment Register에 성공적으로로드되었지만 이후에 액세스 할 때 여러 가지 규칙 중 하나가 위반되었습니다.

  • 세그먼트 레지스터에는 GDT의 0x0000 디스크립터 색인이로드되었습니다. 이것은 하드웨어에 의해 NULL 로 예약되었습니다.
  • 로드 된 Descriptor가 Read-Only로 마크되었지만, Write가 시도되었다.
  • 액세스의 일부 (1, 2, 4 바이트 이상)가 세그먼트 한계 밖인 경우

보호 모드로 전환

보호 모드로 전환하는 것은 쉽습니다. 제어 레지스터에 단일 비트를 설정하기 만하면됩니다. 그러나 CPU가 손을 위로 던지고 때문에 다음에 무엇을 모르고 자신을 재설정하지 않고, 보호 모드에 머물고, 많은 준비를합니다.

즉, 필요한 단계는 다음과 같습니다.

  • 글로벌 디스크립터 테이블을위한 메모리 영역은 최소 3 개의 디스크립터를 정의하도록 설정되어야한다.

    1. 0 번째의 NULL 디스크립터.
    2. 코드 세그먼트를위한 또 다른 기술자;
    3. 데이터 세그먼트에 대한 또 다른 설명자.

      이것은 데이터와 스택 모두에 사용할 수 있습니다.

  • GDTR (Global Descriptor Table Register)은이 정의 된 메모리 영역을 가리 키도록 초기화되어야합니다.

     GDT_Ptr    dw      SIZE GDT
                dd      OFFSET GDT
    
                ...
    
                lgdt    [GDT_Ptr]
    
  • CR0PM 비트를 CR0 해야합니다.

         mov   eax, cr0      ; Get CR0 into register
         or    eax, 0x01     ; Set the Protected Mode bit
         mov   cr0, eax      ; We're now in Protected Mode!
    
  • 현재의 실수 모드 값을 제거하려면 세그먼트 레지스터를 GDT에서로드해야합니다.

         jmp   0x0008:NowInPM  ; This is a FAR Jump. 0x0008 is the Code Descriptor
    
    NowInPM:
         mov   ax, 0x0010      ; This is the Data Descriptor
         mov   ds, ax
         mov   es, ax
         mov   ss, ax
         mov   sp, 0x0000      ; Top of stack!
    

이, 최소한 단지 보호 모드로 CPU를 얻을 수 있습니다. 실제로 전체 시스템을 준비하려면 더 많은 단계가 필요할 수 있습니다. 예 :

  • 상위 메모리 영역을 활성화해야 할 수도 있습니다 - A20 게이트를 끄기;
  • 인터럽트는 확실히 비활성화되어야합니다. 그러나 처리 중에 오류가 발생하기 전에 보호 모드로 들어가기 전에 여러 가지 오류 처리기를 설정할 수 있습니다.

이 섹션의 원저자는 보호 모드로 들어가고 그것에 대해 작업하는 전체 자습서 를 작성했습니다.

언리얼 모드

언리얼 모드 는 인텔과 AMD 프로세서가 어떻게 세그먼트를 설명하기 위해 정보를로드하고 저장하는지에 대한 두 가지 사실을 이용합니다.

  1. 프로세서는 이동 중에 페치 된 설명자 정보를 보호 모드의 선택기 레지스터에 캐시합니다.
    이러한 정보는 선택기 레지스터 자체의 아키텍처 보이지 않는 부분에 저장됩니다.

  2. 리얼 모드에서 셀렉터 레지스터는 세그먼트 레지스터라고 불리지 만 그 외의 레지스터는 동일한 레지스터 세트를 지정하며 보이지 않는 부분도 가지고 있습니다. 이 부분은 고정 값으로 채워지지만 방금로드 된 값에서 파생 된 기준에 대해 채워집니다.

이러한 관점에서, 리얼 모드는 보호 모드의 특별한 경우 일뿐입니다. 즉, 기본 및 제한과 같은 세그먼트 정보는 GDT / LDT없이 가져 오지만 세그먼트 레지스터 숨겨진 부분에서 읽습니다.


보호 모드를 전환하고 GDT를 작성하면 원하는 속성 (예 : 0의 기본 및 4GiB의 제한)으로 세그먼트를 만들 수 있습니다.
이러한 속성이 캐시 된 선택기 레지스터의 연속적인로드를 통해 리얼 모드로 전환하고 전체 32 비트 주소 공간을 액세스하는 세그먼트 레지스터를 가질 수 있습니다.

BITS 16

jmp 7c0h:__START__

__START__:
 push cs
 pop ds
 push ds
 pop ss
 xor sp, sp

 
 lgdt [GDT]            ;Set the GDTR register
 

 cli                ;We don't have an IDT set, we can't handle interrupts


 ;Entering protected mode

 mov eax, cr0
 or ax, 01h            ;Set bit PE (bit 0) of CR0
 mov cr0, eax            ;Apply

 ;We are now in Protected mode

 mov bx, 08h           ;Selector to use, RPL = 0, Table = 0 (GDT), Index = 1

 mov fs, bx            ;Load FS with descriptor 1 info
 mov gs, bx            ;Load GS with descriptor 1 info

 ;Exit protected mode

 and ax, 0fffeh            ;Clear bit PE (bit0) of CR0
 mov cr0, eax                   ;Apply

 sti                

 ;Back to real mode

 ;Do nothing
 cli
 hlt 



 GDT:
    ;First entry, number 0
    ;Null descriptor
    ;Used to store a m16&32 object that tells the GDT start and size

    dw 0fh                 ;Size in byte -1 of the GDT (2 descriptors = 16 bytes)
    dd GDT + 7c00h         ;Linear address of GDT start (24 bits)
    dw 00h                 ;Pad 

    dd 0000ffffh           ;Base[15:00] = 0, Limit[15:00] = 0ffffh
    dd 00cf9200h           ;Base[31:24] = 0, G = 1, B = 1, Limit[19:16] = 0fh, 
               ;P = 1, DPL = 0, E = 0, W = 1, A = 0, Base[23:16] = 00h


 TIMES 510-($-$$) db 00h
 dw 0aa55h 

고려 사항

  • 세그먼트 레지스터가 다시로드 되 자마자 프로세서는 동일한 값으로도 현재 모드에 따라 숨겨진 속성을 다시로드합니다. 위의 코드는 fsgs 를 사용하여 "확장"세그먼트를 보유하는 이유입니다. 이러한 레지스터는 다양한 16 비트 서비스에서 사용 / 저장 / 복원 할 가능성이 적습니다.
  • lgdt 명령어는 GDT에 먼 포인터를로드하지 않고 대신 24 비트 (32 비트로 재정의 가능) 선형 주소를로드 합니다. 이것은 가까운 주소 가 아니며 물리적 주소입니다 (페이징을 비활성화해야하기 때문에). 그것이 GDT+7c00h 의 이유입니다.
  • 위의 프로그램은 cs / ds / ss tp 7c00h를 설정 하고 0에서 위치 카운터를 시작하는 부트 로더 (MBR의 경우 BPB 없음)입니다. 따라서 파일의 오프셋 X 에있는 바이트가 세그먼트 7c00h의 오프셋 X 에 있고 선형 주소 7c00h + X.
  • 보호 모드에서 IDT가 짧은 왕복 시간으로 설정되어 있지 않으므로 인터럽트를 사용하지 않도록 설정해야합니다.
  • 코드는 6 바이트의 코드를 저장하기 위해 해킹을 사용합니다. lgdt 에 의해로드 된 구조는 ... GDT 자체에 널 디스크립터 (첫 번째 디스크립터)에 저장된다.

GDT 디스크립터에 대한 설명은 Intel Manual Volume 3A의 3.4.3 장을 참조하십시오.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow