ARM64에서의 커널 메모리 맵

· 1234 words · 3 minute read

ARM64에서의 커널 메모리 맵 🔗

<코드로 알아보는 ARM 리눅스 커널> 에서의 “페이징과 매핑"이라는 챕터를 읽으면서 커널 메모리 맵에 대한 간략한 설명을 포스팅으로 정리하고자 한다. 물리 메모리와 가상 메모리 주소간의 매핑을 위해 사용하는 테이블을 매핑 테이블이라고 하며, 본 포스팅에서는 기본적인 개념인 가상 주소 공간과 ARM64에서의 커널 메모리 맵 구성을 정리한다.

ARM64 커널에서는 64비트 가상 주소의 시작 부분과 끝부분의 영역을 사용한다. 이 때, 가상 주소 기준으로 각 끝 영역을 사용한다는 점에 유의해야 한다.

가상 주소 공간 🔗

ARM64 커널에서는 64비트 가상 주소의 시작 부분과 끝부분의 가상 주소 공간을 사용한다. 각각의 공간은 서로 다른 TTBR(Translation Table Base Register)를 사용하기 때문에 각자의 페이지 테이블을 갖고 있다. 이 때, 커널 주소 공간은 TTBR1, 사용자 주소 공간은 TTBR0를 사용하며 각각의 레지스터는 MMU 디바이스 내부에 저장된다.

Kernel-space and User-space in memory

페이지 테이블을 엔트리 여러 개로 구성되며, 페이지 테이블 엔트리 하나는 페이지 1개에 대한 물리주소로 변환하는데 사용한다. ARM64 커널에서는 페이지 크기로 4KB, 16KB, 64KB 중 하나를 사용할 수 있다(기본 4KB). 중요한 점은 ARM64 커널이 64비트 가상 주소 전체를 사용하는 것이 아니라 36, 39, 42, 47 및 최대 48비트와 같이 아키텍처가 지원하는 비트만을 선택해 사용할 수 있고 이 범위를 가상 주소로 사용한다. 이러한 비트는 VA_BITS 값으로 설정하며 페이지 크기페이지 테이블 엔트리 인덱스, 페이지 오프셋 크기 구성에 따라 페이지 테이블 엔트리의 수가 결정된다.

커널에서 레벨에 따라 페이지 테이블 명칭은 아래와 같이 구분한다.

  • 1단계: PGD (Page Global Directory)
  • 2단계: PUD (Page Upper Directory)
  • 3단계: PMD (Page Mid-level Directory)
  • 4단계: PTE (Page Table Entry)

예를 들어, VA_BITS 를 36으로 설정한다면, 아래와 같이 64비트 가상주소 중에서 테이블 엔트리 인덱스와 페이지 오프셋을 포함한 비트가 36비트를 차지한다. 그리고 2단계 페이지 테이블을 구성한다면, 16K 페이지를 사용한다고 가정했을 때 아래와 같이 가상주소의 구성을 생각할 수 있다.

Virtual Address

ARM64 커널의 기본 구성인 3단계 페이지 테이블 🔗

커널의 기본 구성인 4K 페이지와 VA_BITS = 39로 구성된 3단계 페이지 테이블을 사용하는 경우를 살펴보자. 64비트 중 39비트에 포함하지 않는 상위 25비트는 커널(모두 1)과 유저 주소 공간(모두 0) 구분에 사용하고, 나머지 39비트를 각각 9비트/9비트/9비트/12비트(페이지 오프셋용) 으로 나누어 사용한다. 상위 비트에 따라 TTBR을 어떤 것을 사용할지를 결정한다.

Virtual Address and Page Table Mapping

ARM64 커널 메모리 맵 🔗

커널용 가상 주소 영역도 독특하게 사용한다. 상위 절반은 물리 메모리를 1:1로 미리 매핑하여 사용하며 나머지 절반에 대해 fixmap, vmalloc, vmemmap, pci-iomap 등의 영역과 커널 이미지 영역으로 나누어 사용한다.

  • fixmap: 컴파일 테임에 목적에 따라 가상 주소 공간이 이미 결정된 매핑 영역이다.
  • vmalloc: 런타임에 연속된 가상 주소 공간을 자유롭게 매핑할 수 있는 영역이다. vmalloc() 함수가 vmap() 함수를 통해 이용하는 곳이고 ioremap() 역시 사용하는 영역이다.
  • vmemmap: 빠른 접근을 위해 분산된 페이지 구조체들을 이 영역에 매핑하기 위해 사용한다.
  • pci-iomap: PCI 디바이스의 메모리 맵 I/O 영역으로 사용한다. PCI 디바이스만 사용하며, 일반적으로 ioremap 함수를 통해 매핑하는 곳은 vmalloc 영역이다.