본문 바로 가기

[Linux] 페이지 테이블 구조

리눅스에서 페이지 테이블이 어떻게 구성되어 있는지 알아보자.

환경

리눅스 커널 5.15 버전, x86_64 기준

🌵 페이지 테이블 구조

테이블 매핑 방식은 4가지가 존재한다.

  1. 직접 매핑
  2. 연관 매핑
  3. 집합-연관 매핑
  4. 역매핑
  5. 해시형 테이블 구조

그중, 리눅스는 직접 매핑방식 중, 계층적 페이지 테이블을 사용한다.
계층적 페이지 테이블은 아래 그림을 보면 직관적으로 이해 할 수 있다.

64bit 를 나누어서, 각각을 offset 으로 사용하는 방식이다.
리눅스에서는 디폴트로 다음과 같이 4단계로 페이지 테이블을 구성한다.
PGD (Page Global Directory)
PUD (Page Upper Directory)
PMD (Page Middle Directory)
PTE (Page Table Entry)

pgtable_64_types.h

직접 코드를 보며 이해해보자.

https://github.com/torvalds/linux/blob/v5.15/arch/x86/include/asm/pgtable_64_types.h
의 코드를 일부 가져왔다.

#define PTRS_PER_PGD     512
#define PTRS_PER_PUD     512
#define PTRS_PER_PMD     512
#define PTRS_PER_PTE     512

위의 값을 봤을때, 각각의 테이블은 512개의 엔트리를 가지는 것을 알 수 있다.
2^9 = 512 이므로, 각각 9bit를 차지한다는 점을 알 수 있다.

리눅스는 기본적으로 4kb 페이지사이즈를 가지므로 (=12bit offset) 위와 같은 memory bit 구조를 가지게 된다.

memory.c

https://github.com/torvalds/linux/blob/v5.15/mm/memory.c
에서 follow_invalidate_pte 함수의 코드를 일부발췌 했다.

    pgd_t *pgd; //pgd offset
    pud_t *pud; //pud offset
    pmd_t *pmd; //pmd offset
    pte_t *ptep; //pte offset

    pgd = pgd_offset(mm, address); 
    pud = pud_offset(pgd, address); 
    pmd = pmd_offset(pud, address); 
    ptep = pte_offset_map_lock(mm, pmd, address, ptlp); 

코드를 통해 리눅스 커널이 실제로 페이지 테이블을 계층적으로 탐색한다는 점을 알게되었다.

Reference

https://velog.io/@lcy960729/%ED%8E%98%EC%9D%B4%EC%A7%80-%ED%85%8C%EC%9D%B4%EB%B8%94%EC%9D%98-%EA%B5%AC%EC%A1%B0-%EA%B3%84%EC%B8%B5%EC%A0%81-%ED%8E%98%EC%9D%B4%EC%A7%95
https://github.com/torvalds/linux/blob/v5.15/arch/x86/include/asm/pgtable_64_types.h
https://github.com/torvalds/linux/blob/v5.15/mm/memory.c