64bit 멀티코어 OS 원리와 구조 - Day 5

이 글은 ‘64비트 멀티코어 OS 원리와 구조 - 한승훈 저자’을 공부하며 정리한 내용을 작성했습니다.

페이지 기능을 활성화하여 64비트 전환 준비

선형 주소와 4단계 페이징 기법

페이징에 사용하는 각 테이블은 512개의 엔트리로 구성되며 다음 레벨에서 사용할 테이블의 기준 주소를 포함한다. 그리고 가장 마지막 레벨인 페이지 디렉터리의 엔트리는 2MB 페이지의 기준 주소를 포함한다.

책 P.250 내용에 포함된 사진을 보시면 이해가 쉽습니다.

선형 주소를 실제 물리 주소로 변환하는 과정은 CR3 레지스터에 설정된 PML4 테이블의 기준 주소로 PML4 엔트리 -> 페이지 디렉터리 포인터 엔트리 -> 디렉터리 엔트리로 진행하여 2MB 페이지의 기준 주소를 찾은 다음 선형 주소의 하위 21비트 오프셋을 더하면 된다.

이 과정에서 알 수 있듯이 PML4(Page Map Level 4)에서는 (1)PML4 테이블, (2)페이지 디렉터리 포인터 테이블, (3) 페이지 디렉터리 등 세 가지 자료구조를 생성해야 한다. 각 테이블은 8바이트로 구성되며 각 엔트리는 다음 레벨 테이블의 기준 주소외에도 다양한 필드를 포함한다.

페이지 테이블 구성과 공간 할당

MINT64 OS는 2MB 크기의 페이지를 사용해 최대 64GB의 물리 메모리를 매핑한다고 하면, 페이지 디렉터리8바이트 크기의 엔트리 512개로 구성되며 각 엔트리는 2MB 페이지에 대한 정보를 담고 있다. 따라서 한 페이지 디렉터리는 2MB x 512개로 1GB이며 하나의 페이지 디렉터리는 8바이트 x 512개로 4KB의 메모리를 차지한다. 총 64GB를 관리하기 위해서는 4KB의 페이지 디렉터리 64개가 필요하니 총 256KB가 된다.

앞서 페이지 디렉터리의 포인터를 가지고 있는 페이지 디렉터리 포인터 테이블 역시 페이지 디렉터리와 마찬가지로 8바이트 크기의 엔트리 512개로 구성되고 앞서 페이지 디렉터리 64개를 관리하기 위해서 총 64개의 필드가 필요하다. 64개의 크기는 기존 512개로 충분히 커버가 가능하기 때문에 총 4KB(기본 크기)가 필요하다.

페이지 디렉터리 포인터 테이블을 가리키는 PML4 테이블은 다른 테이블과 마찬가지로 8바이트 크기인 PML4 테이블 엔트리 512개로 구성되며 각 엔트리는 페이지 디렉터리 포인터 테이블의 정보를 담고 있다. 때문에 앞서 페이지 디렉터리 포인터 테이블을 관리하기 위해선 1개의 엔트리만 있으면 되며, 기본 크기 4KB가 필요하다.

이로써 총 264KB의 메모리가 필요하며 이 크기는 지금까지 만든 OS 이미지가 5KB가 안된다는걸 생각하면 큰 크기이다. 이런 큰 크기의 메모리를 이미지에 포함한다면 부팅시간이 지연되고, 4KB로 정렬하기 위해서 추가적으로 불필요한 공간이 낭비된다.

이 문제를 해결하기 위해서 MINTOS64에서는 IA-32e 모드 커널을 0x200000(2MB)주소에 복사했고 그 이전의 0x100000(1MB)~0x200000(2MB)까지의 메모리 영역을 비워뒀다. 이곳에 PML4, 페이지 디렉터리 포인터 테이블, 페이지 디렉터리를 순서대로 위치시킨다.

공통 속성 필드 설정

PML4 테이블 엔트리, 페이지 디렉터리 포인터 엔트리, 페이지 디렉터리 엔트리는 공통적인 속성을 가지고 각 속성은 다음과 같다.

  • A, P, Avail, EXB
    • MINT64 OS에선 기본 기능외에 다른 기능은 사용하지 않는다. 따라서 EXB(코드 실행 제한), A(메모리 접근), Avail(커널 임시 영역 사용)를 0으로 설정한다. 하지만 P 필드는 해당 엔트리의 유효성을 나타내므로 반드시 1로 설정한다.
  • PCD와 PWT
    • IA-32e 모드 커널은 보호 모드 커널과 달리 실제 OS를 구성하는 핵심 역할이며 속도 향상을 위해서 캐시를 사용한다. 캐시 정책은 Write-Through와 Write-Back 방식이 있지만 Write-Back이 더 효율적이다. 따라서 PCD와 PWT 비트를 설정해 Write-Back 방식을 사용하게 한다.
  • U/S와 R/W
    • MINT64 OS는 유저레벨과 커널레벨을 구분하여 잘못된 접근을 막아 보호해야 한다. 하지만 현재는 유저레벨이 존재하지 않기 때문에 코드 영역, 데이터 영역등을 따로 구분하지 않고 모든 영역을 커널 레벨 영역으로 지정하고 읽기와 쓰기가 가능하게 설정한다.

프로세서의 페이징 기능 활성화

페이징 기능을 활성화 하기 위해서는 CR0의 PG, CR3와 CR4 레지스터의 PAE를 설정할 필요가 있다.

PG비트는 CR0의 최상위 비트이며 PG를 설정하는 순간 페이징 기능이 활성화되기 때문에 설정하기 전 CR3 레지스터의 PML4 테이블의 주소를 설정해야한다. 여기서 추가적으로 CR2 레지스터는 페이지 접근 또는 오류가 발생했을때 예외처리를 하는 역할을 담당한다.

보호 모드에서의 3단계 페이징 기능을 사용하는것이 목적이라면 CR0, CR3레지스터로 충분하지만, 우리의 최종목적은 IA-32e 모드에서 동작하며 2MB의 크기를 가지는 페이징 활성화며 프로세스에 통지하는것이다. 이런 작업을 CR4 레지스터의 PAE(Physical Address Extensions) 비트와 페이지 디렉터리 엔트리의 PS 비트를 1로 설정하여 처리한다. 따라서 페이징 기능 활성화를 위해 레지스터를 CR4->CR3->CR0 순으로 설정하는게 좋다.

Share