크래프톤 정글 일지

[PintOS] Page Table 페이지 테이블

나한나한나한나 2024. 6. 1. 14:32

페이지 테이블의 주요 역할:

  • 가상 주소를 물리 주소로 변환: 프로그램에서 사용하는 가상 주소는 페이지 테이블을 통해 실제 물리 메모리 주소로 변환됩니다.
  • 페이지 접근 제어: 페이지 테이블에는 각 페이지의 접근 권한(읽기, 쓰기, 실행 등)이 저장되어 있으며, 이를 통해 메모리 보호 기능을 수행합니다.
  • 페이지 교체 관리: 사용하지 않는 페이지는 디스크에 저장된 백업 스토리지(스왑 공간)로 이동하고, 필요한 페이지는 다시 메모리로 로드됩니다. 페이지 테이블은 이러한 페이지 교체 과정을 관리합니다.

페이지 테이블의 구조:

페이지 테이블은 일반적으로 다음과 같은 정보를 포함하는 엔트리들로 구성됩니다.

  • 페이지 번호: 가상 주소 공간에서 페이지를 식별하는 번호
  • 프레임 번호: 실제 물리 메모리에서 페이지가 할당된 프레임 번호
  • 유효 비트: 페이지가 유효한지 여부를 나타내는 비트
  • 접근 권한: 페이지에 대한 접근 권한(읽기, 쓰기, 실행 등)
  • 변경 비트: 페이지가 변경되었는지 여부를 나타내는 비트
  • 보호 키: 페이지에 대한 접근을 제어하는 보안 키

페이지 테이블의 작동 방식:

  1. 프로그램에서 메모리에 액세스하려고 하면 CPU는 가상 주소를 생성합니다.
  2. CPU는 페이지 테이블 레지스터(PTR)에 저장된 페이지 테이블 기본 주소를 사용하여 페이지 테이블 엔트리를 찾습니다.
  3. 페이지 테이블 엔트리에서 페이지 번호가 일치하는 엔트리를 찾습니다.
  4. 엔트리가 유효하면 프레임 번호가 페이지 테이블 엔트리에 저장됩니다.
  5. CPU는 프레임 번호와 오프셋을 사용하여 실제 물리 주소를 계산합니다.
  6. 계산된 물리 주소를 사용하여 메모리에 액세스합니다.

페이지 테이블

threads/mmu.c의 코드는 x86_64 하드웨어 페이지 테이블에 대한 추상 인터페이스입니다. Pintos에서 사용하는 페이지 테이블은 Page-Map-Level-4의 약자인 pml4라고 불리며, 이는 테이블이 4단계로 구성되어 있기 때문입니다. 페이지 테이블 인터페이스는 내부 구조에 접근하기 편리하도록 uint64_t *를 사용하여 페이지 테이블을 표현합니다. 아래 섹션에서는 페이지 테이블 인터페이스와 내부 구조에 대해 설명합니다.

생성, 소멸, 및 활성화

이 함수들은 페이지 테이블을 생성, 소멸 및 활성화합니다. 기본 Pintos 코드에서는 이미 필요한 곳에서 이 함수들을 호출하므로, 직접 호출할 필요는 없습니다.

  • uint64_t *pml4_create(void);
    • 새로운 페이지 테이블을 생성하고 반환합니다. 새로운 페이지 테이블은 Pintos의 일반 커널 가상 페이지 매핑을 포함하지만 사용자 가상 매핑은 포함하지 않습니다. 메모리를 얻을 수 없는 경우 null 포인터를 반환합니다.
  • void pml4_destroy(uint64_t *pml4);
    • pml4가 소유한 모든 자원, 페이지 테이블 자체 및 매핑된 프레임을 해제합니다. 모든 레벨의 페이지 테이블 자원을 해제하기 위해 pdpe_destroy, pgdir_destroy 및 pt_destroy를 재귀적으로 호출합니다.
  • void pml4_activate(uint64_t *pml4);
    • pml4를 활성화합니다. 활성화된 페이지 테이블은 CPU가 메모리 참조를 변환하는 데 사용하는 페이지 테이블입니다.

검사 및 업데이트

이 함수들은 페이지 테이블이 캡슐화한 페이지에서 프레임으로의 매핑을 검사하거나 업데이트합니다. 실행 중인 프로세스와 중지된 프로세스 모두에서 사용되며, 필요에 따라 TLB를 플러시합니다.

  • bool pml4_set_page(uint64_t *pml4, void *upage, void *kpage, bool rw);
    • 사용자 페이지 upage를 커널 가상 주소 kpage가 식별하는 프레임에 매핑합니다. rw가 true인 경우 페이지는 읽기/쓰기로 매핑되며, 그렇지 않은 경우 읽기 전용으로 매핑됩니다. 사용자 페이지 upage는 pml4에 이미 매핑되어 있지 않아야 합니다. 커널 페이지 kpage는 palloc_get_page(PAL_USER)를 사용하여 사용자 풀에서 얻은 커널 가상 주소여야 합니다. 성공 시 true를 반환하고, 실패 시 false를 반환합니다. 페이지 테이블에 필요한 추가 메모리를 얻을 수 없는 경우 실패합니다.
  • void *pml4_get_page(uint64_t *pml4, const void *uaddr);
    • pml4에서 uaddr에 매핑된 프레임을 조회합니다. uaddr이 매핑된 경우 해당 프레임의 커널 가상 주소를 반환하고, 그렇지 않은 경우 null 포인터를 반환합니다.
  • void pml4_clear_page(uint64_t *pml4, void *upage);
    • pml4에서 페이지를 "존재하지 않음"으로 표시합니다. 이후 페이지에 대한 접근은 오류를 발생시킵니다. 페이지 테이블의 다른 비트는 유지되어 접근 및 더티 비트를 확인할 수 있습니다. 페이지가 매핑되지 않은 경우 이 함수는 아무런 효과가 없습니다.

접근 및 더티 비트

x86_64 하드웨어는 각 페이지에 대한 페이지 테이블 엔트리(PTE)의 두 개의 비트를 통해 페이지 교체 알고리즘 구현을 일부 지원합니다. 페이지에 대한 읽기 또는 쓰기 시 CPU는 해당 페이지의 PTE에서 접근 비트를 1로 설정하고, 쓰기 시에는 더티 비트를 1로 설정합니다. CPU는 이 비트들을 0으로 리셋하지 않지만, 운영체제(OS)는 이를 리셋할 수 있습니다. 이러한 비트들을 올바르게 해석하려면 두 개 이상의 페이지가 동일한 프레임을 참조하는 경우인 별칭(alias)에 대한 이해가 필요합니다. 별칭된 프레임이 접근될 때, 접근 및 더티 비트는 오직 하나의 페이지 테이블 엔트리(접근에 사용된 페이지의 엔트리)에서만 업데이트됩니다. 다른 별칭들의 접근 및 더티 비트는 업데이트되지 않습니다.

  • bool pml4_is_dirty(uint64_t *pml4, const void *vpage);
    • pml4에 더티(혹은 접근)로 표시된 vpage에 대한 페이지 테이블 엔트리가 있으면 true를 반환합니다. 그렇지 않으면 false를 반환합니다.
  • void pml4_set_dirty(uint64_t *pml4, const void *vpage, bool dirty);
  • void pml4_set_accessed(uint64_t *pml4, const void *vpage, bool accessed);
    • pml4에 페이지에 대한 페이지 테이블 엔트리가 있으면 해당 더티(또는 접근) 비트를 주어진 값으로 설정합니다.
댓글수0